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 .
*
2022-12-07 09:38:05 +01:00
* $ Id : device . c 5.6 2022 / 12 / 07 09 : 38 : 05 kls Exp $
2002-06-16 12:57:31 +02:00
*/
# include "device.h"
# include <errno.h>
2015-01-12 14:56:42 +01:00
# include <math.h>
2002-06-16 12:57:31 +02:00
# 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
2007-10-12 14:52:30 +02:00
// --- cLiveSubtitle ---------------------------------------------------------
2008-08-15 14:49:34 +02:00
class cLiveSubtitle : public cReceiver {
2007-10-12 14:52:30 +02:00
protected :
2015-09-05 11:49:56 +02:00
virtual void Receive ( const uchar * Data , int Length ) ;
2007-10-12 14:52:30 +02:00
public :
cLiveSubtitle ( int SPid ) ;
virtual ~ cLiveSubtitle ( ) ;
} ;
cLiveSubtitle : : cLiveSubtitle ( int SPid )
{
2010-01-30 11:10:25 +01:00
AddPid ( SPid ) ;
2007-10-12 14:52:30 +02:00
}
cLiveSubtitle : : ~ cLiveSubtitle ( )
{
cReceiver : : Detach ( ) ;
}
2015-09-05 11:49:56 +02:00
void cLiveSubtitle : : Receive ( const uchar * Data , int Length )
2007-10-12 14:52:30 +02:00
{
2012-02-12 15:45:59 +01:00
if ( cDevice : : PrimaryDevice ( ) )
cDevice : : PrimaryDevice ( ) - > PlayTs ( Data , Length ) ;
2005-02-06 14:22:08 +01:00
}
2010-02-06 14:23:03 +01:00
// --- cDeviceHook -----------------------------------------------------------
cDeviceHook : : cDeviceHook ( void )
{
cDevice : : deviceHooks . Add ( this ) ;
}
bool cDeviceHook : : DeviceProvidesTransponder ( const cDevice * Device , const cChannel * Channel ) const
{
return true ;
}
2020-06-10 14:52:43 +02:00
bool cDeviceHook : : DeviceProvidesEIT ( const cDevice * Device ) const
{
return true ;
}
2002-09-08 09:03:10 +02:00
// --- cDevice ---------------------------------------------------------------
2007-11-03 14:32:03 +01:00
// The minimum number of unknown PS1 packets to consider this a "pre 1.3.19 private stream":
# define MIN_PRE_1_3_19_PRIVATESTREAM 10
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 ;
2010-02-06 14:23:03 +01:00
cList < cDeviceHook > cDevice : : deviceHooks ;
2002-06-16 12:57:31 +02:00
2002-08-04 14:57:29 +02:00
cDevice : : cDevice ( void )
2009-06-06 13:26:23 +02:00
: patPmtParser ( true )
2002-06-16 12:57:31 +02:00
{
2002-08-04 14:57:29 +02:00
cardIndex = nextCardIndex + + ;
2019-05-28 15:54:22 +02:00
dsyslog ( " new device number %d (card index %d) " , numDevices + 1 , CardIndex ( ) + 1 ) ;
2002-06-16 12:57:31 +02:00
2019-05-28 15:54:22 +02:00
SetDescription ( " device %d receiver " , numDevices + 1 ) ;
2003-10-18 12:29:08 +02:00
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 ;
2011-10-16 14:02:34 +02:00
occupiedTimeout = 0 ;
2002-06-16 12:57:31 +02:00
player = NULL ;
2009-01-25 11:39:43 +01:00
isPlayingVideo = false ;
2013-04-05 10:27:16 +02:00
keepTracks = false ; // used in ClrAvailableTracks()!
2004-12-17 14:55:49 +01:00
ClrAvailableTracks ( ) ;
2005-02-27 10:36:19 +01:00
currentAudioTrack = ttNone ;
2005-02-06 11:33:13 +01:00
currentAudioTrackMissingCount = 0 ;
2007-10-12 14:52:30 +02:00
currentSubtitleTrack = ttNone ;
liveSubtitle = NULL ;
dvbSubtitleConverter = NULL ;
autoSelectPreferredSubtitleLanguage = true ;
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 ( ) ;
2007-10-12 14:52:30 +02:00
delete liveSubtitle ;
delete dvbSubtitleConverter ;
2013-08-22 10:33:59 +02:00
if ( this = = primaryDevice )
primaryDevice = NULL ;
2018-01-27 14:45:08 +01:00
Cancel ( 3 ) ;
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 )
2010-06-03 13:35:02 +02:00
esyslog ( " ERROR: invalid value in nextCardIndex(%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 ;
}
2012-04-04 09:52:15 +02:00
cString cDevice : : DeviceType ( void ) const
{
return " " ;
}
2012-03-13 10:20:42 +01:00
cString cDevice : : DeviceName ( void ) const
{
return " " ;
}
2002-08-04 14:57:29 +02:00
void cDevice : : MakePrimaryDevice ( bool On )
{
2010-01-01 15:15:36 +01:00
if ( ! On ) {
DELETENULL ( liveSubtitle ) ;
DELETENULL ( dvbSubtitleConverter ) ;
}
2002-08-04 14:57:29 +02:00
}
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 ) ;
2007-10-13 10:34:30 +02:00
primaryDevice - > SetVolumeDevice ( Setup . CurrentVolume ) ;
2018-03-24 09:58:03 +01:00
Setup . PrimaryDVB = n + 1 ;
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 ;
}
2008-04-12 13:39:12 +02:00
static int GetClippedNumProvidedSystems ( int AvailableBits , cDevice * Device )
{
2010-04-11 13:02:42 +02:00
int MaxNumProvidedSystems = ( 1 < < AvailableBits ) - 1 ;
2008-04-12 13:39:12 +02:00
int NumProvidedSystems = Device - > NumProvidedSystems ( ) ;
if ( NumProvidedSystems > MaxNumProvidedSystems ) {
2019-05-28 15:54:22 +02:00
esyslog ( " ERROR: device %d supports %d modulation systems but cDevice::GetDevice() currently only supports %d delivery systems which should be fixed " , Device - > DeviceNumber ( ) + 1 , NumProvidedSystems , MaxNumProvidedSystems ) ;
2008-04-12 13:39:12 +02:00
NumProvidedSystems = MaxNumProvidedSystems ;
}
else if ( NumProvidedSystems < = 0 ) {
2019-05-28 15:54:22 +02:00
esyslog ( " ERROR: device %d reported an invalid number (%d) of supported delivery systems - assuming 1 " , Device - > DeviceNumber ( ) + 1 , NumProvidedSystems ) ;
2008-04-12 13:39:12 +02:00
NumProvidedSystems = 1 ;
}
return NumProvidedSystems ;
}
2012-03-02 10:43:26 +01:00
cDevice * cDevice : : GetDevice ( const cChannel * Channel , int Priority , bool LiveView , bool Query )
2007-01-07 14:46:14 +01:00
{
// Collect the current priorities of all CAM slots that can decrypt the channel:
int NumCamSlots = CamSlots . Count ( ) ;
2022-12-07 09:38:05 +01:00
int SlotPriority [ NumCamSlots + 1 ] ; // +1 to avoid a zero sized array in case there are no CAM slots
2007-01-07 14:46:14 +01:00
int NumUsableSlots = 0 ;
2012-08-26 13:59:37 +02:00
bool InternalCamNeeded = false ;
2007-01-07 14:46:14 +01:00
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 ( ) ) ) {
2017-01-23 12:01:48 +01:00
if ( ! ChannelCamRelations . CamChecked ( Channel - > GetChannelID ( ) , CamSlot - > MasterSlotNumber ( ) ) ) {
2017-04-02 10:08:49 +02:00
SlotPriority [ CamSlot - > Index ( ) ] = CamSlot - > MtdActive ( ) ? IDLEPRIORITY : CamSlot - > Priority ( ) ; // we don't need to take the priority into account here for MTD CAM slots, because they can be used with several devices in parallel
2007-01-07 14:46:14 +01:00
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 )
2012-08-26 13:59:37 +02:00
InternalCamNeeded = true ; // no CAM is able to decrypt this channel
2007-01-07 14:46:14 +01:00
}
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 + + ) {
2019-05-28 15:54:22 +02:00
if ( Channel - > Ca ( ) & & Channel - > Ca ( ) < = CA_DVB_MAX & & Channel - > Ca ( ) ! = device [ i ] - > DeviceNumber ( ) + 1 )
2007-01-07 14:46:14 +01:00
continue ; // a specific card was requested, but not this one
2012-08-26 13:59:37 +02:00
bool HasInternalCam = device [ i ] - > HasInternalCam ( ) ;
if ( InternalCamNeeded & & ! HasInternalCam )
continue ; // no CAM is able to decrypt this channel and the device uses vdr handled CAMs
if ( NumUsableSlots & & ! HasInternalCam & & ! CamSlots . Get ( j ) - > Assign ( device [ i ] , true ) )
2007-01-07 14:46:14 +01:00
continue ; // CAM slot can't be used with this device
bool ndr ;
2012-06-09 14:40:26 +02:00
if ( device [ i ] - > ProvidesChannel ( Channel , Priority , & ndr ) ) { // this device is basically able to do the job
2017-03-18 16:33:59 +01:00
if ( NumUsableSlots & & ! HasInternalCam ) {
if ( cCamSlot * csi = device [ i ] - > CamSlot ( ) ) {
cCamSlot * csj = CamSlots . Get ( j ) ;
if ( ( csj - > MtdActive ( ) ? csi - > MasterSlot ( ) : csi ) ! = csj )
ndr = true ; // using a different CAM slot requires detaching receivers
}
}
2007-01-07 14:46:14 +01: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.
uint32_t imp = 0 ;
2017-05-09 09:13:36 +02:00
imp < < = 1 ; imp | = ( LiveView & & NumUsableSlots & & ! HasInternalCam ) ? ! ChannelCamRelations . CamDecrypt ( Channel - > GetChannelID ( ) , CamSlots . Get ( j ) - > MasterSlotNumber ( ) ) | | ndr : 0 ; // prefer CAMs that are known to decrypt this channel for live viewing, if we don't need to detach existing receivers
2007-01-07 14:46:14 +01:00
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
2021-01-11 10:36:05 +01:00
imp < < = 5 ; imp | = GetClippedNumProvidedSystems ( 5 , device [ i ] ) - 1 ; // avoid cards which support multiple delivery systems
2007-01-07 14:46:14 +01:00
imp < < = 1 ; imp | = device [ i ] = = cTransferControl : : ReceiverDevice ( ) ; // avoid the Transfer Mode receiver device
2012-03-02 10:19:00 +01:00
imp < < = 8 ; imp | = device [ i ] - > Priority ( ) - IDLEPRIORITY ; // use the device with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
2012-08-26 13:59:37 +02:00
imp < < = 8 ; imp | = ( ( NumUsableSlots & & ! HasInternalCam ) ? SlotPriority [ j ] : IDLEPRIORITY ) - IDLEPRIORITY ; // use the CAM slot with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
2007-01-07 14:46:14 +01:00
imp < < = 1 ; imp | = ndr ; // avoid devices if we need to detach existing receivers
2012-08-26 13:59:37 +02:00
imp < < = 1 ; imp | = ( NumUsableSlots | | InternalCamNeeded ) ? 0 : device [ i ] - > HasCi ( ) ; // avoid cards with Common Interface for FTA channels
2011-05-21 13:40:47 +02:00
imp < < = 1 ; imp | = device [ i ] - > AvoidRecording ( ) ; // avoid SD full featured cards
2017-01-23 12:01:48 +01:00
imp < < = 1 ; imp | = ( NumUsableSlots & & ! HasInternalCam ) ? ! ChannelCamRelations . CamDecrypt ( Channel - > GetChannelID ( ) , CamSlots . Get ( j ) - > MasterSlotNumber ( ) ) : 0 ; // prefer CAMs that are known to decrypt this channel
2011-05-22 09:42:57 +02:00
imp < < = 1 ; imp | = device [ i ] - > IsPrimaryDevice ( ) ; // avoid the primary device
2007-01-07 14:46:14 +01:00
if ( imp < Impact ) {
// This device has less impact than any previous one, so we take it.
Impact = imp ;
d = device [ i ] ;
NeedsDetachReceivers = ndr ;
2012-08-26 13:59:37 +02:00
if ( NumUsableSlots & & ! HasInternalCam )
2007-01-07 14:46:14 +01:00
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
}
2017-03-23 14:34:53 +01:00
if ( d ) {
if ( ! Query & & NeedsDetachReceivers )
2007-01-07 14:46:14 +01:00
d - > DetachAllReceivers ( ) ;
if ( s ) {
2017-03-18 16:33:59 +01:00
// Some of the following statements could probably be combined, but let's keep them
// explicit so we can clearly see every single aspect of the decisions made here.
if ( d - > CamSlot ( ) ) {
if ( s - > MtdActive ( ) ) {
if ( s = = d - > CamSlot ( ) - > MasterSlot ( ) ) {
// device d already has a proper CAM slot, so nothing to do here
}
else {
// device d has a CAM slot, but it's not the right one
2017-03-23 14:34:53 +01:00
if ( ! Query ) {
d - > CamSlot ( ) - > Assign ( NULL ) ;
s = s - > MtdSpawn ( ) ;
s - > Assign ( d ) ;
}
2017-03-18 16:33:59 +01:00
}
}
else {
if ( s - > Device ( ) ) {
if ( s - > Device ( ) ! = d ) {
// CAM slot s is currently assigned to a different device than d
if ( Priority > s - > Priority ( ) ) {
2017-03-23 14:34:53 +01:00
if ( ! Query ) {
d - > CamSlot ( ) - > Assign ( NULL ) ;
s - > Assign ( d ) ;
}
2017-03-18 16:33:59 +01:00
}
else {
d = NULL ;
s = NULL ;
}
}
else {
// device d already has a proper CAM slot, so nothing to do here
}
}
else {
if ( s ! = d - > CamSlot ( ) ) {
// device d has a CAM slot, but it's not the right one
2017-03-23 14:34:53 +01:00
if ( ! Query ) {
d - > CamSlot ( ) - > Assign ( NULL ) ;
s - > Assign ( d ) ;
}
2017-03-18 16:33:59 +01:00
}
else {
// device d already has a proper CAM slot, so nothing to do here
}
}
}
}
else {
// device d has no CAM slot, ...
if ( s - > MtdActive ( ) ) {
// ... so we assign s with MTD support
2017-03-23 14:34:53 +01:00
if ( ! Query ) {
s = s - > MtdSpawn ( ) ;
s - > Assign ( d ) ;
}
2017-03-18 16:33:59 +01:00
}
else {
// CAM slot s has no MTD support ...
if ( s - > Device ( ) ) {
// ... but it is assigned to a different device, so we reassign it to d
if ( Priority > s - > Priority ( ) ) {
2017-03-23 14:34:53 +01:00
if ( ! Query ) {
s - > Device ( ) - > DetachAllReceivers ( ) ;
s - > Assign ( d ) ;
}
2017-03-18 16:33:59 +01:00
}
else {
d = NULL ;
s = NULL ;
}
}
else {
// ... and is not assigned to any device, so we just assign it to d
2017-03-23 14:34:53 +01:00
if ( ! Query )
s - > Assign ( d ) ;
2017-03-18 16:33:59 +01:00
}
}
2007-01-07 14:46:14 +01:00
}
}
else if ( d - > CamSlot ( ) & & ! d - > CamSlot ( ) - > IsDecrypting ( ) )
d - > CamSlot ( ) - > Assign ( NULL ) ;
}
2002-06-16 12:57:31 +02:00
return d ;
}
2012-03-06 12:32:38 +01:00
cDevice * cDevice : : GetDeviceForTransponder ( const cChannel * Channel , int Priority )
{
cDevice * Device = NULL ;
for ( int i = 0 ; i < cDevice : : NumDevices ( ) ; i + + ) {
if ( cDevice * d = cDevice : : GetDevice ( i ) ) {
if ( d - > IsTunedToTransponder ( Channel ) )
return d ; // if any device is tuned to the transponder, we're done
if ( d - > ProvidesTransponder ( Channel ) ) {
if ( d - > MaySwitchTransponder ( Channel ) )
2020-06-25 13:46:16 +02:00
return d ; // this device may switch to the transponder without disturbing any receiver or live view
2020-06-27 10:24:46 +02:00
else if ( ! d - > Occupied ( ) & & ! d - > IsBonded ( ) ) { // MaySwitchTransponder() implicitly calls Occupied()
2012-03-06 12:32:38 +01:00
if ( d - > Priority ( ) < Priority & & ( ! Device | | d - > Priority ( ) < Device - > Priority ( ) ) )
Device = d ; // use this one only if no other with less impact can be found
}
}
}
}
return Device ;
}
2022-01-24 16:53:45 +01:00
void cDevice : : ReleaseCamSlot ( void )
{
if ( camSlot & & ! camSlot - > IsDecrypting ( ) & & ! camSlot - > IsActivating ( ) )
camSlot - > Assign ( NULL ) ;
}
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 )
{
2014-01-14 12:21:17 +01:00
LOCK_THREAD ;
2007-01-07 14:46:14 +01:00
camSlot = CamSlot ;
}
2002-06-16 12:57:31 +02:00
void cDevice : : Shutdown ( void )
{
2012-01-18 10:51:01 +01:00
deviceHooks . Clear ( ) ;
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 ;
2009-12-06 12:57:45 +01:00
default : esyslog ( " ERROR: invalid value for VideoDisplayFormat '%d' " , VideoDisplayFormat ) ;
2005-02-20 12:01:05 +01:00
}
}
}
}
2002-08-04 14:57:29 +02:00
void cDevice : : SetVideoFormat ( bool VideoFormat16_9 )
2002-06-16 12:57:31 +02:00
{
}
2009-06-06 11:20:52 +02:00
void cDevice : : GetVideoSize ( int & Width , int & Height , double & VideoAspect )
2009-05-03 14:15:21 +02:00
{
2009-05-09 10:11:16 +02:00
Width = 0 ;
Height = 0 ;
2009-06-06 11:20:52 +02:00
VideoAspect = 1.0 ;
2009-05-03 14:15:21 +02:00
}
2009-06-06 11:20:52 +02:00
void cDevice : : GetOsdSize ( int & Width , int & Height , double & PixelAspect )
2009-05-09 10:11:16 +02:00
{
Width = 720 ;
Height = 480 ;
2009-06-06 11:20:52 +02:00
PixelAspect = 1.0 ;
2009-05-09 10:11:16 +02:00
}
2019-05-28 15:54:22 +02:00
//#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", DeviceNumber() + 1, s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog("%s", 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
{
2017-02-21 14:17:07 +01:00
cMutexLock MutexLock ( & mutexPids ) ;
2002-09-04 17:26:02 +02:00
for ( int i = 0 ; i < MAXPIDHANDLES ; i + + ) {
if ( pidHandles [ i ] . pid = = Pid )
return true ;
}
return false ;
}
2009-12-25 15:26:16 +01:00
bool cDevice : : AddPid ( int Pid , ePidType PidType , int StreamType )
2002-06-16 12:57:31 +02:00
{
2017-02-21 14:17:07 +01:00
cMutexLock MutexLock ( & mutexPids ) ;
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 ) ) {
2019-05-28 15:54:22 +02:00
esyslog ( " ERROR: can't set PID %d on device %d " , Pid , DeviceNumber ( ) + 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 {
2019-05-28 15:54:22 +02:00
esyslog ( " ERROR: no free slot for PID %d on device %d " , Pid , DeviceNumber ( ) + 1 ) ;
2004-10-17 09:42:36 +02:00
return false ;
}
2002-06-16 12:57:31 +02:00
if ( n > = 0 ) {
pidHandles [ n ] . pid = Pid ;
2009-12-25 15:26:16 +01:00
pidHandles [ n ] . streamType = StreamType ;
2002-06-16 12:57:31 +02:00
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 ) ) {
2019-05-28 15:54:22 +02:00
esyslog ( " ERROR: can't set PID %d on device %d " , Pid , DeviceNumber ( ) + 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
{
2017-02-21 14:17:07 +01:00
cMutexLock MutexLock ( & mutexPids ) ;
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
}
2012-01-17 15:37:52 +01:00
void cDevice : : DelLivePids ( void )
{
2017-02-21 14:17:07 +01:00
cMutexLock MutexLock ( & mutexPids ) ;
2012-01-17 15:37:52 +01:00
for ( int i = ptAudio ; i < ptOther ; i + + ) {
if ( pidHandles [ i ] . pid )
DelPid ( pidHandles [ i ] . pid , ePidType ( i ) ) ;
}
}
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 ) ) ;
2014-03-10 14:50:58 +01:00
AttachFilter ( nitFilter = new cNitFilter ( sdtFilter ) ) ;
2003-12-22 13:29:24 +01:00
}
}
2008-02-09 16:28:15 +01:00
void cDevice : : StopSectionHandler ( void )
{
if ( sectionHandler ) {
delete nitFilter ;
delete sdtFilter ;
delete patFilter ;
delete eitFilter ;
delete sectionHandler ;
nitFilter = NULL ;
sdtFilter = NULL ;
patFilter = NULL ;
eitFilter = NULL ;
sectionHandler = NULL ;
}
}
2003-12-22 13:29:24 +01:00
int cDevice : : OpenFilter ( u_short Pid , u_char Tid , u_char Mask )
{
return - 1 ;
}
2012-08-26 13:09:01 +02:00
int cDevice : : ReadFilter ( int Handle , void * Buffer , size_t Length )
{
return safe_read ( Handle , Buffer , Length ) ;
}
2007-10-14 13:11:23 +02:00
void cDevice : : CloseFilter ( int Handle )
{
close ( Handle ) ;
}
2003-12-22 13:29:24 +01:00
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 ;
}
2010-02-06 14:23:03 +01:00
bool cDevice : : DeviceHooksProvidesTransponder ( const cChannel * Channel ) const
{
cDeviceHook * Hook = deviceHooks . First ( ) ;
while ( Hook ) {
if ( ! Hook - > DeviceProvidesTransponder ( this , Channel ) )
return false ;
Hook = deviceHooks . Next ( Hook ) ;
}
return true ;
}
2020-06-10 14:52:43 +02:00
bool cDevice : : DeviceHooksProvidesEIT ( void ) const
{
cDeviceHook * Hook = deviceHooks . First ( ) ;
while ( Hook ) {
if ( ! Hook - > DeviceProvidesEIT ( this ) )
return false ;
Hook = deviceHooks . Next ( Hook ) ;
}
return true ;
}
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 ;
}
2011-08-26 13:03:14 +02:00
bool cDevice : : ProvidesEIT ( void ) const
{
return false ;
}
2008-04-12 13:39:12 +02:00
int cDevice : : NumProvidedSystems ( void ) const
{
return 0 ;
}
2013-08-21 11:02:52 +02:00
const cPositioner * cDevice : : Positioner ( void ) const
{
return NULL ;
}
2017-05-09 11:53:41 +02:00
bool cDevice : : SignalStats ( int & Valid , double * Strength , double * Cnr , double * BerPre , double * BerPost , double * Per , int * Status ) const
2017-04-17 15:02:44 +02:00
{
return false ;
}
2011-06-02 13:28:42 +02:00
int cDevice : : SignalStrength ( void ) const
{
return - 1 ;
}
int cDevice : : SignalQuality ( void ) const
{
return - 1 ;
}
2010-02-06 14:43:42 +01:00
const cChannel * cDevice : : GetCurrentlyTunedTransponder ( void ) const
{
return NULL ;
}
2011-12-04 12:45:26 +01:00
bool cDevice : : IsTunedToTransponder ( const cChannel * Channel ) const
2006-04-09 09:12:47 +02:00
{
return false ;
}
2011-12-04 12:45:26 +01:00
bool cDevice : : MaySwitchTransponder ( const cChannel * Channel ) const
2005-11-05 15:48:05 +01:00
{
2012-03-02 10:19:00 +01:00
return time ( NULL ) > occupiedTimeout & & ! Receiving ( ) & & ! ( pidHandles [ ptAudio ] . pid | | pidHandles [ ptVideo ] . pid | | pidHandles [ ptDolby ] . pid ) ;
2005-11-05 15:48:05 +01:00
}
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 ) {
2017-05-01 13:06:32 +02:00
isyslog ( " switching to channel %d %s (%s) " , Channel - > Number ( ) , * Channel - > GetChannelID ( ) . ToString ( ) , Channel - > Name ( ) ) ;
2007-01-07 14:46:14 +01:00
cControl : : Shutdown ( ) ; // prevents old channel from being shown too long if GetDevice() takes longer
2020-09-16 13:48:33 +02:00
// and, if decrypted, this removes the now superfluous PIDs from the CAM, too
2007-01-07 14:46:14 +01:00
}
2002-09-04 17:26:02 +02:00
for ( int i = 3 ; i - - ; ) {
switch ( SetChannel ( Channel , LiveView ) ) {
case scrOk : return true ;
2020-07-13 08:16:41 +02:00
case scrNotAvailable : Skins . QueueMessage ( mtInfo , tr ( " Channel not available! " ) ) ;
2002-10-06 11:34:02 +02:00
return false ;
2020-07-13 08:16:41 +02:00
case scrNoTransfer : Skins . QueueMessage ( mtError , tr ( " Can't start Transfer Mode! " ) ) ;
2002-09-04 17:26:02 +02:00
return false ;
case scrFailed : break ; // loop will retry
2009-12-06 12:57:45 +01:00
default : esyslog ( " ERROR: invalid return value from SetChannel " ) ;
2002-09-04 17:26:02 +02:00
}
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
2020-09-16 13:48:33 +02:00
// and, if decrypted, this removes the now superfluous PIDs from the CAM, too
2002-09-08 11:46:53 +02:00
int n = CurrentChannel ( ) + Direction ;
int first = n ;
2015-09-01 11:14:27 +02:00
LOCK_CHANNELS_READ ;
const cChannel * Channel ;
while ( ( Channel = Channels - > GetByNumber ( n , Direction ) ) ! = NULL ) {
2002-10-06 11:34:02 +02:00
// try only channels which are currently available
2015-09-01 11:14:27 +02:00
if ( GetDevice ( Channel , LIVEPRIORITY , true , true ) )
2002-10-06 11:34:02 +02:00
break ;
2015-09-01 11:14:27 +02:00
n = Channel - > Number ( ) + Direction ;
2002-10-06 11:34:02 +02:00
}
2015-09-01 11:14:27 +02:00
if ( Channel ) {
2002-10-06 11:34:02 +02:00
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 ) ) ;
2015-09-01 11:14:27 +02:00
if ( PrimaryDevice ( ) - > SwitchChannel ( Channel , true ) )
2002-10-06 11:34:02 +02:00
result = true ;
}
2004-05-16 10:35:36 +02:00
else if ( n ! = first )
2019-05-06 13:14:23 +02:00
Skins . QueueMessage ( 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
{
2017-05-30 11:06:55 +02:00
cMutexLock MutexLock ( & mutexChannel ) ; // to avoid a race between SVDRP CHAN and HasProgramme()
2012-03-07 14:39:38 +01:00
cStatus : : MsgChannelSwitch ( this , 0 , LiveView ) ;
2012-03-03 11:51:32 +01:00
2007-10-12 14:52:30 +02:00
if ( LiveView ) {
2021-06-08 14:57:26 +02:00
if ( IsPrimaryDevice ( ) & & ! Replaying ( ) & & ! Transferring ( ) ) { // this is only for FF DVB cards!
LOCK_CHANNELS_READ ;
if ( const cChannel * ch = Channels - > GetByNumber ( currentChannel ) ) {
if ( patFilter )
patFilter - > Release ( ch - > Sid ( ) ) ;
}
}
2002-09-04 17:26:02 +02:00
StopReplay ( ) ;
2007-10-12 14:52:30 +02:00
DELETENULL ( liveSubtitle ) ;
DELETENULL ( dvbSubtitleConverter ) ;
}
2002-08-04 14:57:29 +02:00
2012-02-25 14:44:43 +01:00
cDevice * Device = ( LiveView & & IsPrimaryDevice ( ) ) ? GetDevice ( Channel , LIVEPRIORITY , true ) : this ;
2006-01-06 13:55:57 +01:00
2015-01-30 13:38:44 +01:00
bool NeedsTransferMode = LiveView & & Device ! = PrimaryDevice ( ) ;
2014-01-20 12:14:30 +01:00
// If the CAM slot wants the TS data, we need to switch to Transfer Mode:
if ( ! NeedsTransferMode & & LiveView & & IsPrimaryDevice ( ) & & CamSlot ( ) & & CamSlot ( ) - > WantsTsData ( ) )
NeedsTransferMode = true ;
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 ) {
2015-01-30 13:38:44 +01:00
if ( Device & & PrimaryDevice ( ) - > CanReplay ( ) ) {
2007-01-07 14:46:14 +01:00
if ( Device - > SetChannel ( Channel , false ) = = scrOk ) // calling SetChannel() directly, not SwitchChannel()!
2010-01-30 11:10:25 +01:00
cControl : : Launch ( new cTransferControl ( Device , Channel ) ) ;
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 {
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 ;
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 ( ) ) {
2021-06-08 14:57:26 +02:00
if ( patFilter ) // this is only for FF DVB cards!
patFilter - > Request ( Channel - > Sid ( ) ) ;
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 ) ) ;
}
2007-10-12 14:52:30 +02:00
for ( int i = 0 ; i < MAXSPIDS ; i + + )
SetAvailableTrack ( ttSubtitle , i , Channel - > Spid ( i ) , Channel - > Slang ( i ) ) ;
2005-02-27 13:40:33 +01:00
if ( ! NeedsTransferMode )
EnsureAudioTrack ( true ) ;
2007-10-12 14:52:30 +02:00
EnsureSubtitleTrack ( ) ;
2005-02-27 13:40:33 +01:00
}
2012-06-09 14:40:26 +02:00
cStatus : : MsgChannelSwitch ( this , Channel - > Number ( ) , LiveView ) ; // only report status if channel switch successful
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 ( ) ) {
2015-09-01 11:14:27 +02:00
LOCK_CHANNELS_READ ;
if ( const cChannel * Channel = Channels - > GetByNumber ( CurrentChannel ( ) ) )
2006-03-26 09:46:58 +02:00
SetChannelDevice ( Channel , false ) ; // this implicitly starts Transfer Mode
}
}
2011-10-16 14:02:34 +02:00
int cDevice : : Occupied ( void ) const
{
int Seconds = occupiedTimeout - time ( NULL ) ;
return Seconds > 0 ? Seconds : 0 ;
}
void cDevice : : SetOccupied ( int Seconds )
{
if ( Seconds > = 0 )
occupiedTimeout = time ( NULL ) + min ( Seconds , MAXOCCUPIEDTIMEOUT ) ;
}
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
2013-02-16 13:06:16 +01:00
bool cDevice : : HasLock ( int TimeoutMs ) const
2004-01-04 12:30:00 +01:00
{
return true ;
}
2013-02-16 13:06:16 +01:00
bool cDevice : : HasProgramme ( void ) const
2003-05-03 13:42:37 +02:00
{
2017-05-30 11:06:55 +02:00
cMutexLock MutexLock ( & mutexChannel ) ; // to avoid a race between SVDRP CHAN and HasProgramme()
2003-05-03 13:42:37 +02:00
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
{
}
2008-02-16 13:59:09 +01:00
void cDevice : : SetSubtitleTrackDevice ( eTrackType Type )
{
}
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 ;
2015-01-12 14:56:42 +01:00
double VolumeDelta = double ( MAXVOLUME ) / Setup . VolumeSteps ;
double VolumeLinearize = ( Setup . VolumeLinearize > = 0 ) ? ( Setup . VolumeLinearize / 10.0 + 1.0 ) : ( 1.0 / ( ( - Setup . VolumeLinearize / 10.0 ) + 1.0 ) ) ;
volume = constrain ( int ( floor ( ( Absolute ? Volume : volume + Volume ) / VolumeDelta + 0.5 ) * VolumeDelta ) , 0 , MAXVOLUME ) ;
SetVolumeDevice ( MAXVOLUME - int ( pow ( 1.0 - pow ( double ( volume ) / MAXVOLUME , VolumeLinearize ) , 1.0 / VolumeLinearize ) * MAXVOLUME ) ) ;
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
{
2013-02-01 12:06:50 +01:00
if ( keepTracks )
return ;
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 ) ) ;
2007-11-03 14:32:03 +01:00
pre_1_3_19_PrivateStream = 0 ;
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 ;
2007-10-12 14:52:30 +02:00
currentSubtitleTrack = 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 ) | |
2007-10-12 14:52:30 +02:00
Type = = ttDolby & & IS_DOLBY_TRACK ( t ) | |
Type = = ttSubtitle & & IS_SUBTITLE_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
2007-10-12 14:52:30 +02:00
if ( Type = = ttAudio | | Type = = ttDolby ) {
int numAudioTracks = NumAudioTracks ( ) ;
if ( ! availableTracks [ currentAudioTrack ] . id & & numAudioTracks & & currentAudioTrackMissingCount + + > numAudioTracks * 10 )
EnsureAudioTrack ( ) ;
else if ( t = = currentAudioTrack )
currentAudioTrackMissingCount = 0 ;
}
else if ( Type = = ttSubtitle & & autoSelectPreferredSubtitleLanguage )
EnsureSubtitleTrack ( ) ;
2005-02-27 10:36:19 +01:00
}
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 ;
}
2007-10-12 14:52:30 +02:00
int cDevice : : NumTracks ( eTrackType FirstTrack , eTrackType LastTrack ) const
2002-10-12 14:29:46 +02:00
{
2004-12-17 14:55:49 +01:00
int n = 0 ;
2007-10-12 14:52:30 +02:00
for ( int i = FirstTrack ; i < = LastTrack ; i + + ) {
2004-12-17 14:55:49 +01:00
if ( availableTracks [ i ] . id )
n + + ;
}
return n ;
2002-10-12 14:29:46 +02:00
}
2007-10-12 14:52:30 +02:00
int cDevice : : NumAudioTracks ( void ) const
{
return NumTracks ( ttAudioFirst , ttDolbyLast ) ;
}
int cDevice : : NumSubtitleTracks ( void ) const
{
return NumTracks ( ttSubtitleFirst , ttSubtitleLast ) ;
}
2004-12-17 14:55:49 +01:00
bool cDevice : : SetCurrentAudioTrack ( eTrackType Type )
2002-10-12 14:29:46 +02:00
{
2007-08-26 11:13:10 +02: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
}
2007-10-12 14:52:30 +02:00
bool cDevice : : SetCurrentSubtitleTrack ( eTrackType Type , bool Manual )
{
if ( Type = = ttNone | | IS_SUBTITLE_TRACK ( Type ) ) {
currentSubtitleTrack = Type ;
autoSelectPreferredSubtitleLanguage = ! Manual ;
if ( dvbSubtitleConverter )
dvbSubtitleConverter - > Reset ( ) ;
if ( Type = = ttNone & & dvbSubtitleConverter ) {
cMutexLock MutexLock ( & mutexCurrentSubtitleTrack ) ;
DELETENULL ( dvbSubtitleConverter ) ;
}
DELETENULL ( liveSubtitle ) ;
2008-02-16 13:59:09 +01:00
if ( player )
player - > SetSubtitleTrack ( currentSubtitleTrack , GetTrack ( currentSubtitleTrack ) ) ;
else
SetSubtitleTrackDevice ( currentSubtitleTrack ) ;
2007-10-12 14:52:30 +02:00
if ( currentSubtitleTrack ! = ttNone & & ! Replaying ( ) & & ! Transferring ( ) ) {
const tTrackId * TrackId = GetTrack ( currentSubtitleTrack ) ;
if ( TrackId & & TrackId - > id ) {
liveSubtitle = new cLiveSubtitle ( TrackId - > id ) ;
AttachReceiver ( liveSubtitle ) ;
}
}
return true ;
}
return false ;
}
2005-02-06 11:33:13 +01:00
void cDevice : : EnsureAudioTrack ( bool Force )
{
2013-02-01 12:06:50 +01:00
if ( keepTracks )
return ;
2005-02-06 11:33:13 +01:00
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
}
}
}
2007-10-12 14:52:30 +02:00
void cDevice : : EnsureSubtitleTrack ( void )
{
2013-02-01 12:06:50 +01:00
if ( keepTracks )
return ;
2007-10-12 14:52:30 +02:00
if ( Setup . DisplaySubtitles ) {
2008-03-07 15:44:52 +01:00
eTrackType PreferredTrack = ttNone ;
int LanguagePreference = INT_MAX ; // higher than the maximum possible value
2007-10-12 14:52:30 +02:00
for ( int i = ttSubtitleFirst ; i < = ttSubtitleLast ; i + + ) {
const tTrackId * TrackId = GetTrack ( eTrackType ( i ) ) ;
2012-02-28 09:28:54 +01:00
if ( TrackId & & TrackId - > id & & ( I18nIsPreferredLanguage ( Setup . SubtitleLanguages , TrackId - > language , LanguagePreference ) | |
( i = = ttSubtitleFirst + 8 & & ! * TrackId - > language & & LanguagePreference = = INT_MAX ) ) ) // compatibility mode for old subtitles plugin
2007-10-12 14:52:30 +02:00
PreferredTrack = eTrackType ( i ) ;
}
// Make sure we're set to an available subtitle track:
const tTrackId * Track = GetTrack ( GetCurrentSubtitleTrack ( ) ) ;
if ( ! Track | | ! Track - > id | | PreferredTrack ! = GetCurrentSubtitleTrack ( ) )
SetCurrentSubtitleTrack ( PreferredTrack ) ;
}
else
SetCurrentSubtitleTrack ( ttNone ) ;
}
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 ;
}
2013-12-25 13:36:51 +01:00
void cDevice : : TrickSpeed ( int Speed , bool Forward )
2002-06-16 12:57:31 +02:00
{
}
void cDevice : : Clear ( void )
{
2002-11-03 11:53:58 +01:00
Audios . ClearAudio ( ) ;
2007-10-12 14:52:30 +02:00
if ( dvbSubtitleConverter )
dvbSubtitleConverter - > Reset ( ) ;
2002-06-16 12:57:31 +02:00
}
void cDevice : : Play ( void )
{
2003-03-30 12:42:23 +02:00
Audios . MuteAudio ( mute ) ;
2010-02-07 12:08:13 +01:00
if ( dvbSubtitleConverter )
dvbSubtitleConverter - > Freeze ( false ) ;
2002-06-16 12:57:31 +02:00
}
void cDevice : : Freeze ( void )
{
2003-03-30 12:42:23 +02:00
Audios . MuteAudio ( true ) ;
2010-02-07 12:08:13 +01:00
if ( dvbSubtitleConverter )
dvbSubtitleConverter - > Freeze ( 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 )
{
2009-01-06 14:41:11 +01:00
if ( Data [ 0 ] = = 0x47 ) {
// TS data
cTsToPes TsToPes ;
uchar * buf = NULL ;
int Size = 0 ;
while ( Length > = TS_SIZE ) {
int Pid = TsPid ( Data ) ;
2012-11-13 09:11:43 +01:00
if ( Pid = = PATPID )
2009-01-23 16:43:23 +01:00
patPmtParser . ParsePat ( Data , TS_SIZE ) ;
2012-11-19 10:32:31 +01:00
else if ( patPmtParser . IsPmtPid ( Pid ) )
2009-01-23 16:43:23 +01:00
patPmtParser . ParsePmt ( Data , TS_SIZE ) ;
2009-01-06 14:41:11 +01:00
else if ( Pid = = patPmtParser . Vpid ( ) ) {
if ( TsPayloadStart ( Data ) ) {
int l ;
while ( const uchar * p = TsToPes . GetPes ( l ) ) {
int Offset = Size ;
2011-02-25 15:25:42 +01:00
int NewSize = Size + l ;
if ( uchar * NewBuffer = ( uchar * ) realloc ( buf , NewSize ) ) {
Size = NewSize ;
buf = NewBuffer ;
memcpy ( buf + Offset , p , l ) ;
}
else {
LOG_ERROR_STR ( " out of memory " ) ;
free ( buf ) ;
2009-01-06 14:41:11 +01:00
return ;
2011-02-25 15:25:42 +01:00
}
2009-01-06 14:41:11 +01:00
}
TsToPes . Reset ( ) ;
}
TsToPes . PutTs ( Data , TS_SIZE ) ;
}
Length - = TS_SIZE ;
Data + = TS_SIZE ;
}
int l ;
while ( const uchar * p = TsToPes . GetPes ( l ) ) {
int Offset = Size ;
2011-02-25 15:25:42 +01:00
int NewSize = Size + l ;
if ( uchar * NewBuffer = ( uchar * ) realloc ( buf , NewSize ) ) {
Size = NewSize ;
buf = NewBuffer ;
memcpy ( buf + Offset , p , l ) ;
}
else {
esyslog ( " ERROR: out of memory " ) ;
free ( buf ) ;
2009-01-06 14:41:11 +01:00
return ;
2011-02-25 15:25:42 +01:00
}
2009-01-06 14:41:11 +01:00
}
2012-04-26 10:28:39 +02:00
if ( buf ) {
StillPicture ( buf , Size ) ;
free ( buf ) ;
}
2009-01-06 14:41:11 +01:00
}
2002-06-16 12:57:31 +02:00
}
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
{
2012-08-25 12:03:55 +02:00
return cTransferControl : : ReceiverDevice ( ) ! = NULL ;
2006-02-04 14:58:24 +01:00
}
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 ) ;
2007-11-17 15:58:55 +01:00
DELETENULL ( liveSubtitle ) ;
DELETENULL ( dvbSubtitleConverter ) ;
2009-04-18 09:41:00 +02:00
patPmtParser . 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 ;
2007-10-12 14:52:30 +02:00
cMutexLock MutexLock ( & mutexCurrentSubtitleTrack ) ;
delete dvbSubtitleConverter ;
dvbSubtitleConverter = NULL ;
2002-08-15 11:16:34 +02:00
SetPlayMode ( pmNone ) ;
2005-02-20 13:39:49 +01:00
SetVideoDisplayFormat ( eVideoDisplayFormat ( Setup . VideoDisplayFormat ) ) ;
2009-01-16 15:20:29 +01:00
PlayTs ( NULL , 0 ) ;
2009-04-18 09:41:00 +02:00
patPmtParser . Reset ( ) ;
2003-03-30 12:42:23 +02:00
Audios . ClearAudio ( ) ;
2009-01-25 11:39:43 +01:00
isPlayingVideo = false ;
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 ;
}
2007-10-12 14:52:30 +02:00
int cDevice : : PlaySubtitle ( const uchar * Data , int Length )
{
if ( ! dvbSubtitleConverter )
dvbSubtitleConverter = new cDvbSubtitleConverter ;
2008-08-15 14:49:34 +02:00
return dvbSubtitleConverter - > ConvertFragments ( Data , Length ) ;
2007-10-12 14:52:30 +02:00
}
2004-12-17 14:55:49 +01:00
int cDevice : : PlayPesPacket ( const uchar * Data , int Length , bool VideoOnly )
2002-06-16 12:57:31 +02:00
{
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
2009-01-25 11:39:43 +01:00
isPlayingVideo = true ;
2004-12-17 14:55:49 +01:00
w = PlayVideo ( Start , d ) ;
break ;
case 0xC0 . . . 0xDF : // audio
SetAvailableTrack ( ttAudio , c - 0xC0 , c ) ;
2008-02-09 15:12:55 +01:00
if ( ( ! VideoOnly | | HasIBPTrickSpeed ( ) ) & & 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 ;
2007-10-12 14:52:30 +02:00
// Compatibility mode for old subtitles plugin:
2007-10-17 18:34:17 +02:00
if ( ( Data [ 7 ] & 0x01 ) & & ( Data [ PayloadOffset - 3 ] & 0x81 ) = = 0x01 & & Data [ PayloadOffset - 2 ] = = 0x81 )
2007-10-12 14:52:30 +02:00
PayloadOffset - - ;
2005-01-23 14:10:15 +01:00
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:
2008-04-12 14:14:07 +02:00
pre_1_3_19_PrivateStreamDetected :
2007-11-03 14:32:03 +01:00
if ( pre_1_3_19_PrivateStream > MIN_PRE_1_3_19_PRIVATESTREAM ) {
2005-01-23 14:10:15 +01:00
SubStreamId = c ;
SubStreamType = 0x80 ;
SubStreamIndex = 0 ;
2004-12-17 14:55:49 +01:00
}
2007-11-03 14:32:03 +01:00
else if ( pre_1_3_19_PrivateStream )
pre_1_3_19_PrivateStream - - ; // every known PS1 packet counts down towards 0 to recover from glitches...
2005-01-23 14:10:15 +01:00
switch ( SubStreamType ) {
case 0x20 : // SPU
2005-01-30 13:38:06 +01:00
case 0x30 : // SPU
2007-10-12 14:52:30 +02:00
SetAvailableTrack ( ttSubtitle , SubStreamIndex , SubStreamId ) ;
2008-02-09 15:12:55 +01:00
if ( ( ! VideoOnly | | HasIBPTrickSpeed ( ) ) & & currentSubtitleTrack ! = ttNone & & SubStreamId = = availableTracks [ currentSubtitleTrack ] . id )
2007-10-12 14:52:30 +02:00
w = PlaySubtitle ( Start , d ) ;
2005-01-23 14:10:15 +01:00
break ;
case 0x80 : // AC3 & DTS
if ( Setup . UseDolbyDigital ) {
SetAvailableTrack ( ttDolby , SubStreamIndex , SubStreamId ) ;
2008-02-09 15:12:55 +01:00
if ( ( ! VideoOnly | | HasIBPTrickSpeed ( ) ) & & 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 ) ;
2008-02-09 15:12:55 +01:00
if ( ( ! VideoOnly | | HasIBPTrickSpeed ( ) ) & & 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:
2007-11-03 14:32:03 +01:00
if ( pre_1_3_19_PrivateStream < = MIN_PRE_1_3_19_PRIVATESTREAM ) {
dsyslog ( " unknown PS1 packet, substream id = %02X (counter is at %d) " , SubStreamId , pre_1_3_19_PrivateStream ) ;
pre_1_3_19_PrivateStream + = 2 ; // ...and every unknown PS1 packet counts up (the very first one counts twice, but that's ok)
if ( pre_1_3_19_PrivateStream > MIN_PRE_1_3_19_PRIVATESTREAM ) {
dsyslog ( " switching to pre 1.3.19 Dolby Digital compatibility mode - substream id = %02X " , SubStreamId ) ;
ClrAvailableTracks ( ) ;
2008-04-12 14:14:07 +02:00
pre_1_3_19_PrivateStream = MIN_PRE_1_3_19_PRIVATESTREAM + 1 ;
goto pre_1_3_19_PrivateStreamDetected ;
2007-11-03 14:32:03 +01:00
}
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 ) {
2007-10-12 14:52:30 +02:00
if ( dvbSubtitleConverter )
dvbSubtitleConverter - > Reset ( ) ;
2004-12-17 14:55:49 +01:00
return 0 ;
}
int i = 0 ;
while ( i < = Length - 6 ) {
if ( Data [ i ] = = 0x00 & & Data [ i + 1 ] = = 0x00 & & Data [ i + 2 ] = = 0x01 ) {
2008-08-15 14:49:34 +02:00
int l = PesLength ( Data + i ) ;
2004-12-17 14:55:49 +01:00
if ( i + l > Length ) {
2008-08-15 14:49:34 +02:00
esyslog ( " ERROR: incomplete PES packet! " ) ;
2004-12-17 14:55:49 +01:00
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 )
2008-08-15 14:49:34 +02:00
esyslog ( " ERROR: leftover PES data! " ) ;
return Length ;
}
int cDevice : : PlayTsVideo ( const uchar * Data , int Length )
{
// Video PES has no explicit length, so we can only determine the end of
// a PES packet when the next TS packet that starts a payload comes in:
if ( TsPayloadStart ( Data ) ) {
2008-12-13 14:43:22 +01:00
int l ;
while ( const uchar * p = tsToPesVideo . GetPes ( l ) ) {
int w = PlayVideo ( p , l ) ;
2009-08-16 10:54:36 +02:00
if ( w < = 0 ) {
2009-06-21 13:34:40 +02:00
tsToPesVideo . SetRepeatLast ( ) ;
2008-12-13 14:43:22 +01:00
return w ;
2009-08-16 10:54:36 +02:00
}
2008-12-13 14:43:22 +01:00
}
tsToPesVideo . Reset ( ) ;
2008-08-15 14:49:34 +02:00
}
tsToPesVideo . PutTs ( Data , Length ) ;
return Length ;
}
int cDevice : : PlayTsAudio ( const uchar * Data , int Length )
{
2009-01-24 11:20:24 +01:00
// Audio PES always has an explicit length and consists of single packets:
int l ;
if ( const uchar * p = tsToPesAudio . GetPes ( l ) ) {
2009-11-22 13:25:16 +01:00
int w = PlayAudio ( p , l , p [ 3 ] ) ;
2009-08-16 10:54:36 +02:00
if ( w < = 0 ) {
2009-06-21 13:34:40 +02:00
tsToPesAudio . SetRepeatLast ( ) ;
2009-01-24 11:20:24 +01:00
return w ;
2009-08-16 10:54:36 +02:00
}
2009-01-24 11:20:24 +01:00
tsToPesAudio . Reset ( ) ;
}
tsToPesAudio . PutTs ( Data , Length ) ;
2004-12-17 14:55:49 +01:00
return Length ;
2005-02-27 10:36:19 +01:00
}
2004-12-17 14:55:49 +01:00
2008-08-15 14:49:34 +02:00
int cDevice : : PlayTsSubtitle ( const uchar * Data , int Length )
{
if ( ! dvbSubtitleConverter )
dvbSubtitleConverter = new cDvbSubtitleConverter ;
tsToPesSubtitle . PutTs ( Data , Length ) ;
2009-01-30 16:07:32 +01:00
int l ;
if ( const uchar * p = tsToPesSubtitle . GetPes ( l ) ) {
dvbSubtitleConverter - > Convert ( p , l ) ;
2008-08-15 14:49:34 +02:00
tsToPesSubtitle . Reset ( ) ;
}
return Length ;
}
int cDevice : : PlayTs ( const uchar * Data , int Length , bool VideoOnly )
{
2009-04-05 12:29:27 +02:00
int Played = 0 ;
2013-03-07 13:27:05 +01:00
if ( ! Data ) {
2009-01-06 14:41:11 +01:00
tsToPesVideo . Reset ( ) ;
tsToPesAudio . Reset ( ) ;
tsToPesSubtitle . Reset ( ) ;
}
2009-04-13 11:08:05 +02:00
else if ( Length < TS_SIZE ) {
esyslog ( " ERROR: skipped %d bytes of TS fragment " , Length ) ;
return Length ;
}
2009-04-05 12:29:27 +02:00
else {
while ( Length > = TS_SIZE ) {
2017-03-26 13:07:01 +02:00
if ( int Skipped = TS_SYNC ( Data , Length ) )
2009-04-13 11:08:05 +02:00
return Played + Skipped ;
2010-01-30 11:10:25 +01:00
int Pid = TsPid ( Data ) ;
2009-04-05 12:29:27 +02:00
if ( TsHasPayload ( Data ) ) { // silently ignore TS packets w/o payload
int PayloadOffset = TsPayloadOffset ( Data ) ;
if ( PayloadOffset < TS_SIZE ) {
2012-11-13 09:11:43 +01:00
if ( Pid = = PATPID )
2009-04-05 12:29:27 +02:00
patPmtParser . ParsePat ( Data , TS_SIZE ) ;
2012-11-19 10:32:31 +01:00
else if ( patPmtParser . IsPmtPid ( Pid ) )
2009-04-05 12:29:27 +02:00
patPmtParser . ParsePmt ( Data , TS_SIZE ) ;
else if ( Pid = = patPmtParser . Vpid ( ) ) {
isPlayingVideo = true ;
int w = PlayTsVideo ( Data , TS_SIZE ) ;
if ( w < 0 )
return Played ? Played : w ;
if ( w = = 0 )
break ;
}
else if ( Pid = = availableTracks [ currentAudioTrack ] . id ) {
if ( ! VideoOnly | | HasIBPTrickSpeed ( ) ) {
int w = PlayTsAudio ( Data , TS_SIZE ) ;
if ( w < 0 )
return Played ? Played : w ;
if ( w = = 0 )
break ;
Audios . PlayTsAudio ( Data , TS_SIZE ) ;
}
}
else if ( Pid = = availableTracks [ currentSubtitleTrack ] . id ) {
if ( ! VideoOnly | | HasIBPTrickSpeed ( ) )
PlayTsSubtitle ( Data , TS_SIZE ) ;
}
}
}
2010-01-30 11:10:25 +01:00
else if ( Pid = = patPmtParser . Ppid ( ) ) {
int w = PlayTsVideo ( Data , TS_SIZE ) ;
if ( w < 0 )
return Played ? Played : w ;
if ( w = = 0 )
break ;
}
2009-04-05 12:29:27 +02:00
Played + = TS_SIZE ;
Length - = TS_SIZE ;
Data + = TS_SIZE ;
}
}
return Played ;
2008-08-15 14:49:34 +02:00
}
2002-09-29 13:40:45 +02:00
int cDevice : : Priority ( void ) const
2002-06-16 12:57:31 +02:00
{
2012-02-25 14:44:43 +01:00
int priority = IDLEPRIORITY ;
2013-02-16 14:39:30 +01:00
if ( IsPrimaryDevice ( ) & & ! Replaying ( ) & & HasProgramme ( ) )
2012-03-02 10:19:00 +01:00
priority = TRANSFERPRIORITY ; // we use the same value here, no matter whether it's actual Transfer Mode or real live viewing
2011-12-04 12:45:26 +01:00
cMutexLock MutexLock ( & mutexReceiver ) ;
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 ;
}
2012-03-02 10:19:00 +01:00
bool cDevice : : Receiving ( bool Dummy ) const
2002-06-16 12:57:31 +02:00
{
2011-12-04 12:45:26 +01:00
cMutexLock MutexLock ( & mutexReceiver ) ;
2002-06-16 12:57:31 +02:00
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
2012-03-02 10:19:00 +01:00
if ( receiver [ i ] )
2002-06-16 12:57:31 +02:00
return true ;
}
return false ;
}
2007-01-07 14:46:14 +01:00
# define TS_SCRAMBLING_TIMEOUT 3 // seconds to wait until a TS becomes unscrambled
2017-05-18 09:32:04 +02:00
# define TS_SCRAMBLING_TIME_OK 3 // seconds before a Channel/CAM combination is marked as known to decrypt
2017-05-01 09:32:32 +02:00
# define EIT_INJECTION_TIME 10 // seconds for which to inject EIT event
2007-01-07 14:46:14 +01:00
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 ) {
// Distribute the packet to all attached receivers:
2014-01-21 11:12:01 +01:00
Lock ( ) ;
2017-05-18 09:05:46 +02:00
cCamSlot * cs = CamSlot ( ) ;
if ( cs )
cs - > TsPostProcess ( b ) ;
2017-04-02 10:08:49 +02:00
int Pid = TsPid ( b ) ;
bool IsScrambled = TsIsScrambled ( b ) ;
2005-08-13 13:17:24 +02:00
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
2017-12-16 13:13:13 +01:00
cMutexLock MutexLock ( & mutexReceiver ) ;
2017-04-02 10:08:49 +02:00
cReceiver * Receiver = receiver [ i ] ;
if ( Receiver & & Receiver - > WantsPid ( Pid ) ) {
Receiver - > Receive ( b , TS_SIZE ) ;
// Check whether the TS packet is scrambled:
if ( Receiver - > startScrambleDetection ) {
2017-05-18 09:05:46 +02:00
if ( cs ) {
2017-04-02 10:08:49 +02:00
int CamSlotNumber = cs - > MasterSlotNumber ( ) ;
if ( Receiver - > lastScrambledPacket < Receiver - > startScrambleDetection )
Receiver - > lastScrambledPacket = Receiver - > startScrambleDetection ;
time_t Now = time ( NULL ) ;
if ( IsScrambled ) {
Receiver - > lastScrambledPacket = Now ;
if ( Now - Receiver - > startScrambleDetection > Receiver - > scramblingTimeout ) {
if ( ! cs - > IsActivating ( ) | | Receiver - > Priority ( ) > = LIVEPRIORITY ) {
if ( Receiver - > ChannelID ( ) . Valid ( ) ) {
dsyslog ( " CAM %d: won't decrypt channel %s, detaching receiver " , CamSlotNumber , * Receiver - > ChannelID ( ) . ToString ( ) ) ;
ChannelCamRelations . SetChecked ( Receiver - > ChannelID ( ) , CamSlotNumber ) ;
}
Detach ( Receiver ) ;
}
}
}
else if ( Now - Receiver - > lastScrambledPacket > TS_SCRAMBLING_TIME_OK ) {
if ( Receiver - > ChannelID ( ) . Valid ( ) ) {
dsyslog ( " CAM %d: decrypts channel %s " , CamSlotNumber , * Receiver - > ChannelID ( ) . ToString ( ) ) ;
ChannelCamRelations . SetDecrypt ( Receiver - > ChannelID ( ) , CamSlotNumber ) ;
}
Receiver - > startScrambleDetection = 0 ;
}
}
2017-01-09 13:42:41 +01:00
}
2017-05-01 09:32:32 +02:00
// Inject EIT event to avoid the CAMs parental rating prompt:
if ( Receiver - > startEitInjection ) {
time_t Now = time ( NULL ) ;
if ( cCamSlot * cs = CamSlot ( ) ) {
if ( Now ! = Receiver - > lastEitInjection ) { // once per second
cs - > InjectEit ( Receiver - > ChannelID ( ) . Sid ( ) ) ;
Receiver - > lastEitInjection = Now ;
}
}
if ( Now - Receiver - > startEitInjection > EIT_INJECTION_TIME )
Receiver - > startEitInjection = 0 ;
}
2007-01-07 14:46:14 +01:00
}
2005-08-13 13:17:24 +02:00
}
2014-01-21 11:12:01 +01:00
Unlock ( ) ;
2005-08-13 13:17:24 +02:00
}
}
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 ) ) {
2019-05-28 15:54:22 +02:00
esyslog ( " ERROR: device %d has no lock, can't attach receiver! " , DeviceNumber ( ) + 1 ) ;
2005-09-02 13:55:37 +02:00
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 ) ;
Receiver - > device = this ;
receiver [ i ] = Receiver ;
2014-01-01 12:37:22 +01:00
if ( camSlot & & Receiver - > priority > MINPRIORITY ) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
2007-01-07 14:46:14 +01:00
camSlot - > StartDecrypting ( ) ;
2017-05-01 09:32:32 +02:00
if ( camSlot - > WantsTsData ( ) ) {
Receiver - > lastEitInjection = 0 ;
Receiver - > startEitInjection = time ( NULL ) ;
}
2017-01-23 12:01:48 +01:00
if ( CamSlots . NumReadyMasterSlots ( ) > 1 ) { // don't try different CAMs if there is only one
2017-04-02 10:08:49 +02:00
Receiver - > startScrambleDetection = time ( NULL ) ;
Receiver - > scramblingTimeout = TS_SCRAMBLING_TIMEOUT ;
2017-01-23 12:01:48 +01:00
bool KnownToDecrypt = ChannelCamRelations . CamDecrypt ( Receiver - > ChannelID ( ) , camSlot - > MasterSlotNumber ( ) ) ;
2017-01-09 14:27:36 +01:00
if ( KnownToDecrypt )
2021-03-17 10:59:36 +01:00
Receiver - > scramblingTimeout * = 9 ; // give it time to receive ECM/EMM (must be less than MAXBROKENTIMEOUT in recorder.c!)
2017-04-02 10:08:49 +02:00
if ( Receiver - > ChannelID ( ) . Valid ( ) )
dsyslog ( " CAM %d: %sknown to decrypt channel %s (scramblingTimeout = %ds) " , camSlot - > MasterSlotNumber ( ) , KnownToDecrypt ? " " : " not " , * Receiver - > ChannelID ( ) . ToString ( ) , Receiver - > scramblingTimeout ) ;
2017-01-09 14:27:36 +01:00
}
2007-01-07 14:46:14 +01:00
}
2021-06-08 14:57:26 +02:00
if ( patFilter & & Receiver - > ChannelID ( ) . Valid ( ) )
patFilter - > Request ( Receiver - > ChannelID ( ) . Sid ( ) ) ;
2007-01-07 14:46:14 +01:00
Start ( ) ;
2002-06-16 12:57:31 +02:00
return true ;
}
}
esyslog ( " ERROR: no free receiver slot! " ) ;
return false ;
}
2022-01-24 16:53:45 +01:00
void cDevice : : Detach ( cReceiver * Receiver , bool ReleaseCam )
2002-06-16 12:57:31 +02:00
{
if ( ! Receiver | | Receiver - > device ! = this )
return ;
bool receiversLeft = false ;
2017-12-16 13:13:13 +01:00
mutexReceiver . Lock ( ) ;
2002-06-16 12:57:31 +02:00
for ( int i = 0 ; i < MAXRECEIVERS ; i + + ) {
2020-06-12 09:28:44 +02:00
if ( receiver [ i ] = = Receiver )
2002-06-16 12:57:31 +02:00
receiver [ i ] = NULL ;
else if ( receiver [ i ] )
receiversLeft = true ;
}
2021-06-08 14:57:26 +02:00
if ( patFilter & & Receiver - > ChannelID ( ) . Valid ( ) )
patFilter - > Release ( Receiver - > ChannelID ( ) . Sid ( ) ) ;
2017-12-16 13:13:13 +01:00
mutexReceiver . Unlock ( ) ;
2020-06-12 09:28:44 +02:00
Receiver - > device = NULL ;
Receiver - > Activate ( false ) ;
for ( int n = 0 ; n < Receiver - > numPids ; n + + )
DelPid ( Receiver - > pids [ n ] ) ;
2014-01-18 14:30:58 +01:00
if ( camSlot ) {
2015-01-07 13:00:33 +01:00
if ( Receiver - > priority > MINPRIORITY ) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
2014-01-18 14:30:58 +01:00
camSlot - > StartDecrypting ( ) ;
2022-01-24 16:53:45 +01:00
if ( ReleaseCam )
ReleaseCamSlot ( ) ;
2015-01-07 13:00:33 +01:00
}
2014-01-18 14:30:58 +01:00
}
2005-08-13 13:17:24 +02:00
if ( ! receiversLeft )
2018-01-27 14:45:08 +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 ) )
2022-01-24 16:53:45 +01:00
Detach ( Receiver , false ) ;
2005-06-05 13:37:37 +02:00
}
2022-01-24 16:53:45 +01:00
ReleaseCamSlot ( ) ;
2005-06-05 13:37:37 +02:00
}
}
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 + + )
2022-01-24 16:53:45 +01:00
Detach ( receiver [ i ] , false ) ;
ReleaseCamSlot ( ) ;
2006-01-06 13:55:57 +01:00
}
2002-09-08 09:03:10 +02:00
// --- cTSBuffer -------------------------------------------------------------
2019-05-28 15:54:22 +02:00
cTSBuffer : : cTSBuffer ( int File , int Size , int DeviceNumber )
2002-09-08 09:03:10 +02:00
{
2019-05-28 15:54:22 +02:00
SetDescription ( " device %d TS buffer " , DeviceNumber ) ;
2002-09-08 09:03:10 +02:00
f = File ;
2019-05-28 15:54:22 +02:00
deviceNumber = DeviceNumber ;
2017-04-15 09:55:32 +02:00
delivered = 0 ;
2004-10-16 09:36:28 +02:00
ringBuffer = new cRingBufferLinear ( Size , TS_SIZE , true , " TS " ) ;
ringBuffer - > SetTimeouts ( 100 , 100 ) ;
2012-09-22 11:52:33 +02:00
ringBuffer - > SetIoThrottle ( ) ;
2004-10-16 09:36:28 +02:00
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 )
2019-05-28 15:54:22 +02:00
esyslog ( " ERROR: driver buffer overflow on device %d " , deviceNumber ) ;
2005-08-13 13:17:24 +02:00
else {
LOG_ERROR ;
break ;
}
}
2016-12-23 14:49:06 +01:00
cCondWait : : SleepMs ( 10 ) ; // avoids small chunks of data, which cause high CPU usage, esp. on ARM CPUs
2005-08-13 13:17:24 +02:00
}
}
2002-09-08 09:03:10 +02:00
}
}
2017-04-15 09:39:55 +02:00
uchar * cTSBuffer : : Get ( int * Available , bool CheckAvailable )
2002-09-08 09:03:10 +02:00
{
2004-10-16 09:36:28 +02:00
int Count = 0 ;
if ( delivered ) {
2017-04-15 09:55:32 +02:00
ringBuffer - > Del ( delivered ) ;
delivered = 0 ;
2004-10-16 09:36:28 +02:00
}
2017-04-15 09:39:55 +02:00
if ( CheckAvailable & & ringBuffer - > Available ( ) < TS_SIZE )
return NULL ;
2004-10-16 09:36:28 +02:00
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 ) ;
2019-05-28 15:54:22 +02:00
esyslog ( " ERROR: skipped %d bytes to sync on TS packet on device %d " , Count , deviceNumber ) ;
2002-09-08 09:03:10 +02:00
return NULL ;
}
2017-04-15 09:55:32 +02:00
delivered = TS_SIZE ;
2013-12-28 13:29:54 +01:00
if ( Available )
* Available = Count ;
2002-09-08 09:03:10 +02:00
return p ;
}
return NULL ;
}
2014-01-02 10:47:08 +01:00
void cTSBuffer : : Skip ( int Count )
{
2017-04-15 09:55:32 +02:00
delivered = Count ;
2014-01-02 10:47:08 +01:00
}