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 .
*
2006-09-03 11:49:32 +02:00
* $ Id : device . c 1.137 2006 / 09 / 03 10 : 13 : 25 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
2003-01-06 14:44:27 +01:00
ciHandler = NULL ;
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 ) ;
for ( int i = 0 ; i < MAXRECEIVERS ; i + + )
Detach ( receiver [ i ] ) ;
2003-01-06 14:44:27 +01:00
delete ciHandler ;
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 + + ) {
if ( device [ i ] & & ! device [ i ] - > Ready ( ) )
ready = false ;
}
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 ;
}
2002-09-06 14:10:17 +02:00
cDevice * cDevice : : GetDevice ( const cChannel * Channel , int Priority , bool * NeedsDetachReceivers )
2002-06-16 12:57:31 +02:00
{
cDevice * d = NULL ;
2006-06-15 10:00:40 +02:00
uint Impact = 0xFFFFFFFF ; // we're looking for a device with the least impact
2002-06-16 12:57:31 +02:00
for ( int i = 0 ; i < numDevices ; i + + ) {
2002-09-06 14:10:17 +02:00
bool ndr ;
2003-08-02 11:52:29 +02:00
if ( device [ i ] - > ProvidesChannel ( Channel , Priority , & ndr ) ) { // this device is basicly able to do the job
2006-06-15 10:00:40 +02:00
// 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.
2006-05-27 09:43:37 +02:00
uint imp = 0 ;
2006-08-27 08:42:31 +02:00
imp < < = 1 ; imp | = ! device [ i ] - > Receiving ( ) | | ndr ; // use receiving devices if we don't need to detach existing receivers
2006-06-15 10:00:40 +02:00
imp < < = 1 ; imp | = device [ i ] - > Receiving ( ) ; // avoid devices that are receiving
2006-08-12 11:33:34 +02:00
imp < < = 1 ; imp | = device [ i ] = = cTransferControl : : ReceiverDevice ( ) ; // avoid the Transfer Mode receiver device
2006-06-15 10:00:40 +02:00
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 ( device [ i ] - > ProvidesCa ( Channel ) , 0 ) , 0xFF ) ; // use the device that provides the lowest number of conditional access methods
2006-08-12 11:33:34 +02:00
imp < < = 1 ; imp | = device [ i ] - > IsPrimaryDevice ( ) ; // avoid the primary device
imp < < = 1 ; imp | = device [ i ] - > HasDecoder ( ) ; // avoid full featured cards
2006-05-27 09:43:37 +02:00
if ( imp < Impact ) {
2006-06-15 10:00:40 +02:00
// This device has less impact than any previous one, so we take it.
2006-05-27 09:43:37 +02:00
Impact = imp ;
2003-08-02 11:52:29 +02:00
d = device [ i ] ;
if ( NeedsDetachReceivers )
* NeedsDetachReceivers = ndr ;
}
2002-06-16 12:57:31 +02:00
}
}
return d ;
}
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 ;
}
2005-11-26 13:39:47 +01:00
if ( ciHandler )
ciHandler - > 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 ;
}
2005-11-26 13:39:47 +01:00
if ( ciHandler )
ciHandler - > 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 ;
2005-11-26 13:39:47 +01:00
if ( ciHandler )
ciHandler - > 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 )
{
if ( LiveView )
2002-10-06 10:25:42 +02:00
isyslog ( " switching to channel %d " , Channel - > Number ( ) ) ;
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 ) {
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
2002-10-26 11:51:37 +02:00
if ( PrimaryDevice ( ) - > ProvidesChannel ( channel , Setup . PrimaryLimit ) | | PrimaryDevice ( ) - > CanReplay ( ) & & GetDevice ( channel , 0 ) )
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 ( " skipped 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
2006-01-06 13:55:57 +01:00
// If this card is switched to an other transponder, any receivers still
2006-05-27 11:14:42 +02:00
// attached to it need to be automatically detached:
2006-01-06 13:55:57 +01:00
bool NeedsDetachReceivers = false ;
2002-06-16 12:57:31 +02:00
// If this card can't receive this channel, we must not actually switch
// the channel here, because that would irritate the driver when we
// start replaying in Transfer Mode immediately after switching the channel:
2006-01-06 13:55:57 +01:00
bool NeedsTransferMode = ( LiveView & & IsPrimaryDevice ( ) & & ! ProvidesChannel ( Channel , Setup . PrimaryLimit , & NeedsDetachReceivers ) ) ;
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 ) {
2006-01-06 13:55:57 +01:00
cDevice * CaDevice = GetDevice ( Channel , 0 , & NeedsDetachReceivers ) ;
2002-10-26 11:51:37 +02:00
if ( CaDevice & & 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
2006-01-06 13:55:57 +01:00
if ( CaDevice - > SetChannel ( Channel , false ) = = scrOk ) { // calling SetChannel() directly, not SwitchChannel()!
if ( NeedsDetachReceivers )
CaDevice - > DetachAllReceivers ( ) ;
2005-01-16 14:40:47 +01:00
cControl : : Launch ( new cTransferControl ( CaDevice , Channel - > Vpid ( ) , Channel - > Apids ( ) , Channel - > Dpids ( ) , Channel - > Spids ( ) ) ) ;
2006-01-06 13:55:57 +01:00
}
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
}
2005-11-26 13:39:47 +01:00
// Tell the ciHandler about the channel switch and add all PIDs of this
// channel to it, for possible later decryption:
if ( ciHandler ) {
ciHandler - > SetSource ( Channel - > Source ( ) , Channel - > Transponder ( ) ) ;
// Men at work - please stand clear! ;-)
# ifdef XXX_DO_MULTIPLE_CA_CHANNELS
2006-01-07 14:10:17 +01:00
if ( Channel - > Ca ( ) > = CA_ENCRYPTED_MIN ) {
2005-11-26 13:39:47 +01:00
# endif
ciHandler - > AddPid ( Channel - > Sid ( ) , Channel - > Vpid ( ) , 2 ) ;
for ( const int * Apid = Channel - > Apids ( ) ; * Apid ; Apid + + )
ciHandler - > AddPid ( Channel - > Sid ( ) , * Apid , 4 ) ;
for ( const int * Dpid = Channel - > Dpids ( ) ; * Dpid ; Dpid + + )
ciHandler - > AddPid ( Channel - > Sid ( ) , * Dpid , 0 ) ;
# ifdef XXX_DO_MULTIPLE_CA_CHANNELS
bool CanDecrypt = ciHandler - > CanDecrypt ( Channel - > Sid ( ) ) ; //XXX
dsyslog ( " CanDecrypt %d %d %d %s " , CardIndex ( ) + 1 , CanDecrypt , Channel - > Number ( ) , Channel - > Name ( ) ) ; //XXX
}
# endif
}
2006-01-06 13:55:57 +01:00
if ( NeedsDetachReceivers )
DetachAllReceivers ( ) ;
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():
2005-11-26 13:39:47 +01:00
if ( ciHandler )
ciHandler - > 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 )
strn0cpy ( 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 ) {
player - > Activate ( false ) ;
player - > device = NULL ;
player = 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-10-26 09:43:11 +02:00
int cDevice : : Ca ( void ) const
{
int ca = 0 ;
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
if ( receiver [ i ] & & ( ca = receiver [ i ] - > ca ) ! = 0 )
break ; // all receivers have the same ca
}
return ca ;
}
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 ;
}
2004-01-04 12:30:00 +01:00
int cDevice : : ProvidesCa ( const cChannel * Channel ) const
2002-06-16 12:57:31 +02:00
{
2004-01-04 12:30:00 +01:00
int Ca = Channel - > Ca ( ) ;
2002-06-16 12:57:31 +02:00
if ( Ca = = CardIndex ( ) + 1 )
return 1 ; // exactly _this_ card was requested
2006-01-07 15:16:09 +01:00
if ( Ca & & Ca < = CA_DVB_MAX )
2002-06-16 12:57:31 +02:00
return 0 ; // a specific card was requested, but not _this_ one
2004-01-04 12:30:00 +01:00
return ! Ca ; // by default every card can provide FTA
2002-06-16 12:57:31 +02:00
}
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 ;
}
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 ] ;
// Distribute the packet to all attached receivers:
Lock ( ) ;
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
if ( receiver [ i ] & & receiver [ i ] - > WantsPid ( Pid ) )
receiver [ i ] - > Receive ( b , TS_SIZE ) ;
}
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 ( ) ;
2005-08-14 11:24:57 +02:00
if ( ! Running ( ) )
2005-01-16 14:50:33 +01:00
Start ( ) ;
2005-11-26 13:39:47 +01:00
if ( ciHandler )
ciHandler - > StartDecrypting ( ) ;
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 ;
}
2005-11-26 13:39:47 +01:00
if ( ciHandler )
ciHandler - > StartDecrypting ( ) ;
2005-08-13 13:17:24 +02:00
if ( ! receiversLeft )
2002-06-16 12:57:31 +02:00
Cancel ( 3 ) ;
}
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 ) ;
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
if ( receiver [ i ] )
Detach ( receiver [ i ] ) ;
}
}
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 ;
}