2002-06-16 12:57:31 +02:00
/*
* device . c : The basic device interface
*
* See the main source file ' vdr . c ' for copyright information and
* how to reach the author .
*
2007-06-16 10:41:21 +02:00
* $ Id : device . c 1.141 2007 / 06 / 16 09 : 31 : 32 kls Exp $
2002-06-16 12:57:31 +02:00
*/
# include "device.h"
# include <errno.h>
# include <sys/ioctl.h>
# include <sys/mman.h>
2002-11-03 11:53:58 +01:00
# include "audio.h"
2002-10-06 10:25:42 +02:00
# include "channels.h"
2002-09-04 17:26:02 +02:00
# include "i18n.h"
2002-06-16 12:57:31 +02:00
# include "player.h"
# include "receiver.h"
# include "status.h"
2002-06-22 13:45:53 +02:00
# include "transfer.h"
2002-06-16 12:57:31 +02:00
2004-12-17 14:55:49 +01:00
// --- cPesAssembler ---------------------------------------------------------
class cPesAssembler {
private :
uchar * data ;
uint32_t tag ;
int length ;
int size ;
bool Realloc ( int Size ) ;
public :
cPesAssembler ( void ) ;
~ cPesAssembler ( ) ;
2005-02-06 14:22:08 +01:00
int ExpectedLength ( void ) { return PacketSize ( data ) ; }
static int PacketSize ( const uchar * data ) ;
2004-12-17 14:55:49 +01:00
int Length ( void ) { return length ; }
2005-05-05 14:59:46 +02:00
const uchar * Data ( void ) { return data ; } // only valid if Length() >= 4
2004-12-17 14:55:49 +01:00
void Reset ( void ) ;
void Put ( uchar c ) ;
void Put ( const uchar * Data , int Length ) ;
bool IsPes ( void ) ;
} ;
cPesAssembler : : cPesAssembler ( void )
{
data = NULL ;
size = 0 ;
Reset ( ) ;
}
cPesAssembler : : ~ cPesAssembler ( )
{
free ( data ) ;
}
void cPesAssembler : : Reset ( void )
{
tag = 0xFFFFFFFF ;
length = 0 ;
}
bool cPesAssembler : : Realloc ( int Size )
{
if ( Size > size ) {
size = max ( Size , 2048 ) ;
data = ( uchar * ) realloc ( data , size ) ;
if ( ! data ) {
esyslog ( " ERROR: can't allocate memory for PES assembler " ) ;
length = 0 ;
size = 0 ;
return false ;
}
}
return true ;
}
void cPesAssembler : : Put ( uchar c )
{
2005-05-05 14:59:46 +02:00
if ( length < 4 ) {
2004-12-17 14:55:49 +01:00
tag = ( tag < < 8 ) | c ;
if ( ( tag & 0xFFFFFF00 ) = = 0x00000100 ) {
if ( Realloc ( 4 ) ) {
* ( uint32_t * ) data = htonl ( tag ) ;
length = 4 ;
}
}
2005-05-05 14:59:46 +02:00
else if ( length < 3 )
length + + ;
2004-12-17 14:55:49 +01:00
}
else if ( Realloc ( length + 1 ) )
data [ length + + ] = c ;
}
void cPesAssembler : : Put ( const uchar * Data , int Length )
{
2005-05-05 14:59:46 +02:00
while ( length < 4 & & Length > 0 ) {
2004-12-17 14:55:49 +01:00
Put ( * Data + + ) ;
Length - - ;
}
if ( Length & & Realloc ( length + Length ) ) {
memcpy ( data + length , Data , Length ) ;
length + = Length ;
}
}
2005-02-06 14:22:08 +01:00
int cPesAssembler : : PacketSize ( const uchar * data )
{
// we need atleast 6 bytes of data here !!!
switch ( data [ 3 ] ) {
default :
case 0x00 . . . 0xB8 : // video stream start codes
case 0xB9 : // Program end
case 0xBC : // Programm stream map
case 0xF0 . . . 0xFF : // reserved
return 6 ;
case 0xBA : // Pack header
if ( ( data [ 4 ] & 0xC0 ) = = 0x40 ) // MPEG2
return 14 ;
// to be absolutely correct we would have to add the stuffing bytes
// as well, but at this point we only may have 6 bytes of data avail-
// able. So it's up to the higher level to resync...
//return 14 + (data[13] & 0x07); // add stuffing bytes
else // MPEG1
return 12 ;
case 0xBB : // System header
case 0xBD : // Private stream1
case 0xBE : // Padding stream
case 0xBF : // Private stream2 (navigation data)
case 0xC0 . . . 0xCF : // all the rest (the real packets)
case 0xD0 . . . 0xDF :
case 0xE0 . . . 0xEF :
return 6 + data [ 4 ] * 256 + data [ 5 ] ;
}
}
2002-09-08 09:03:10 +02:00
// --- cDevice ---------------------------------------------------------------
2002-08-04 14:57:29 +02:00
// The default priority for non-primary devices:
2003-05-25 11:02:58 +02:00
# define DEFAULTPRIORITY -1
2002-06-16 12:57:31 +02:00
int cDevice : : numDevices = 0 ;
int cDevice : : useDevice = 0 ;
2002-08-04 14:57:29 +02:00
int cDevice : : nextCardIndex = 0 ;
2003-06-08 09:25:07 +02:00
int cDevice : : currentChannel = 1 ;
2002-06-16 12:57:31 +02:00
cDevice * cDevice : : device [ MAXDEVICES ] = { NULL } ;
cDevice * cDevice : : primaryDevice = NULL ;
2002-08-04 14:57:29 +02:00
cDevice : : cDevice ( void )
2002-06-16 12:57:31 +02:00
{
2002-08-04 14:57:29 +02:00
cardIndex = nextCardIndex + + ;
2002-06-16 12:57:31 +02:00
2003-10-18 12:29:08 +02:00
SetDescription ( " receiver on device %d " , CardIndex ( ) + 1 ) ;
2002-08-04 14:57:29 +02:00
SetVideoFormat ( Setup . VideoFormat ) ;
2002-06-16 12:57:31 +02:00
mute = false ;
volume = Setup . CurrentVolume ;
2003-12-22 13:29:24 +01:00
sectionHandler = NULL ;
eitFilter = NULL ;
patFilter = NULL ;
2004-01-04 12:30:00 +01:00
sdtFilter = NULL ;
2004-01-11 15:54:37 +01:00
nitFilter = NULL ;
2003-12-22 13:29:24 +01:00
2007-01-07 14:46:14 +01:00
camSlot = NULL ;
startScrambleDetection = 0 ;
2002-06-16 12:57:31 +02:00
player = NULL ;
2004-12-17 14:55:49 +01:00
pesAssembler = new cPesAssembler ;
ClrAvailableTracks ( ) ;
2005-02-27 10:36:19 +01:00
currentAudioTrack = ttNone ;
2005-02-06 11:33:13 +01:00
currentAudioTrackMissingCount = 0 ;
2002-06-16 12:57:31 +02:00
for ( int i = 0 ; i < MAXRECEIVERS ; i + + )
receiver [ i ] = NULL ;
2002-08-04 14:57:29 +02:00
2004-02-08 15:11:07 +01:00
if ( numDevices < MAXDEVICES )
2002-08-04 14:57:29 +02:00
device [ numDevices + + ] = this ;
else
esyslog ( " ERROR: too many devices! " ) ;
2002-06-16 12:57:31 +02:00
}
cDevice : : ~ cDevice ( )
{
Detach ( player ) ;
2007-01-07 14:46:14 +01:00
DetachAllReceivers ( ) ;
2004-01-11 15:54:37 +01:00
delete nitFilter ;
2004-01-04 12:30:00 +01:00
delete sdtFilter ;
2003-12-22 13:29:24 +01:00
delete patFilter ;
2004-01-04 12:30:00 +01:00
delete eitFilter ;
2003-12-22 13:29:24 +01:00
delete sectionHandler ;
2004-12-17 14:55:49 +01:00
delete pesAssembler ;
2002-06-16 12:57:31 +02:00
}
2005-08-21 08:56:49 +02:00
bool cDevice : : WaitForAllDevicesReady ( int Timeout )
{
for ( time_t t0 = time ( NULL ) ; time ( NULL ) - t0 < Timeout ; ) {
bool ready = true ;
for ( int i = 0 ; i < numDevices ; i + + ) {
2007-01-07 14:46:14 +01:00
if ( device [ i ] & & ! device [ i ] - > Ready ( ) ) {
2005-08-21 08:56:49 +02:00
ready = false ;
2007-01-07 14:46:14 +01:00
cCondWait : : SleepMs ( 100 ) ;
}
2005-08-21 08:56:49 +02:00
}
if ( ready )
return true ;
}
return false ;
}
2002-06-16 12:57:31 +02:00
void cDevice : : SetUseDevice ( int n )
{
if ( n < MAXDEVICES )
useDevice | = ( 1 < < n ) ;
}
2002-08-04 14:57:29 +02:00
int cDevice : : NextCardIndex ( int n )
{
if ( n > 0 ) {
nextCardIndex + = n ;
if ( nextCardIndex > = MAXDEVICES )
esyslog ( " ERROR: nextCardIndex too big (%d) " , nextCardIndex ) ;
}
else if ( n < 0 )
2005-12-30 15:43:21 +01:00
esyslog ( " ERROR: invalid value in IncCardIndex(%d) " , n ) ;
2002-08-04 14:57:29 +02:00
return nextCardIndex ;
}
2002-10-07 16:21:46 +02:00
int cDevice : : DeviceNumber ( void ) const
{
for ( int i = 0 ; i < numDevices ; i + + ) {
if ( device [ i ] = = this )
return i ;
}
return - 1 ;
}
2002-08-04 14:57:29 +02:00
void cDevice : : MakePrimaryDevice ( bool On )
{
}
2002-06-16 12:57:31 +02:00
bool cDevice : : SetPrimaryDevice ( int n )
{
n - - ;
if ( 0 < = n & & n < numDevices & & device [ n ] ) {
2003-04-12 12:20:07 +02:00
isyslog ( " setting primary device to %d " , n + 1 ) ;
if ( primaryDevice )
primaryDevice - > MakePrimaryDevice ( false ) ;
primaryDevice = device [ n ] ;
primaryDevice - > MakePrimaryDevice ( true ) ;
2005-02-20 12:01:05 +01:00
primaryDevice - > SetVideoFormat ( Setup . VideoFormat ) ;
2003-04-12 12:20:07 +02:00
return true ;
2002-06-16 12:57:31 +02:00
}
2003-04-12 12:20:07 +02:00
esyslog ( " ERROR: invalid primary device number: %d " , n + 1 ) ;
2002-08-04 14:57:29 +02:00
return false ;
}
bool cDevice : : HasDecoder ( void ) const
{
2002-06-16 12:57:31 +02:00
return false ;
}
2002-09-08 14:17:51 +02:00
cSpuDecoder * cDevice : : GetSpuDecoder ( void )
{
return NULL ;
}
2003-05-11 09:01:51 +02:00
cDevice * cDevice : : ActualDevice ( void )
{
cDevice * d = cTransferControl : : ReceiverDevice ( ) ;
if ( ! d )
d = PrimaryDevice ( ) ;
return d ;
}
2002-09-04 17:26:02 +02:00
cDevice * cDevice : : GetDevice ( int Index )
{
return ( 0 < = Index & & Index < numDevices ) ? device [ Index ] : NULL ;
}
2007-01-07 14:46:14 +01:00
cDevice * cDevice : : GetDevice ( const cChannel * Channel , int Priority , bool LiveView )
{
// Collect the current priorities of all CAM slots that can decrypt the channel:
int NumCamSlots = CamSlots . Count ( ) ;
int SlotPriority [ NumCamSlots ] ;
int NumUsableSlots = 0 ;
if ( Channel - > Ca ( ) > = CA_ENCRYPTED_MIN ) {
for ( cCamSlot * CamSlot = CamSlots . First ( ) ; CamSlot ; CamSlot = CamSlots . Next ( CamSlot ) ) {
SlotPriority [ CamSlot - > Index ( ) ] = MAXPRIORITY + 1 ; // assumes it can't be used
if ( CamSlot - > ModuleStatus ( ) = = msReady ) {
if ( CamSlot - > ProvidesCa ( Channel - > Caids ( ) ) ) {
if ( ! ChannelCamRelations . CamChecked ( Channel - > GetChannelID ( ) , CamSlot - > SlotNumber ( ) ) ) {
SlotPriority [ CamSlot - > Index ( ) ] = CamSlot - > Priority ( ) ;
NumUsableSlots + + ;
}
}
2003-08-02 11:52:29 +02:00
}
2002-06-16 12:57:31 +02:00
}
2007-01-07 14:46:14 +01:00
if ( ! NumUsableSlots )
return NULL ; // no CAM is able to decrypt this channel
}
bool NeedsDetachReceivers = false ;
cDevice * d = NULL ;
cCamSlot * s = NULL ;
uint32_t Impact = 0xFFFFFFFF ; // we're looking for a device with the least impact
for ( int j = 0 ; j < NumCamSlots | | ! NumUsableSlots ; j + + ) {
if ( NumUsableSlots & & SlotPriority [ j ] > MAXPRIORITY )
continue ; // there is no CAM available in this slot
for ( int i = 0 ; i < numDevices ; i + + ) {
if ( Channel - > Ca ( ) & & Channel - > Ca ( ) < = CA_DVB_MAX & & Channel - > Ca ( ) ! = device [ i ] - > CardIndex ( ) + 1 )
continue ; // a specific card was requested, but not this one
if ( NumUsableSlots & & ! CamSlots . Get ( j ) - > Assign ( device [ i ] , true ) )
continue ; // CAM slot can't be used with this device
bool ndr ;
if ( device [ i ] - > ProvidesChannel ( Channel , Priority , & ndr ) ) { // this device is basicly able to do the job
if ( NumUsableSlots & & device [ i ] - > CamSlot ( ) & & device [ i ] - > CamSlot ( ) ! = CamSlots . Get ( j ) )
ndr = true ; // using a different CAM slot requires detaching receivers
// Put together an integer number that reflects the "impact" using
// this device would have on the overall system. Each condition is represented
// by one bit in the number (or several bits, if the condition is actually
// a numeric value). The sequence in which the conditions are listed corresponds
// to their individual severity, where the one listed first will make the most
// difference, because it results in the most significant bit of the result.
uint32_t imp = 0 ;
imp < < = 1 ; imp | = LiveView ? ! device [ i ] - > IsPrimaryDevice ( ) | | ndr : 0 ; // prefer the primary device for live viewing if we don't need to detach existing receivers
2007-04-30 09:40:34 +02:00
imp < < = 1 ; imp | = ! device [ i ] - > Receiving ( ) & & ( device [ i ] ! = cTransferControl : : ReceiverDevice ( ) | | device [ i ] - > IsPrimaryDevice ( ) ) | | ndr ; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode
2007-01-07 14:46:14 +01:00
imp < < = 1 ; imp | = device [ i ] - > Receiving ( ) ; // avoid devices that are receiving
imp < < = 1 ; imp | = device [ i ] = = cTransferControl : : ReceiverDevice ( ) ; // avoid the Transfer Mode receiver device
imp < < = 8 ; imp | = min ( max ( device [ i ] - > Priority ( ) + MAXPRIORITY , 0 ) , 0xFF ) ; // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
imp < < = 8 ; imp | = min ( max ( ( NumUsableSlots ? SlotPriority [ j ] : 0 ) + MAXPRIORITY , 0 ) , 0xFF ) ; // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
imp < < = 1 ; imp | = ndr ; // avoid devices if we need to detach existing receivers
imp < < = 1 ; imp | = device [ i ] - > IsPrimaryDevice ( ) ; // avoid the primary device
2007-01-13 12:14:51 +01:00
imp < < = 1 ; imp | = NumUsableSlots ? 0 : device [ i ] - > HasCi ( ) ; // avoid cards with Common Interface for FTA channels
2007-01-07 14:46:14 +01:00
imp < < = 1 ; imp | = device [ i ] - > HasDecoder ( ) ; // avoid full featured cards
imp < < = 1 ; imp | = NumUsableSlots ? ! ChannelCamRelations . CamDecrypt ( Channel - > GetChannelID ( ) , j + 1 ) : 0 ; // prefer CAMs that are known to decrypt this channel
if ( imp < Impact ) {
// This device has less impact than any previous one, so we take it.
Impact = imp ;
d = device [ i ] ;
NeedsDetachReceivers = ndr ;
if ( NumUsableSlots )
s = CamSlots . Get ( j ) ;
}
}
}
if ( ! NumUsableSlots )
break ; // no CAM necessary, so just one loop over the devices
2002-06-16 12:57:31 +02:00
}
2007-01-07 14:46:14 +01:00
if ( d ) {
if ( NeedsDetachReceivers )
d - > DetachAllReceivers ( ) ;
if ( s ) {
if ( s - > Device ( ) ! = d ) {
if ( s - > Device ( ) )
s - > Device ( ) - > DetachAllReceivers ( ) ;
if ( d - > CamSlot ( ) )
d - > CamSlot ( ) - > Assign ( NULL ) ;
s - > Assign ( d ) ;
}
}
else if ( d - > CamSlot ( ) & & ! d - > CamSlot ( ) - > IsDecrypting ( ) )
d - > CamSlot ( ) - > Assign ( NULL ) ;
}
2002-06-16 12:57:31 +02:00
return d ;
}
2007-01-13 12:14:51 +01:00
bool cDevice : : HasCi ( void )
{
return false ;
}
2007-01-07 14:46:14 +01:00
void cDevice : : SetCamSlot ( cCamSlot * CamSlot )
{
camSlot = CamSlot ;
}
2002-06-16 12:57:31 +02:00
void cDevice : : Shutdown ( void )
{
2005-01-25 18:22:46 +01:00
primaryDevice = NULL ;
2002-06-16 12:57:31 +02:00
for ( int i = 0 ; i < numDevices ; i + + ) {
delete device [ i ] ;
device [ i ] = NULL ;
}
}
2005-12-29 14:51:59 +01:00
uchar * cDevice : : GrabImage ( int & Size , bool Jpeg , int Quality , int SizeX , int SizeY )
2002-06-16 12:57:31 +02:00
{
2005-12-29 14:51:59 +01:00
return NULL ;
}
bool cDevice : : GrabImageFile ( const char * FileName , bool Jpeg , int Quality , int SizeX , int SizeY )
{
int result = 0 ;
2005-12-30 15:11:16 +01:00
int fd = open ( FileName , O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC , DEFFILEMODE ) ;
if ( fd > = 0 ) {
2005-12-29 14:51:59 +01:00
int ImageSize ;
uchar * Image = GrabImage ( ImageSize , Jpeg , Quality , SizeX , SizeY ) ;
if ( Image ) {
2005-12-30 15:11:16 +01:00
if ( safe_write ( fd , Image , ImageSize ) = = ImageSize )
2005-12-29 14:51:59 +01:00
isyslog ( " grabbed image to %s " , FileName ) ;
else {
LOG_ERROR_STR ( FileName ) ;
result | = 1 ;
}
free ( Image ) ;
}
else
result | = 1 ;
2005-12-30 15:11:16 +01:00
close ( fd ) ;
2005-12-29 14:51:59 +01:00
}
else {
LOG_ERROR_STR ( FileName ) ;
result | = 1 ;
}
return result = = 0 ;
2002-06-16 12:57:31 +02:00
}
2005-02-20 12:01:05 +01:00
void cDevice : : SetVideoDisplayFormat ( eVideoDisplayFormat VideoDisplayFormat )
{
cSpuDecoder * spuDecoder = GetSpuDecoder ( ) ;
if ( spuDecoder ) {
if ( Setup . VideoFormat )
spuDecoder - > setScaleMode ( cSpuDecoder : : eSpuNormal ) ;
else {
switch ( VideoDisplayFormat ) {
case vdfPanAndScan :
spuDecoder - > setScaleMode ( cSpuDecoder : : eSpuPanAndScan ) ;
break ;
case vdfLetterBox :
spuDecoder - > setScaleMode ( cSpuDecoder : : eSpuLetterBox ) ;
break ;
case vdfCenterCutOut :
spuDecoder - > setScaleMode ( cSpuDecoder : : eSpuNormal ) ;
break ;
}
}
}
}
2002-08-04 14:57:29 +02:00
void cDevice : : SetVideoFormat ( bool VideoFormat16_9 )
2002-06-16 12:57:31 +02:00
{
}
2003-08-15 13:05:50 +02:00
eVideoSystem cDevice : : GetVideoSystem ( void )
{
return vsPAL ;
}
2002-09-04 17:26:02 +02:00
//#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", CardIndex(), s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog(b); }
2002-06-16 12:57:31 +02:00
# define PRINTPIDS(s)
2002-09-29 13:40:45 +02:00
bool cDevice : : HasPid ( int Pid ) const
2002-09-04 17:26:02 +02:00
{
for ( int i = 0 ; i < MAXPIDHANDLES ; i + + ) {
if ( pidHandles [ i ] . pid = = Pid )
return true ;
}
return false ;
}
2002-06-16 12:57:31 +02:00
bool cDevice : : AddPid ( int Pid , ePidType PidType )
{
2003-05-02 09:24:31 +02:00
if ( Pid | | PidType = = ptPcr ) {
2002-06-16 12:57:31 +02:00
int n = - 1 ;
int a = - 1 ;
2003-05-02 09:24:31 +02:00
if ( PidType ! = ptPcr ) { // PPID always has to be explicit
for ( int i = 0 ; i < MAXPIDHANDLES ; i + + ) {
if ( i ! = ptPcr ) {
if ( pidHandles [ i ] . pid = = Pid )
n = i ;
else if ( a < 0 & & i > = ptOther & & ! pidHandles [ i ] . used )
a = i ;
}
}
}
2002-06-16 12:57:31 +02:00
if ( n > = 0 ) {
// The Pid is already in use
if ( + + pidHandles [ n ] . used = = 2 & & n < = ptTeletext ) {
2002-08-04 14:57:29 +02:00
// It's a special PID that may have to be switched into "tap" mode
2002-09-04 17:26:02 +02:00
PRINTPIDS ( " A " ) ;
2004-10-17 09:42:36 +02:00
if ( ! SetPid ( & pidHandles [ n ] , n , true ) ) {
esyslog ( " ERROR: can't set PID %d on device %d " , Pid , CardIndex ( ) + 1 ) ;
2005-06-05 13:37:37 +02:00
if ( PidType < = ptTeletext )
DetachAll ( Pid ) ;
2004-10-17 09:42:36 +02:00
DelPid ( Pid , PidType ) ;
return false ;
}
2007-01-07 14:46:14 +01:00
if ( camSlot )
camSlot - > SetPid ( Pid , true ) ;
2002-06-16 12:57:31 +02:00
}
2002-09-04 17:26:02 +02:00
PRINTPIDS ( " a " ) ;
2002-06-16 12:57:31 +02:00
return true ;
}
else if ( PidType < ptOther ) {
// The Pid is not yet in use and it is a special one
n = PidType ;
}
else if ( a > = 0 ) {
// The Pid is not yet in use and we have a free slot
n = a ;
}
2004-10-17 09:42:36 +02:00
else {
esyslog ( " ERROR: no free slot for PID %d on device %d " , Pid , CardIndex ( ) + 1 ) ;
return false ;
}
2002-06-16 12:57:31 +02:00
if ( n > = 0 ) {
pidHandles [ n ] . pid = Pid ;
pidHandles [ n ] . used = 1 ;
2002-09-04 17:26:02 +02:00
PRINTPIDS ( " C " ) ;
2004-10-17 09:42:36 +02:00
if ( ! SetPid ( & pidHandles [ n ] , n , true ) ) {
esyslog ( " ERROR: can't set PID %d on device %d " , Pid , CardIndex ( ) + 1 ) ;
2005-06-05 13:37:37 +02:00
if ( PidType < = ptTeletext )
DetachAll ( Pid ) ;
2004-10-17 09:42:36 +02:00
DelPid ( Pid , PidType ) ;
return false ;
}
2007-01-07 14:46:14 +01:00
if ( camSlot )
camSlot - > SetPid ( Pid , true ) ;
2002-06-16 12:57:31 +02:00
}
}
return true ;
}
2003-05-02 09:24:31 +02:00
void cDevice : : DelPid ( int Pid , ePidType PidType )
2002-06-16 12:57:31 +02:00
{
2003-05-02 09:24:31 +02:00
if ( Pid | | PidType = = ptPcr ) {
int n = - 1 ;
if ( PidType = = ptPcr )
n = PidType ; // PPID always has to be explicit
else {
for ( int i = 0 ; i < MAXPIDHANDLES ; i + + ) {
if ( pidHandles [ i ] . pid = = Pid ) {
n = i ;
break ;
2002-08-04 14:57:29 +02:00
}
2002-06-16 12:57:31 +02:00
}
2003-05-02 09:24:31 +02:00
}
if ( n > = 0 & & pidHandles [ n ] . used ) {
PRINTPIDS ( " D " ) ;
if ( - - pidHandles [ n ] . used < 2 ) {
SetPid ( & pidHandles [ n ] , n , false ) ;
if ( pidHandles [ n ] . used = = 0 ) {
pidHandles [ n ] . handle = - 1 ;
pidHandles [ n ] . pid = 0 ;
2007-01-07 14:46:14 +01:00
if ( camSlot )
camSlot - > SetPid ( Pid , false ) ;
2003-05-02 09:24:31 +02:00
}
}
PRINTPIDS ( " E " ) ;
}
2002-06-16 12:57:31 +02:00
}
}
2002-08-04 14:57:29 +02:00
bool cDevice : : SetPid ( cPidHandle * Handle , int Type , bool On )
2002-06-16 12:57:31 +02:00
{
2002-08-04 14:57:29 +02:00
return false ;
2002-06-16 12:57:31 +02:00
}
2003-12-22 13:29:24 +01:00
void cDevice : : StartSectionHandler ( void )
{
if ( ! sectionHandler ) {
sectionHandler = new cSectionHandler ( this ) ;
AttachFilter ( eitFilter = new cEitFilter ) ;
AttachFilter ( patFilter = new cPatFilter ) ;
2004-01-04 12:30:00 +01:00
AttachFilter ( sdtFilter = new cSdtFilter ( patFilter ) ) ;
2004-01-11 15:54:37 +01:00
AttachFilter ( nitFilter = new cNitFilter ) ;
2003-12-22 13:29:24 +01:00
}
}
int cDevice : : OpenFilter ( u_short Pid , u_char Tid , u_char Mask )
{
return - 1 ;
}
void cDevice : : AttachFilter ( cFilter * Filter )
{
2004-05-16 12:15:55 +02:00
if ( sectionHandler )
sectionHandler - > Attach ( Filter ) ;
2003-12-22 13:29:24 +01:00
}
void cDevice : : Detach ( cFilter * Filter )
{
2004-05-16 12:15:55 +02:00
if ( sectionHandler )
sectionHandler - > Detach ( Filter ) ;
2003-12-22 13:29:24 +01:00
}
2002-10-06 10:25:42 +02:00
bool cDevice : : ProvidesSource ( int Source ) const
{
return false ;
}
2004-01-04 12:30:00 +01:00
bool cDevice : : ProvidesTransponder ( const cChannel * Channel ) const
{
return false ;
}
2005-06-12 14:09:45 +02:00
bool cDevice : : ProvidesTransponderExclusively ( const cChannel * Channel ) const
{
for ( int i = 0 ; i < numDevices ; i + + ) {
if ( device [ i ] & & device [ i ] ! = this & & device [ i ] - > ProvidesTransponder ( Channel ) )
return false ;
}
return true ;
}
2002-09-29 13:40:45 +02:00
bool cDevice : : ProvidesChannel ( const cChannel * Channel , int Priority , bool * NeedsDetachReceivers ) const
2002-09-04 17:26:02 +02:00
{
return false ;
}
2006-04-09 09:12:47 +02:00
bool cDevice : : IsTunedToTransponder ( const cChannel * Channel )
{
return false ;
}
2005-11-05 15:48:05 +01:00
bool cDevice : : MaySwitchTransponder ( void )
{
return ! Receiving ( true ) & & ! ( pidHandles [ ptAudio ] . pid | | pidHandles [ ptVideo ] . pid | | pidHandles [ ptDolby ] . pid ) ;
}
2002-09-04 17:26:02 +02:00
bool cDevice : : SwitchChannel ( const cChannel * Channel , bool LiveView )
{
2007-01-07 14:46:14 +01:00
if ( LiveView ) {
2002-10-06 10:25:42 +02:00
isyslog ( " switching to channel %d " , Channel - > Number ( ) ) ;
2007-01-07 14:46:14 +01:00
cControl : : Shutdown ( ) ; // prevents old channel from being shown too long if GetDevice() takes longer
}
2002-09-04 17:26:02 +02:00
for ( int i = 3 ; i - - ; ) {
switch ( SetChannel ( Channel , LiveView ) ) {
case scrOk : return true ;
2004-10-16 13:51:05 +02:00
case scrNotAvailable : Skins . Message ( mtInfo , tr ( " Channel not available! " ) ) ;
2002-10-06 11:34:02 +02:00
return false ;
2004-05-16 10:35:36 +02:00
case scrNoTransfer : Skins . Message ( mtError , tr ( " Can't start Transfer Mode! " ) ) ;
2002-09-04 17:26:02 +02:00
return false ;
case scrFailed : break ; // loop will retry
}
esyslog ( " retrying " ) ;
}
return false ;
}
2002-09-08 11:46:53 +02:00
bool cDevice : : SwitchChannel ( int Direction )
{
bool result = false ;
Direction = sgn ( Direction ) ;
if ( Direction ) {
2007-01-07 14:46:14 +01:00
cControl : : Shutdown ( ) ; // prevents old channel from being shown too long if GetDevice() takes longer
2002-09-08 11:46:53 +02:00
int n = CurrentChannel ( ) + Direction ;
int first = n ;
2002-10-06 11:34:02 +02:00
cChannel * channel ;
2002-10-19 15:33:37 +02:00
while ( ( channel = Channels . GetByNumber ( n , Direction ) ) ! = NULL ) {
2002-10-06 11:34:02 +02:00
// try only channels which are currently available
2007-01-07 14:46:14 +01:00
if ( GetDevice ( channel , 0 , true ) )
2002-10-06 11:34:02 +02:00
break ;
2002-10-20 16:07:56 +02:00
n = channel - > Number ( ) + Direction ;
2002-10-06 11:34:02 +02:00
}
if ( channel ) {
int d = n - first ;
if ( abs ( d ) = = 1 )
dsyslog ( " s kipped channel %d " , first ) ;
else if ( d )
dsyslog ( " skipped channels %d..%d " , first , n - sgn ( d ) ) ;
if ( PrimaryDevice ( ) - > SwitchChannel ( channel , true ) )
result = true ;
}
2004-05-16 10:35:36 +02:00
else if ( n ! = first )
Skins . Message ( mtError , tr ( " Channel not available! " ) ) ;
2002-09-08 11:46:53 +02:00
}
return result ;
}
2002-09-04 17:26:02 +02:00
eSetChannelResult cDevice : : SetChannel ( const cChannel * Channel , bool LiveView )
2002-06-16 12:57:31 +02:00
{
2002-09-04 17:26:02 +02:00
if ( LiveView )
StopReplay ( ) ;
2002-08-04 14:57:29 +02:00
2007-01-07 14:46:14 +01:00
cDevice * Device = ( LiveView & & IsPrimaryDevice ( ) ) ? GetDevice ( Channel , 0 , LiveView ) : this ;
2006-01-06 13:55:57 +01:00
2007-01-07 14:46:14 +01:00
bool NeedsTransferMode = Device ! = this ;
2002-06-16 12:57:31 +02:00
eSetChannelResult Result = scrOk ;
// If this DVB card can't receive this channel, let's see if we can
// use the card that actually can receive it and transfer data from there:
if ( NeedsTransferMode ) {
2007-01-07 14:46:14 +01:00
if ( Device & & CanReplay ( ) ) {
2002-09-15 11:52:43 +02:00
cStatus : : MsgChannelSwitch ( this , 0 ) ; // only report status if we are actually going to switch the channel
2007-01-07 14:46:14 +01:00
if ( Device - > SetChannel ( Channel , false ) = = scrOk ) // calling SetChannel() directly, not SwitchChannel()!
cControl : : Launch ( new cTransferControl ( Device , Channel - > GetChannelID ( ) , Channel - > Vpid ( ) , Channel - > Apids ( ) , Channel - > Dpids ( ) , Channel - > Spids ( ) ) ) ;
2002-09-04 17:26:02 +02:00
else
Result = scrNoTransfer ;
}
2002-06-16 12:57:31 +02:00
else
2002-09-04 17:26:02 +02:00
Result = scrNotAvailable ;
2002-06-16 12:57:31 +02:00
}
2002-09-15 11:52:43 +02:00
else {
2004-01-04 12:30:00 +01:00
Channels . Lock ( false ) ;
2002-09-15 11:52:43 +02:00
cStatus : : MsgChannelSwitch ( this , 0 ) ; // only report status if we are actually going to switch the channel
2003-12-22 13:29:24 +01:00
// Stop section handling:
if ( sectionHandler ) {
sectionHandler - > SetStatus ( false ) ;
2004-01-11 15:54:37 +01:00
sectionHandler - > SetChannel ( NULL ) ;
2003-12-22 13:29:24 +01:00
}
2007-01-07 14:46:14 +01:00
// Tell the camSlot about the channel switch and add all PIDs of this
2005-11-26 13:39:47 +01:00
// channel to it, for possible later decryption:
2007-01-07 14:46:14 +01:00
if ( camSlot )
camSlot - > AddChannel ( Channel ) ;
2003-12-22 13:29:24 +01:00
if ( SetChannelDevice ( Channel , LiveView ) ) {
// Start section handling:
if ( sectionHandler ) {
2004-01-11 15:54:37 +01:00
sectionHandler - > SetChannel ( Channel ) ;
2003-12-22 13:29:24 +01:00
sectionHandler - > SetStatus ( true ) ;
}
2006-01-06 12:56:44 +01:00
// Start decrypting any PIDs that might have been set in SetChannelDevice():
2007-01-07 14:46:14 +01:00
if ( camSlot )
camSlot - > StartDecrypting ( ) ;
2003-12-22 13:29:24 +01:00
}
else
2002-09-15 11:52:43 +02:00
Result = scrFailed ;
2004-01-04 12:30:00 +01:00
Channels . Unlock ( ) ;
2002-09-08 11:46:53 +02:00
}
2005-02-27 13:40:33 +01:00
2002-09-15 11:52:43 +02:00
if ( Result = = scrOk ) {
2005-02-27 13:40:33 +01:00
if ( LiveView & & IsPrimaryDevice ( ) ) {
2005-01-08 13:53:30 +01:00
currentChannel = Channel - > Number ( ) ;
2005-02-27 13:40:33 +01:00
// Set the available audio tracks:
ClrAvailableTracks ( ) ;
for ( int i = 0 ; i < MAXAPIDS ; i + + )
SetAvailableTrack ( ttAudio , i , Channel - > Apid ( i ) , Channel - > Alang ( i ) ) ;
if ( Setup . UseDolbyDigital ) {
for ( int i = 0 ; i < MAXDPIDS ; i + + )
SetAvailableTrack ( ttDolby , i , Channel - > Dpid ( i ) , Channel - > Dlang ( i ) ) ;
}
if ( ! NeedsTransferMode )
EnsureAudioTrack ( true ) ;
}
2002-10-06 10:25:42 +02:00
cStatus : : MsgChannelSwitch ( this , Channel - > Number ( ) ) ; // only report status if channel switch successfull
2002-09-15 11:52:43 +02:00
}
2002-06-16 12:57:31 +02:00
2002-08-04 14:57:29 +02:00
return Result ;
}
2002-06-16 12:57:31 +02:00
2006-03-26 09:46:58 +02:00
void cDevice : : ForceTransferMode ( void )
{
if ( ! cTransferControl : : ReceiverDevice ( ) ) {
cChannel * Channel = Channels . GetByNumber ( CurrentChannel ( ) ) ;
if ( Channel )
SetChannelDevice ( Channel , false ) ; // this implicitly starts Transfer Mode
}
}
2002-09-04 17:26:02 +02:00
bool cDevice : : SetChannelDevice ( const cChannel * Channel , bool LiveView )
2002-08-04 14:57:29 +02:00
{
return false ;
}
2002-06-16 12:57:31 +02:00
2004-10-30 15:10:50 +02:00
bool cDevice : : HasLock ( int TimeoutMs )
2004-01-04 12:30:00 +01:00
{
return true ;
}
2003-05-03 13:42:37 +02:00
bool cDevice : : HasProgramme ( void )
{
return Replaying ( ) | | pidHandles [ ptAudio ] . pid | | pidHandles [ ptVideo ] . pid ;
}
2005-01-06 13:50:17 +01:00
int cDevice : : GetAudioChannelDevice ( void )
{
return 0 ;
}
void cDevice : : SetAudioChannelDevice ( int AudioChannel )
{
}
2002-08-04 14:57:29 +02:00
void cDevice : : SetVolumeDevice ( int Volume )
{
2002-06-16 12:57:31 +02:00
}
2005-01-06 13:50:17 +01:00
void cDevice : : SetDigitalAudioDevice ( bool On )
{
}
2004-12-17 14:55:49 +01:00
void cDevice : : SetAudioTrackDevice ( eTrackType Type )
2002-10-12 14:29:46 +02:00
{
}
2002-06-16 12:57:31 +02:00
bool cDevice : : ToggleMute ( void )
{
int OldVolume = volume ;
mute = ! mute ;
2003-03-30 12:42:23 +02:00
//XXX why is it necessary to use different sequences???
if ( mute ) {
2006-07-29 10:17:35 +02:00
SetVolume ( 0 , true ) ;
2003-03-30 12:42:23 +02:00
Audios . MuteAudio ( mute ) ; // Mute external audio after analog audio
}
else {
Audios . MuteAudio ( mute ) ; // Enable external audio before analog audio
2006-07-29 10:17:35 +02:00
SetVolume ( OldVolume , true ) ;
2003-03-30 12:42:23 +02:00
}
2002-06-16 12:57:31 +02:00
volume = OldVolume ;
return mute ;
}
2005-01-06 13:50:17 +01:00
int cDevice : : GetAudioChannel ( void )
{
int c = GetAudioChannelDevice ( ) ;
return ( 0 < = c & & c < = 2 ) ? c : 0 ;
}
void cDevice : : SetAudioChannel ( int AudioChannel )
{
if ( 0 < = AudioChannel & & AudioChannel < = 2 )
SetAudioChannelDevice ( AudioChannel ) ;
}
2002-06-16 12:57:31 +02:00
void cDevice : : SetVolume ( int Volume , bool Absolute )
{
2006-07-22 13:26:44 +02:00
int OldVolume = volume ;
2002-08-04 14:57:29 +02:00
volume = min ( max ( Absolute ? Volume : volume + Volume , 0 ) , MAXVOLUME ) ;
SetVolumeDevice ( volume ) ;
2006-09-03 11:49:32 +02:00
Absolute | = mute ;
2006-07-22 13:26:44 +02:00
cStatus : : MsgSetVolume ( Absolute ? volume : volume - OldVolume , Absolute ) ;
2002-11-03 11:53:58 +01:00
if ( volume > 0 ) {
2002-08-04 14:57:29 +02:00
mute = false ;
2002-11-03 11:53:58 +01:00
Audios . MuteAudio ( mute ) ;
}
2002-08-04 14:57:29 +02:00
}
2006-04-14 14:47:01 +02:00
void cDevice : : ClrAvailableTracks ( bool DescriptionsOnly , bool IdsOnly )
2004-12-17 14:55:49 +01:00
{
2005-01-08 10:15:30 +01:00
if ( DescriptionsOnly ) {
for ( int i = ttNone ; i < ttMaxTrackTypes ; i + + )
* availableTracks [ i ] . description = 0 ;
}
2005-01-23 14:10:15 +01:00
else {
2006-04-14 14:47:01 +02:00
if ( IdsOnly ) {
for ( int i = ttNone ; i < ttMaxTrackTypes ; i + + )
availableTracks [ i ] . id = 0 ;
}
else
memset ( availableTracks , 0 , sizeof ( availableTracks ) ) ;
2005-01-23 14:10:15 +01:00
pre_1_3_19_PrivateStream = false ;
2005-01-30 14:42:51 +01:00
SetAudioChannel ( 0 ) ; // fall back to stereo
2005-02-06 12:31:36 +01:00
currentAudioTrackMissingCount = 0 ;
2005-02-27 10:36:19 +01:00
currentAudioTrack = ttNone ;
2005-01-23 14:10:15 +01:00
}
2004-12-17 14:55:49 +01:00
}
2005-02-06 11:44:56 +01:00
bool cDevice : : SetAvailableTrack ( eTrackType Type , int Index , uint16_t Id , const char * Language , const char * Description )
2004-12-17 14:55:49 +01:00
{
eTrackType t = eTrackType ( Type + Index ) ;
2005-01-09 12:36:48 +01:00
if ( Type = = ttAudio & & IS_AUDIO_TRACK ( t ) | |
Type = = ttDolby & & IS_DOLBY_TRACK ( t ) ) {
2004-12-17 14:55:49 +01:00
if ( Language )
strn0cpy ( availableTracks [ t ] . language , Language , sizeof ( availableTracks [ t ] . language ) ) ;
2005-01-02 15:11:44 +01:00
if ( Description )
2007-06-16 10:41:21 +02:00
Utf8Strn0Cpy ( availableTracks [ t ] . description , Description , sizeof ( availableTracks [ t ] . description ) ) ;
2005-02-27 10:36:19 +01:00
if ( Id ) {
2005-01-02 15:11:44 +01:00
availableTracks [ t ] . id = Id ; // setting 'id' last to avoid the need for extensive locking
2005-02-27 10:36:19 +01:00
int numAudioTracks = NumAudioTracks ( ) ;
if ( ! availableTracks [ currentAudioTrack ] . id & & numAudioTracks & & currentAudioTrackMissingCount + + > numAudioTracks * 10 )
EnsureAudioTrack ( ) ;
else if ( t = = currentAudioTrack )
currentAudioTrackMissingCount = 0 ;
}
2004-12-17 14:55:49 +01:00
return true ;
}
else
esyslog ( " ERROR: SetAvailableTrack called with invalid Type/Index (%d/%d) " , Type , Index ) ;
return false ;
}
const tTrackId * cDevice : : GetTrack ( eTrackType Type )
{
return ( ttNone < Type & & Type < ttMaxTrackTypes ) ? & availableTracks [ Type ] : NULL ;
}
2002-10-12 14:29:46 +02:00
int cDevice : : NumAudioTracks ( void ) const
{
2004-12-17 14:55:49 +01:00
int n = 0 ;
for ( int i = ttAudioFirst ; i < = ttDolbyLast ; i + + ) {
if ( availableTracks [ i ] . id )
n + + ;
}
return n ;
2002-10-12 14:29:46 +02:00
}
2004-12-17 14:55:49 +01:00
bool cDevice : : SetCurrentAudioTrack ( eTrackType Type )
2002-10-12 14:29:46 +02:00
{
2004-12-17 14:55:49 +01:00
if ( ttNone < Type & & Type < ttDolbyLast ) {
2006-01-08 10:13:38 +01:00
cMutexLock MutexLock ( & mutexCurrentAudioTrack ) ;
2004-12-17 14:55:49 +01:00
if ( IS_DOLBY_TRACK ( Type ) )
SetDigitalAudioDevice ( true ) ;
currentAudioTrack = Type ;
if ( player )
player - > SetAudioTrack ( currentAudioTrack , GetTrack ( currentAudioTrack ) ) ;
else
SetAudioTrackDevice ( currentAudioTrack ) ;
if ( IS_AUDIO_TRACK ( Type ) )
SetDigitalAudioDevice ( false ) ;
return true ;
}
return false ;
2002-10-12 14:29:46 +02:00
}
2005-02-06 11:33:13 +01:00
void cDevice : : EnsureAudioTrack ( bool Force )
{
if ( Force | | ! availableTracks [ currentAudioTrack ] . id ) {
eTrackType PreferredTrack = ttAudioFirst ;
2005-09-04 14:48:39 +02:00
int PreferredAudioChannel = 0 ;
2005-02-06 11:33:13 +01:00
int LanguagePreference = - 1 ;
int StartCheck = Setup . CurrentDolby ? ttDolbyFirst : ttAudioFirst ;
int EndCheck = ttDolbyLast ;
for ( int i = StartCheck ; i < = EndCheck ; i + + ) {
const tTrackId * TrackId = GetTrack ( eTrackType ( i ) ) ;
2005-09-04 14:48:39 +02:00
int pos = 0 ;
if ( TrackId & & TrackId - > id & & I18nIsPreferredLanguage ( Setup . AudioLanguages , TrackId - > language , LanguagePreference , & pos ) ) {
2005-02-06 11:33:13 +01:00
PreferredTrack = eTrackType ( i ) ;
2005-09-04 14:48:39 +02:00
PreferredAudioChannel = pos ;
}
2005-02-06 11:33:13 +01:00
if ( Setup . CurrentDolby & & i = = ttDolbyLast ) {
i = ttAudioFirst - 1 ;
EndCheck = ttAudioLast ;
}
}
// Make sure we're set to an available audio track:
const tTrackId * Track = GetTrack ( GetCurrentAudioTrack ( ) ) ;
2005-02-06 12:31:36 +01:00
if ( Force | | ! Track | | ! Track - > id | | PreferredTrack ! = GetCurrentAudioTrack ( ) ) {
2005-02-08 13:21:34 +01:00
if ( ! Force ) // only log this for automatic changes
2005-09-04 14:48:39 +02:00
dsyslog ( " setting audio track to %d (%d) " , PreferredTrack , PreferredAudioChannel ) ;
2005-02-06 11:33:13 +01:00
SetCurrentAudioTrack ( PreferredTrack ) ;
2005-09-04 14:48:39 +02:00
SetAudioChannel ( PreferredAudioChannel ) ;
2005-02-06 11:33:13 +01:00
}
}
}
2002-10-26 11:51:37 +02:00
bool cDevice : : CanReplay ( void ) const
{
return HasDecoder ( ) ;
}
2002-08-15 11:16:34 +02:00
bool cDevice : : SetPlayMode ( ePlayMode PlayMode )
2002-08-04 14:57:29 +02:00
{
2002-08-15 11:16:34 +02:00
return false ;
2002-06-16 12:57:31 +02:00
}
2003-11-07 14:16:25 +01:00
int64_t cDevice : : GetSTC ( void )
{
return - 1 ;
}
2002-06-16 12:57:31 +02:00
void cDevice : : TrickSpeed ( int Speed )
{
}
void cDevice : : Clear ( void )
{
2002-11-03 11:53:58 +01:00
Audios . ClearAudio ( ) ;
2002-06-16 12:57:31 +02:00
}
void cDevice : : Play ( void )
{
2003-03-30 12:42:23 +02:00
Audios . MuteAudio ( mute ) ;
2002-06-16 12:57:31 +02:00
}
void cDevice : : Freeze ( void )
{
2003-03-30 12:42:23 +02:00
Audios . MuteAudio ( true ) ;
2002-06-16 12:57:31 +02:00
}
void cDevice : : Mute ( void )
{
2002-11-03 11:53:58 +01:00
Audios . MuteAudio ( true ) ;
2002-06-16 12:57:31 +02:00
}
void cDevice : : StillPicture ( const uchar * Data , int Length )
{
}
2002-09-29 13:40:45 +02:00
bool cDevice : : Replaying ( void ) const
2002-06-16 12:57:31 +02:00
{
return player ! = NULL ;
}
2006-02-04 14:58:24 +01:00
bool cDevice : : Transferring ( void ) const
{
return dynamic_cast < cTransfer * > ( player ) ! = NULL ;
}
2002-06-22 13:45:53 +02:00
bool cDevice : : AttachPlayer ( cPlayer * Player )
2002-06-16 12:57:31 +02:00
{
2002-10-26 11:51:37 +02:00
if ( CanReplay ( ) ) {
2002-06-16 12:57:31 +02:00
if ( player )
Detach ( player ) ;
2005-02-06 13:49:13 +01:00
pesAssembler - > Reset ( ) ;
2002-06-16 12:57:31 +02:00
player = Player ;
2006-02-24 14:14:41 +01:00
if ( ! Transferring ( ) )
2006-04-14 14:47:01 +02:00
ClrAvailableTracks ( false , true ) ;
2002-08-15 11:16:34 +02:00
SetPlayMode ( player - > playMode ) ;
2004-10-23 10:18:01 +02:00
player - > device = this ;
2002-06-16 12:57:31 +02:00
player - > Activate ( true ) ;
return true ;
}
return false ;
}
void cDevice : : Detach ( cPlayer * Player )
{
if ( Player & & player = = Player ) {
2007-01-07 14:46:14 +01:00
cPlayer * p = player ;
player = NULL ; // avoids recursive calls to Detach()
p - > Activate ( false ) ;
p - > device = NULL ;
2002-08-15 11:16:34 +02:00
SetPlayMode ( pmNone ) ;
2005-02-20 13:39:49 +01:00
SetVideoDisplayFormat ( eVideoDisplayFormat ( Setup . VideoDisplayFormat ) ) ;
2003-03-30 12:42:23 +02:00
Audios . ClearAudio ( ) ;
2002-06-16 12:57:31 +02:00
}
}
void cDevice : : StopReplay ( void )
{
if ( player ) {
Detach ( player ) ;
2002-06-23 12:59:58 +02:00
if ( IsPrimaryDevice ( ) )
cControl : : Shutdown ( ) ;
2002-06-16 12:57:31 +02:00
}
}
2002-08-16 09:22:29 +02:00
bool cDevice : : Poll ( cPoller & Poller , int TimeoutMs )
2002-08-15 10:13:03 +02:00
{
return false ;
}
2004-06-19 08:58:14 +02:00
bool cDevice : : Flush ( int TimeoutMs )
{
return true ;
}
2002-06-16 12:57:31 +02:00
int cDevice : : PlayVideo ( const uchar * Data , int Length )
{
return - 1 ;
}
2006-02-04 10:24:43 +01:00
int cDevice : : PlayAudio ( const uchar * Data , int Length , uchar Id )
2004-12-17 14:55:49 +01:00
{
return - 1 ;
}
int cDevice : : PlayPesPacket ( const uchar * Data , int Length , bool VideoOnly )
2002-06-16 12:57:31 +02:00
{
2006-01-08 10:13:38 +01:00
cMutexLock MutexLock ( & mutexCurrentAudioTrack ) ;
2004-12-17 14:55:49 +01:00
bool FirstLoop = true ;
uchar c = Data [ 3 ] ;
const uchar * Start = Data ;
const uchar * End = Start + Length ;
while ( Start < End ) {
int d = End - Start ;
int w = d ;
switch ( c ) {
2005-02-06 14:22:08 +01:00
case 0xBE : // padding stream, needed for MPEG1
2004-12-17 14:55:49 +01:00
case 0xE0 . . . 0xEF : // video
w = PlayVideo ( Start , d ) ;
break ;
case 0xC0 . . . 0xDF : // audio
SetAvailableTrack ( ttAudio , c - 0xC0 , c ) ;
2005-02-13 09:54:51 +01:00
if ( ! VideoOnly & & c = = availableTracks [ currentAudioTrack ] . id ) {
2006-02-04 10:24:43 +01:00
w = PlayAudio ( Start , d , c ) ;
2005-02-13 09:54:51 +01:00
if ( FirstLoop )
Audios . PlayAudio ( Data , Length , c ) ;
}
2004-12-17 14:55:49 +01:00
break ;
2005-01-23 14:10:15 +01:00
case 0xBD : { // private stream 1
int PayloadOffset = Data [ 8 ] + 9 ;
uchar SubStreamId = Data [ PayloadOffset ] ;
2005-01-30 13:38:06 +01:00
uchar SubStreamType = SubStreamId & 0xF0 ;
2005-01-23 14:10:15 +01:00
uchar SubStreamIndex = SubStreamId & 0x1F ;
2006-01-08 11:44:37 +01:00
2005-01-23 14:10:15 +01:00
// Compatibility mode for old VDR recordings, where 0xBD was only AC3:
2005-02-12 16:32:54 +01:00
pre_1_3_19_PrivateStreamDeteced :
2005-01-23 14:10:15 +01:00
if ( pre_1_3_19_PrivateStream ) {
SubStreamId = c ;
SubStreamType = 0x80 ;
SubStreamIndex = 0 ;
2004-12-17 14:55:49 +01:00
}
2005-01-23 14:10:15 +01:00
switch ( SubStreamType ) {
case 0x20 : // SPU
2005-01-30 13:38:06 +01:00
case 0x30 : // SPU
2005-01-23 14:10:15 +01:00
break ;
case 0x80 : // AC3 & DTS
if ( Setup . UseDolbyDigital ) {
SetAvailableTrack ( ttDolby , SubStreamIndex , SubStreamId ) ;
if ( ! VideoOnly & & SubStreamId = = availableTracks [ currentAudioTrack ] . id ) {
2006-02-04 10:24:43 +01:00
w = PlayAudio ( Start , d , SubStreamId ) ;
2005-02-12 13:01:24 +01:00
if ( FirstLoop )
Audios . PlayAudio ( Data , Length , SubStreamId ) ;
2005-01-23 14:10:15 +01:00
}
}
break ;
case 0xA0 : // LPCM
SetAvailableTrack ( ttAudio , SubStreamIndex , SubStreamId ) ;
2005-02-12 13:01:24 +01:00
if ( ! VideoOnly & & SubStreamId = = availableTracks [ currentAudioTrack ] . id ) {
2006-02-04 10:24:43 +01:00
w = PlayAudio ( Start , d , SubStreamId ) ;
2005-02-12 13:01:24 +01:00
if ( FirstLoop )
Audios . PlayAudio ( Data , Length , SubStreamId ) ;
}
2005-01-23 14:10:15 +01:00
break ;
2005-02-06 13:19:19 +01:00
default :
// Compatibility mode for old VDR recordings, where 0xBD was only AC3:
if ( ! pre_1_3_19_PrivateStream ) {
dsyslog ( " switching to pre 1.3.19 Dolby Digital compatibility mode " ) ;
ClrAvailableTracks ( ) ;
pre_1_3_19_PrivateStream = true ;
2005-02-12 16:32:54 +01:00
goto pre_1_3_19_PrivateStreamDeteced ;
2005-02-06 13:19:19 +01:00
}
2005-01-23 14:10:15 +01:00
}
}
2004-12-17 14:55:49 +01:00
break ;
default :
; //esyslog("ERROR: unexpected packet id %02X", c);
}
if ( w > 0 )
Start + = w ;
2005-01-16 14:40:47 +01:00
else {
2004-12-17 14:55:49 +01:00
if ( Start ! = Data )
esyslog ( " ERROR: incomplete PES packet write! " ) ;
return Start = = Data ? w : Start - Data ;
}
FirstLoop = false ;
}
return Length ;
2002-06-16 12:57:31 +02:00
}
2004-12-17 14:55:49 +01:00
int cDevice : : PlayPes ( const uchar * Data , int Length , bool VideoOnly )
{
if ( ! Data ) {
pesAssembler - > Reset ( ) ;
return 0 ;
}
int Result = 0 ;
if ( pesAssembler - > Length ( ) ) {
// Make sure we have a complete PES header:
while ( pesAssembler - > Length ( ) < 6 & & Length > 0 ) {
pesAssembler - > Put ( * Data + + ) ;
Length - - ;
Result + + ;
}
if ( pesAssembler - > Length ( ) < 6 )
return Result ; // Still no complete PES header - wait for more
int l = pesAssembler - > ExpectedLength ( ) ;
int Rest = min ( l - pesAssembler - > Length ( ) , Length ) ;
pesAssembler - > Put ( Data , Rest ) ;
Data + = Rest ;
Length - = Rest ;
Result + = Rest ;
if ( pesAssembler - > Length ( ) < l )
return Result ; // Still no complete PES packet - wait for more
// Now pesAssembler contains one complete PES packet.
int w = PlayPesPacket ( pesAssembler - > Data ( ) , pesAssembler - > Length ( ) , VideoOnly ) ;
if ( w > 0 )
pesAssembler - > Reset ( ) ;
return Result > 0 ? Result : w < 0 ? w : 0 ;
}
int i = 0 ;
while ( i < = Length - 6 ) {
if ( Data [ i ] = = 0x00 & & Data [ i + 1 ] = = 0x00 & & Data [ i + 2 ] = = 0x01 ) {
2005-02-06 14:22:08 +01:00
int l = cPesAssembler : : PacketSize ( & Data [ i ] ) ;
2004-12-17 14:55:49 +01:00
if ( i + l > Length ) {
// Store incomplete PES packet for later completion:
pesAssembler - > Put ( Data + i , Length - i ) ;
return Length ;
}
int w = PlayPesPacket ( Data + i , l , VideoOnly ) ;
if ( w > 0 )
i + = l ;
2005-02-08 11:47:15 +01:00
else
2004-12-17 14:55:49 +01:00
return i = = 0 ? w : i ;
}
else
i + + ;
}
if ( i < Length )
pesAssembler - > Put ( Data + i , Length - i ) ;
return Length ;
2005-02-27 10:36:19 +01:00
}
2004-12-17 14:55:49 +01:00
2002-09-29 13:40:45 +02:00
int cDevice : : Priority ( void ) const
2002-06-16 12:57:31 +02:00
{
2002-09-04 17:26:02 +02:00
int priority = IsPrimaryDevice ( ) ? Setup . PrimaryLimit - 1 : DEFAULTPRIORITY ;
2002-06-16 12:57:31 +02:00
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
if ( receiver [ i ] )
priority = max ( receiver [ i ] - > priority , priority ) ;
}
return priority ;
}
2005-08-21 08:56:49 +02:00
bool cDevice : : Ready ( void )
{
return true ;
}
2002-11-01 11:11:20 +01:00
bool cDevice : : Receiving ( bool CheckAny ) const
2002-06-16 12:57:31 +02:00
{
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
2002-11-01 11:11:20 +01:00
if ( receiver [ i ] & & ( CheckAny | | receiver [ i ] - > priority > = 0 ) ) // cReceiver with priority < 0 doesn't count
2002-06-16 12:57:31 +02:00
return true ;
}
return false ;
}
2007-01-07 14:46:14 +01:00
# define TS_SCRAMBLING_CONTROL 0xC0
# define TS_SCRAMBLING_TIMEOUT 3 // seconds to wait until a TS becomes unscrambled
# define TS_SCRAMBLING_TIME_OK 10 // seconds before a Channel/CAM combination is marked a known to decrypt
2002-06-16 12:57:31 +02:00
void cDevice : : Action ( void )
{
2005-08-14 11:24:57 +02:00
if ( Running ( ) & & OpenDvr ( ) ) {
while ( Running ( ) ) {
2005-08-13 13:17:24 +02:00
// Read data from the DVR device:
uchar * b = NULL ;
if ( GetTSPacket ( b ) ) {
if ( b ) {
int Pid = ( ( ( uint16_t ) b [ 1 ] & PID_MASK_HI ) < < 8 ) | b [ 2 ] ;
2007-01-07 14:46:14 +01:00
// Check whether the TS packets are scrambled:
bool DetachReceivers = false ;
bool DescramblingOk = false ;
int CamSlotNumber = 0 ;
if ( startScrambleDetection ) {
cCamSlot * cs = CamSlot ( ) ;
CamSlotNumber = cs ? cs - > SlotNumber ( ) : 0 ;
if ( CamSlotNumber ) {
bool Scrambled = b [ 3 ] & TS_SCRAMBLING_CONTROL ;
int t = time ( NULL ) - startScrambleDetection ;
if ( Scrambled ) {
if ( t > TS_SCRAMBLING_TIMEOUT )
DetachReceivers = true ;
}
else if ( t > TS_SCRAMBLING_TIME_OK ) {
DescramblingOk = true ;
startScrambleDetection = 0 ;
}
}
}
2005-08-13 13:17:24 +02:00
// Distribute the packet to all attached receivers:
Lock ( ) ;
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
2007-01-07 14:46:14 +01:00
if ( receiver [ i ] & & receiver [ i ] - > WantsPid ( Pid ) ) {
if ( DetachReceivers ) {
ChannelCamRelations . SetChecked ( receiver [ i ] - > ChannelID ( ) , CamSlotNumber ) ;
Detach ( receiver [ i ] ) ;
}
else
receiver [ i ] - > Receive ( b , TS_SIZE ) ;
if ( DescramblingOk )
ChannelCamRelations . SetDecrypt ( receiver [ i ] - > ChannelID ( ) , CamSlotNumber ) ;
}
2005-08-13 13:17:24 +02:00
}
Unlock ( ) ;
}
}
else
break ;
}
2002-08-04 14:57:29 +02:00
CloseDvr ( ) ;
2002-06-16 12:57:31 +02:00
}
}
2002-08-04 14:57:29 +02:00
bool cDevice : : OpenDvr ( void )
{
return false ;
}
void cDevice : : CloseDvr ( void )
{
}
2002-09-08 09:03:10 +02:00
bool cDevice : : GetTSPacket ( uchar * & Data )
2002-08-04 14:57:29 +02:00
{
2002-09-08 09:03:10 +02:00
return false ;
2002-08-04 14:57:29 +02:00
}
2002-06-22 13:45:53 +02:00
bool cDevice : : AttachReceiver ( cReceiver * Receiver )
2002-06-16 12:57:31 +02:00
{
if ( ! Receiver )
return false ;
if ( Receiver - > device = = this )
return true ;
2005-09-02 13:55:37 +02:00
// activate the following line if you need it - actually the driver should be fixed!
//#define WAIT_FOR_TUNER_LOCK
# ifdef WAIT_FOR_TUNER_LOCK
# define TUNER_LOCK_TIMEOUT 5000 // ms
if ( ! HasLock ( TUNER_LOCK_TIMEOUT ) ) {
esyslog ( " ERROR: device %d has no lock, can't attach receiver! " , CardIndex ( ) + 1 ) ;
return false ;
}
# endif
2004-12-24 15:37:11 +01:00
cMutexLock MutexLock ( & mutexReceiver ) ;
2002-06-16 12:57:31 +02:00
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
if ( ! receiver [ i ] ) {
2005-01-16 14:40:47 +01:00
for ( int n = 0 ; n < Receiver - > numPids ; n + + ) {
2004-10-17 09:42:36 +02:00
if ( ! AddPid ( Receiver - > pids [ n ] ) ) {
for ( ; n - - > 0 ; )
DelPid ( Receiver - > pids [ n ] ) ;
return false ;
}
}
2002-06-16 12:57:31 +02:00
Receiver - > Activate ( true ) ;
Lock ( ) ;
Receiver - > device = this ;
receiver [ i ] = Receiver ;
Unlock ( ) ;
2007-01-07 14:46:14 +01:00
if ( camSlot ) {
camSlot - > StartDecrypting ( ) ;
startScrambleDetection = time ( NULL ) ;
}
Start ( ) ;
2002-06-16 12:57:31 +02:00
return true ;
}
}
esyslog ( " ERROR: no free receiver slot! " ) ;
return false ;
}
void cDevice : : Detach ( cReceiver * Receiver )
{
if ( ! Receiver | | Receiver - > device ! = this )
return ;
bool receiversLeft = false ;
2004-12-24 15:37:11 +01:00
cMutexLock MutexLock ( & mutexReceiver ) ;
2002-06-16 12:57:31 +02:00
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
if ( receiver [ i ] = = Receiver ) {
Receiver - > Activate ( false ) ;
Lock ( ) ;
receiver [ i ] = NULL ;
Receiver - > device = NULL ;
Unlock ( ) ;
2005-01-16 14:40:47 +01:00
for ( int n = 0 ; n < Receiver - > numPids ; n + + )
2002-07-28 11:29:32 +02:00
DelPid ( Receiver - > pids [ n ] ) ;
2002-06-16 12:57:31 +02:00
}
else if ( receiver [ i ] )
receiversLeft = true ;
}
2007-01-07 14:46:14 +01:00
if ( camSlot )
camSlot - > StartDecrypting ( ) ;
2005-08-13 13:17:24 +02:00
if ( ! receiversLeft )
2007-01-07 14:46:14 +01:00
Cancel ( - 1 ) ;
2002-06-16 12:57:31 +02:00
}
2002-09-08 09:03:10 +02:00
2005-06-05 13:37:37 +02:00
void cDevice : : DetachAll ( int Pid )
{
if ( Pid ) {
cMutexLock MutexLock ( & mutexReceiver ) ;
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
cReceiver * Receiver = receiver [ i ] ;
if ( Receiver & & Receiver - > WantsPid ( Pid ) )
Detach ( Receiver ) ;
}
}
}
2006-01-06 13:55:57 +01:00
void cDevice : : DetachAllReceivers ( void )
{
cMutexLock MutexLock ( & mutexReceiver ) ;
2007-01-07 14:46:14 +01:00
for ( int i = 0 ; i < MAXRECEIVERS ; i + + )
Detach ( receiver [ i ] ) ;
2006-01-06 13:55:57 +01:00
}
2002-09-08 09:03:10 +02:00
// --- cTSBuffer -------------------------------------------------------------
cTSBuffer : : cTSBuffer ( int File , int Size , int CardIndex )
{
2004-10-16 09:36:28 +02:00
SetDescription ( " TS buffer on device %d " , CardIndex ) ;
2002-09-08 09:03:10 +02:00
f = File ;
cardIndex = CardIndex ;
2004-10-16 09:36:28 +02:00
delivered = false ;
ringBuffer = new cRingBufferLinear ( Size , TS_SIZE , true , " TS " ) ;
ringBuffer - > SetTimeouts ( 100 , 100 ) ;
Start ( ) ;
2002-09-08 09:03:10 +02:00
}
cTSBuffer : : ~ cTSBuffer ( )
{
2004-10-16 09:36:28 +02:00
Cancel ( 3 ) ;
delete ringBuffer ;
}
void cTSBuffer : : Action ( void )
{
if ( ringBuffer ) {
bool firstRead = true ;
cPoller Poller ( f ) ;
2005-08-14 11:24:57 +02:00
while ( Running ( ) ) {
2005-08-13 13:17:24 +02:00
if ( firstRead | | Poller . Poll ( 100 ) ) {
firstRead = false ;
int r = ringBuffer - > Read ( f ) ;
if ( r < 0 & & FATALERRNO ) {
if ( errno = = EOVERFLOW )
esyslog ( " ERROR: driver buffer overflow on device %d " , cardIndex ) ;
else {
LOG_ERROR ;
break ;
}
}
}
}
2002-09-08 09:03:10 +02:00
}
}
uchar * cTSBuffer : : Get ( void )
{
2004-10-16 09:36:28 +02:00
int Count = 0 ;
if ( delivered ) {
ringBuffer - > Del ( TS_SIZE ) ;
delivered = false ;
}
uchar * p = ringBuffer - > Get ( Count ) ;
if ( p & & Count > = TS_SIZE ) {
2002-09-08 09:03:10 +02:00
if ( * p ! = TS_SYNC_BYTE ) {
2004-10-16 09:36:28 +02:00
for ( int i = 1 ; i < Count ; i + + ) {
if ( p [ i ] = = TS_SYNC_BYTE ) {
Count = i ;
break ;
2002-09-08 09:03:10 +02:00
}
}
2004-10-16 09:36:28 +02:00
ringBuffer - > Del ( Count ) ;
esyslog ( " ERROR: skipped %d bytes to sync on TS packet on device %d " , Count , cardIndex ) ;
2002-09-08 09:03:10 +02:00
return NULL ;
}
2004-10-16 09:36:28 +02:00
delivered = true ;
2002-09-08 09:03:10 +02:00
return p ;
}
return NULL ;
}