2007-04-24 13:13:05 +02:00
# include <assert.h>
# include <libsi/section.h>
# include <libsi/descriptor.h>
2008-10-13 13:30:05 +02:00
# include "remux/ts2ps.h"
2009-06-19 08:32:38 +02:00
# include "remux/ts2pes.h"
2008-10-13 13:30:05 +02:00
# include "remux/ts2es.h"
# include "remux/extern.h"
2014-06-07 00:24:27 +02:00
# include <vdr/transfer.h>
2004-12-30 23:43:55 +01:00
# include "server/livestreamer.h"
2014-05-18 15:24:24 +02:00
# include "server/setup.h"
2004-12-30 23:43:55 +01:00
# include "common.h"
2009-06-19 08:32:38 +02:00
using namespace Streamdev ;
2008-02-22 13:02:48 +01:00
2014-06-07 00:24:27 +02:00
// device occupied timeout to prevent VDR main loop to immediately switch back
// when streamdev switched the live TV channel.
// Note that there is still a gap between the GetDevice() and SetOccupied()
// calls where the VDR main loop could strike
# define STREAMDEVTUNETIMEOUT 5
2005-02-10 23:24:26 +01:00
// --- cStreamdevLiveReceiver -------------------------------------------------
2007-04-23 17:44:55 +02:00
class cStreamdevLiveReceiver : public cReceiver {
friend class cStreamdevStreamer ;
private :
2012-12-16 12:40:44 +01:00
cStreamdevLiveStreamer * m_Streamer ;
2007-04-23 17:44:55 +02:00
protected :
2016-03-21 00:28:02 +01:00
# if APIVERSNUM >= 20300
virtual void Receive ( const uchar * Data , int Length ) ;
# else
2007-04-23 17:44:55 +02:00
virtual void Receive ( uchar * Data , int Length ) ;
2016-03-21 00:28:02 +01:00
# endif
2007-04-23 17:44:55 +02:00
public :
2012-12-16 12:40:44 +01:00
cStreamdevLiveReceiver ( cStreamdevLiveStreamer * Streamer , const cChannel * Channel , int Priority , const int * Pids ) ;
2007-04-23 17:44:55 +02:00
virtual ~ cStreamdevLiveReceiver ( ) ;
} ;
2012-12-16 12:40:44 +01:00
cStreamdevLiveReceiver : : cStreamdevLiveReceiver ( cStreamdevLiveStreamer * Streamer , const cChannel * Channel , int Priority , const int * Pids ) :
2011-09-09 23:26:45 +02:00
cReceiver ( Channel , Priority ) ,
2005-02-08 14:59:16 +01:00
m_Streamer ( Streamer )
{
2011-09-09 23:26:45 +02:00
// clears all PIDs but channel remains set
SetPids ( NULL ) ;
AddPids ( Pids ) ;
2004-12-30 23:43:55 +01:00
}
2005-02-08 14:59:16 +01:00
cStreamdevLiveReceiver : : ~ cStreamdevLiveReceiver ( )
{
2004-12-30 23:43:55 +01:00
Dprintf ( " Killing live receiver \n " ) ;
Detach ( ) ;
}
2016-03-21 00:28:02 +01:00
# if APIVERSNUM >= 20300
void cStreamdevLiveReceiver : : Receive ( const uchar * Data , int Length ) {
# else
2004-12-30 23:43:55 +01:00
void cStreamdevLiveReceiver : : Receive ( uchar * Data , int Length ) {
2016-03-21 00:28:02 +01:00
# endif
2012-12-16 12:40:44 +01:00
m_Streamer - > Receive ( Data , Length ) ;
2004-12-30 23:43:55 +01:00
}
2007-04-24 13:13:05 +02:00
// --- cStreamdevPatFilter ----------------------------------------------------
class cStreamdevPatFilter : public cFilter {
private :
int pmtPid ;
int pmtSid ;
int pmtVersion ;
2009-06-19 08:32:38 +02:00
uchar tspat_buf [ TS_SIZE ] ;
cStreamdevBuffer siBuffer ;
2007-04-24 13:13:05 +02:00
const cChannel * m_Channel ;
cStreamdevLiveStreamer * m_Streamer ;
virtual void Process ( u_short Pid , u_char Tid , const u_char * Data , int Length ) ;
int GetPid ( SI : : PMT : : Stream & stream ) ;
public :
cStreamdevPatFilter ( cStreamdevLiveStreamer * Streamer , const cChannel * Channel ) ;
2009-06-19 08:32:38 +02:00
uchar * Get ( int & Count ) { return siBuffer . Get ( Count ) ; }
void Del ( int Count ) { return siBuffer . Del ( Count ) ; }
2007-04-24 13:13:05 +02:00
} ;
2009-06-19 08:32:38 +02:00
cStreamdevPatFilter : : cStreamdevPatFilter ( cStreamdevLiveStreamer * Streamer , const cChannel * Channel ) : siBuffer ( 10 * TS_SIZE , TS_SIZE )
2007-04-24 13:13:05 +02:00
{
2008-10-22 13:17:43 +02:00
Dprintf ( " cStreamdevPatFilter( \" %s \" ) \n " , Channel - > Name ( ) ) ;
2007-04-24 13:13:05 +02:00
assert ( Streamer ) ;
m_Channel = Channel ;
m_Streamer = Streamer ;
pmtPid = 0 ;
pmtSid = 0 ;
pmtVersion = - 1 ;
Set ( 0x00 , 0x00 ) ; // PAT
2009-06-19 08:32:38 +02:00
// initialize PAT buffer. Only some values are dynamic (see comments)
memset ( tspat_buf , 0xff , TS_SIZE ) ;
tspat_buf [ 0 ] = TS_SYNC_BYTE ; // Transport packet header sunchronization byte (1000011 = 0x47h)
tspat_buf [ 1 ] = 0x40 ; // Set payload unit start indicator bit
tspat_buf [ 2 ] = 0x0 ; // PID
tspat_buf [ 3 ] = 0x10 ; // Set payload flag, DYNAMIC: Continuity counter
tspat_buf [ 4 ] = 0x0 ; // SI pointer field
tspat_buf [ 5 ] = 0x0 ; // PAT table id
tspat_buf [ 6 ] = 0xb0 ; // Section syntax indicator bit and reserved bits set
tspat_buf [ 7 ] = 12 + 1 ; // Section length (12 bit): PAT_TABLE_LEN + 1
tspat_buf [ 8 ] = 0 ; // DYNAMIC: Transport stream ID (bits 8-15)
tspat_buf [ 9 ] = 0 ; // DYNAMIC: Transport stream ID (bits 0-7)
tspat_buf [ 10 ] = 0xc0 ; // Reserved, DYNAMIC: Version number, DYNAMIC: Current next indicator
tspat_buf [ 11 ] = 0x0 ; // Section number
tspat_buf [ 12 ] = 0x0 ; // Last section number
tspat_buf [ 13 ] = 0 ; // DYNAMIC: Program number (bits 8-15)
tspat_buf [ 14 ] = 0 ; // DYNAMIC: Program number (bits 0-7)
tspat_buf [ 15 ] = 0xe0 ; // Reserved, DYNAMIC: Network ID (bits 8-12)
tspat_buf [ 16 ] = 0 ; // DYNAMIC: Network ID (bits 0-7)
tspat_buf [ 17 ] = 0 ; // DYNAMIC: Checksum
tspat_buf [ 18 ] = 0 ; // DYNAMIC: Checksum
tspat_buf [ 19 ] = 0 ; // DYNAMIC: Checksum
tspat_buf [ 20 ] = 0 ; // DYNAMIC: Checksum
2007-04-24 13:13:05 +02:00
}
static const char * const psStreamTypes [ ] = {
" UNKNOWN " ,
" ISO/IEC 11172 Video " ,
" ISO/IEC 13818-2 Video " ,
" ISO/IEC 11172 Audio " ,
" ISO/IEC 13818-3 Audio " ,
" ISO/IEC 13818-1 Privete sections " ,
" ISO/IEC 13818-1 Private PES data " ,
" ISO/IEC 13512 MHEG " ,
" ISO/IEC 13818-1 Annex A DSM CC " ,
" 0x09 " ,
" ISO/IEC 13818-6 Multiprotocol encapsulation " ,
" ISO/IEC 13818-6 DSM-CC U-N Messages " ,
" ISO/IEC 13818-6 Stream Descriptors " ,
" ISO/IEC 13818-6 Sections (any type, including private data) " ,
" ISO/IEC 13818-1 auxiliary " ,
" ISO/IEC 13818-7 Audio with ADTS transport sytax " ,
" ISO/IEC 14496-2 Visual (MPEG-4) " ,
" ISO/IEC 14496-3 Audio with LATM transport syntax " ,
" 0x12 " , " 0x13 " , " 0x14 " , " 0x15 " , " 0x16 " , " 0x17 " , " 0x18 " , " 0x19 " , " 0x1a " ,
" ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264) " ,
" " ,
} ;
int cStreamdevPatFilter : : GetPid ( SI : : PMT : : Stream & stream )
{
SI : : Descriptor * d ;
if ( ! stream . getPid ( ) )
return 0 ;
switch ( stream . getStreamType ( ) ) {
case 0x01 : // ISO/IEC 11172 Video
case 0x02 : // ISO/IEC 13818-2 Video
case 0x03 : // ISO/IEC 11172 Audio
case 0x04 : // ISO/IEC 13818-3 Audio
#if 0
case 0x07 : // ISO/IEC 13512 MHEG
case 0x08 : // ISO/IEC 13818-1 Annex A DSM CC
case 0x0a : // ISO/IEC 13818-6 Multiprotocol encapsulation
case 0x0b : // ISO/IEC 13818-6 DSM-CC U-N Messages
case 0x0c : // ISO/IEC 13818-6 Stream Descriptors
case 0x0d : // ISO/IEC 13818-6 Sections (any type, including private data)
case 0x0e : // ISO/IEC 13818-1 auxiliary
# endif
case 0x0f : // ISO/IEC 13818-7 Audio with ADTS transport syntax
case 0x10 : // ISO/IEC 14496-2 Visual (MPEG-4)
case 0x11 : // ISO/IEC 14496-3 Audio with LATM transport syntax
case 0x1b : // ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)
2008-10-22 13:17:43 +02:00
Dprintf ( " cStreamdevPatFilter PMT scanner adding PID %d (%s) \n " ,
2007-04-24 13:13:05 +02:00
stream . getPid ( ) , psStreamTypes [ stream . getStreamType ( ) ] ) ;
return stream . getPid ( ) ;
case 0x05 : // ISO/IEC 13818-1 private sections
case 0x06 : // ISO/IEC 13818-1 PES packets containing private data
for ( SI : : Loop : : Iterator it ; ( d = stream . streamDescriptors . getNext ( it ) ) ; ) {
switch ( d - > getDescriptorTag ( ) ) {
case SI : : AC3DescriptorTag :
2010-04-19 12:17:33 +02:00
case SI : : EnhancedAC3DescriptorTag :
2008-10-22 13:17:43 +02:00
Dprintf ( " cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s \n " ,
2007-04-24 13:13:05 +02:00
stream . getPid ( ) , psStreamTypes [ stream . getStreamType ( ) ] , " AC3 " ) ;
2010-02-21 00:02:10 +01:00
delete d ;
2007-04-24 13:13:05 +02:00
return stream . getPid ( ) ;
case SI : : TeletextDescriptorTag :
2008-10-22 13:17:43 +02:00
Dprintf ( " cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s \n " ,
2007-04-24 13:13:05 +02:00
stream . getPid ( ) , psStreamTypes [ stream . getStreamType ( ) ] , " Teletext " ) ;
2010-02-21 00:02:10 +01:00
delete d ;
2007-04-24 13:13:05 +02:00
return stream . getPid ( ) ;
case SI : : SubtitlingDescriptorTag :
2008-10-22 13:17:43 +02:00
Dprintf ( " cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s \n " ,
2007-04-24 13:13:05 +02:00
stream . getPid ( ) , psStreamTypes [ stream . getStreamType ( ) ] , " DVBSUB " ) ;
2010-02-21 00:02:10 +01:00
delete d ;
2007-04-24 13:13:05 +02:00
return stream . getPid ( ) ;
default :
2008-10-22 13:17:43 +02:00
Dprintf ( " cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s \n " ,
2007-04-24 13:13:05 +02:00
stream . getPid ( ) , psStreamTypes [ stream . getStreamType ( ) ] , " UNKNOWN " ) ;
break ;
}
delete d ;
}
break ;
default :
/* This following section handles all the cases where the audio track
* info is stored in PMT user info with stream id > = 0x80
* we check the registration format identifier to see if it
* holds " AC-3 "
*/
if ( stream . getStreamType ( ) > = 0x80 ) {
bool found = false ;
for ( SI : : Loop : : Iterator it ; ( d = stream . streamDescriptors . getNext ( it ) ) ; ) {
switch ( d - > getDescriptorTag ( ) ) {
case SI : : RegistrationDescriptorTag :
/* unfortunately libsi does not implement RegistrationDescriptor */
if ( d - > getLength ( ) > = 4 ) {
found = true ;
SI : : CharArray rawdata = d - > getData ( ) ;
if ( /*rawdata[0] == 5 && rawdata[1] >= 4 && */
rawdata [ 2 ] = = ' A ' & & rawdata [ 3 ] = = ' C ' & &
rawdata [ 4 ] = = ' - ' & & rawdata [ 5 ] = = ' 3 ' ) {
isyslog ( " cStreamdevPatFilter PMT scanner: "
" Adding pid %d (type 0x%x) RegDesc len %d (%c%c%c%c) " ,
stream . getPid ( ) , stream . getStreamType ( ) ,
d - > getLength ( ) , rawdata [ 2 ] , rawdata [ 3 ] ,
rawdata [ 4 ] , rawdata [ 5 ] ) ;
2010-02-21 00:02:10 +01:00
delete d ;
2007-04-24 13:13:05 +02:00
return stream . getPid ( ) ;
}
}
break ;
default :
break ;
}
delete d ;
}
if ( ! found ) {
isyslog ( " Adding pid %d (type 0x%x) RegDesc not found -> assume AC-3 " ,
stream . getPid ( ) , stream . getStreamType ( ) ) ;
return stream . getPid ( ) ;
}
}
2008-10-22 13:17:43 +02:00
Dprintf ( " cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s \n " ,
2007-04-24 13:13:05 +02:00
stream . getPid ( ) , psStreamTypes [ stream . getStreamType ( ) < 0x1c ? stream . getStreamType ( ) : 0 ] , " UNKNOWN " ) ;
break ;
}
return 0 ;
}
void cStreamdevPatFilter : : Process ( u_short Pid , u_char Tid , const u_char * Data , int Length )
{
if ( Pid = = 0x00 ) {
2008-11-24 13:10:27 +01:00
if ( Tid = = 0x00 ) {
2007-04-24 13:13:05 +02:00
SI : : PAT pat ( Data , false ) ;
if ( ! pat . CheckCRCAndParse ( ) )
return ;
SI : : PAT : : Association assoc ;
for ( SI : : Loop : : Iterator it ; pat . associationLoop . getNext ( assoc , it ) ; ) {
if ( ! assoc . isNITPid ( ) ) {
2016-03-21 00:28:02 +01:00
# if APIVERSNUM >= 20300
LOCK_CHANNELS_READ ;
const cChannel * Channel = Channels - > GetByServiceID ( Source ( ) , Transponder ( ) , assoc . getServiceId ( ) ) ;
# else
2007-04-24 13:13:05 +02:00
const cChannel * Channel = Channels . GetByServiceID ( Source ( ) , Transponder ( ) , assoc . getServiceId ( ) ) ;
2016-03-21 00:28:02 +01:00
# endif
2007-04-24 13:13:05 +02:00
if ( Channel & & ( Channel = = m_Channel ) ) {
2008-11-24 13:10:27 +01:00
int prevPmtPid = pmtPid ;
2007-04-24 13:13:05 +02:00
if ( 0 ! = ( pmtPid = assoc . getPid ( ) ) ) {
2008-10-22 13:17:43 +02:00
Dprintf ( " cStreamdevPatFilter: PMT pid for channel %s: %d \n " , Channel - > Name ( ) , pmtPid ) ;
2007-04-24 13:13:05 +02:00
pmtSid = assoc . getServiceId ( ) ;
2009-06-19 08:32:38 +02:00
// repack PAT to TS frame and send to client
int ts_id ;
unsigned int crc , i , len ;
uint8_t * tmp ;
static uint8_t ccounter = 0 ;
ccounter = ( ccounter + 1 ) % 16 ;
ts_id = Channel - > Tid ( ) ; // Get transport stream id of the channel
tspat_buf [ 3 ] = 0x10 | ccounter ; // Set payload flag, Continuity counter
tspat_buf [ 8 ] = ( ts_id > > 8 ) ; // Transport stream ID (bits 8-15)
tspat_buf [ 9 ] = ( ts_id & 0xff ) ; // Transport stream ID (bits 0-7)
tspat_buf [ 10 ] = 0xc0 | ( ( pat . getVersionNumber ( ) < < 1 ) & 0x3e ) |
pat . getCurrentNextIndicator ( ) ; // Version number, Current next indicator
tspat_buf [ 13 ] = ( pmtSid > > 8 ) ; // Program number (bits 8-15)
tspat_buf [ 14 ] = ( pmtSid & 0xff ) ; // Program number (bits 0-7)
tspat_buf [ 15 ] = 0xe0 | ( pmtPid > > 8 ) ; // Network ID (bits 8-12)
tspat_buf [ 16 ] = ( pmtPid & 0xff ) ; // Network ID (bits 0-7)
crc = 0xffffffff ;
len = 12 ; // PAT_TABLE_LEN
tmp = & tspat_buf [ 4 + 1 ] ; // TS_HDR_LEN + 1
while ( len - - ) {
crc ^ = * tmp + + < < 24 ;
for ( i = 0 ; i < 8 ; i + + )
crc = ( crc < < 1 ) ^ ( ( crc & 0x80000000 ) ? 0x04c11db7 : 0 ) ; // CRC32POLY
}
tspat_buf [ 17 ] = crc > > 24 & 0xff ; // Checksum
tspat_buf [ 18 ] = crc > > 16 & 0xff ; // Checksum
tspat_buf [ 19 ] = crc > > 8 & 0xff ; // Checksum
tspat_buf [ 20 ] = crc & 0xff ; // Checksum
int written = siBuffer . PutTS ( tspat_buf , TS_SIZE ) ;
if ( written ! = TS_SIZE )
siBuffer . ReportOverflow ( TS_SIZE - written ) ;
2008-11-24 13:10:27 +01:00
if ( pmtPid ! = prevPmtPid ) {
2010-12-02 09:57:17 +01:00
m_Streamer - > SetPid ( pmtPid , true ) ;
2008-11-24 13:10:27 +01:00
Add ( pmtPid , 0x02 ) ;
pmtVersion = - 1 ;
}
2007-04-24 13:13:05 +02:00
return ;
}
}
}
}
}
} else if ( Pid = = pmtPid & & Tid = = SI : : TableIdPMT & & Source ( ) & & Transponder ( ) ) {
SI : : PMT pmt ( Data , false ) ;
if ( ! pmt . CheckCRCAndParse ( ) )
return ;
if ( pmt . getServiceId ( ) ! = pmtSid )
return ; // skip broken PMT records
if ( pmtVersion ! = - 1 ) {
if ( pmtVersion ! = pmt . getVersionNumber ( ) ) {
2008-10-22 13:17:43 +02:00
Dprintf ( " cStreamdevPatFilter: PMT version changed, detaching all pids \n " ) ;
2009-06-19 08:32:38 +02:00
cFilter : : Del ( pmtPid , 0x02 ) ;
2007-04-24 13:13:05 +02:00
pmtPid = 0 ; // this triggers PAT scan
}
return ;
}
pmtVersion = pmt . getVersionNumber ( ) ;
SI : : PMT : : Stream stream ;
int pids [ MAXRECEIVEPIDS + 1 ] , npids = 0 ;
pids [ npids + + ] = pmtPid ;
#if 0
pids [ npids + + ] = 0x10 ; // pid 0x10, tid 0x40: NIT
2011-10-25 17:18:23 +02:00
# endif
2007-04-24 13:13:05 +02:00
pids [ npids + + ] = 0x11 ; // pid 0x11, tid 0x42: SDT
pids [ npids + + ] = 0x14 ; // pid 0x14, tid 0x70: TDT
2008-03-13 15:10:17 +01:00
pids [ npids + + ] = 0x12 ; // pid 0x12, tid 0x4E...0x6F: EIT
2007-04-24 13:13:05 +02:00
for ( SI : : Loop : : Iterator it ; pmt . streamLoop . getNext ( stream , it ) ; )
if ( 0 ! = ( pids [ npids ] = GetPid ( stream ) ) & & npids < MAXRECEIVEPIDS )
npids + + ;
pids [ npids ] = 0 ;
m_Streamer - > SetPids ( pmt . getPCRPid ( ) , pids ) ;
}
}
2007-04-23 17:44:55 +02:00
2005-02-10 23:24:26 +01:00
// --- cStreamdevLiveStreamer -------------------------------------------------
2014-06-07 00:24:27 +02:00
cStreamdevLiveStreamer : : cStreamdevLiveStreamer ( const cServerConnection * Connection , const cChannel * Channel , int Priority , eStreamType StreamType , const int * Apid , const int * Dpid ) :
2010-12-02 09:57:17 +01:00
cStreamdevStreamer ( " streamdev-livestreaming " , Connection ) ,
2005-02-10 23:24:26 +01:00
m_Priority ( Priority ) ,
m_NumPids ( 0 ) ,
2014-06-07 00:24:27 +02:00
m_Channel ( Channel ) ,
2005-02-10 23:24:26 +01:00
m_Device ( NULL ) ,
m_Receiver ( NULL ) ,
2007-04-24 13:13:05 +02:00
m_PatFilter ( NULL ) ,
2014-06-07 00:24:27 +02:00
m_SwitchLive ( false )
2005-02-10 23:24:26 +01:00
{
2012-12-16 12:40:44 +01:00
m_ReceiveBuffer = new cStreamdevBuffer ( LIVEBUFSIZE , TS_SIZE * 2 , true , " streamdev-livestreamer " ) ,
m_ReceiveBuffer - > SetTimeouts ( 0 , 100 ) ;
2014-06-07 00:24:27 +02:00
if ( Priority = = IDLEPRIORITY ) {
2014-08-10 15:57:16 +02:00
SetChannel ( StreamType , Apid , Dpid ) ;
2014-06-07 00:24:27 +02:00
}
else {
m_Device = SwitchDevice ( Channel , Priority ) ;
if ( m_Device )
2014-08-10 15:57:16 +02:00
SetChannel ( StreamType , Apid , Dpid ) ;
2014-08-31 00:20:35 +02:00
memcpy ( m_Caids , Channel - > Caids ( ) , sizeof ( m_Caids ) ) ;
2014-06-07 00:24:27 +02:00
}
2004-12-30 23:43:55 +01:00
}
2005-02-10 23:24:26 +01:00
cStreamdevLiveStreamer : : ~ cStreamdevLiveStreamer ( )
{
2004-12-30 23:43:55 +01:00
Dprintf ( " Desctructing Live streamer \n " ) ;
2005-02-11 17:44:14 +01:00
Stop ( ) ;
2012-12-16 12:40:44 +01:00
DELETENULL ( m_PatFilter ) ;
2007-04-24 13:13:05 +02:00
DELETENULL ( m_Receiver ) ;
2012-12-16 12:40:44 +01:00
delete m_ReceiveBuffer ;
2007-04-24 13:13:05 +02:00
}
bool cStreamdevLiveStreamer : : HasPid ( int Pid )
{
int idx ;
for ( idx = 0 ; idx < m_NumPids ; + + idx )
if ( m_Pids [ idx ] = = Pid )
return true ;
return false ;
2004-12-30 23:43:55 +01:00
}
2005-02-10 23:24:26 +01:00
bool cStreamdevLiveStreamer : : SetPid ( int Pid , bool On )
{
2004-12-30 23:43:55 +01:00
int idx ;
2005-02-10 23:24:26 +01:00
if ( Pid = = 0 )
return true ;
2004-12-30 23:43:55 +01:00
if ( On ) {
2005-02-08 14:59:16 +01:00
for ( idx = 0 ; idx < m_NumPids ; + + idx ) {
2004-12-30 23:43:55 +01:00
if ( m_Pids [ idx ] = = Pid )
return true ; // No change needed
}
2005-02-08 14:59:16 +01:00
if ( m_NumPids = = MAXRECEIVEPIDS ) {
2004-12-30 23:43:55 +01:00
esyslog ( " ERROR: Streamdev: No free slot to receive pid %d \n " , Pid ) ;
return false ;
}
2005-02-08 14:59:16 +01:00
m_Pids [ m_NumPids + + ] = Pid ;
m_Pids [ m_NumPids ] = 0 ;
2004-12-30 23:43:55 +01:00
} else {
2005-02-08 14:59:16 +01:00
for ( idx = 0 ; idx < m_NumPids ; + + idx ) {
if ( m_Pids [ idx ] = = Pid ) {
- - m_NumPids ;
memmove ( & m_Pids [ idx ] , & m_Pids [ idx + 1 ] , sizeof ( int ) * ( m_NumPids - idx ) ) ;
}
2004-12-30 23:43:55 +01:00
}
}
2007-04-24 13:13:05 +02:00
StartReceiver ( ) ;
return true ;
}
bool cStreamdevLiveStreamer : : SetPids ( int Pid , const int * Pids1 , const int * Pids2 , const int * Pids3 )
{
m_NumPids = 0 ;
if ( Pid )
m_Pids [ m_NumPids + + ] = Pid ;
if ( Pids1 )
for ( ; * Pids1 & & m_NumPids < MAXRECEIVEPIDS ; Pids1 + + )
if ( ! HasPid ( * Pids1 ) )
m_Pids [ m_NumPids + + ] = * Pids1 ;
if ( Pids2 )
for ( ; * Pids2 & & m_NumPids < MAXRECEIVEPIDS ; Pids2 + + )
if ( ! HasPid ( * Pids2 ) )
m_Pids [ m_NumPids + + ] = * Pids2 ;
if ( Pids3 )
for ( ; * Pids3 & & m_NumPids < MAXRECEIVEPIDS ; Pids3 + + )
if ( ! HasPid ( * Pids3 ) )
m_Pids [ m_NumPids + + ] = * Pids3 ;
if ( m_NumPids > = MAXRECEIVEPIDS ) {
esyslog ( " ERROR: Streamdev: No free slot to receive pid %d \n " , Pid ) ;
return false ;
}
m_Pids [ m_NumPids ] = 0 ;
StartReceiver ( ) ;
return true ;
}
2010-12-02 09:57:17 +01:00
void cStreamdevLiveStreamer : : SetPriority ( int Priority )
{
m_Priority = Priority ;
2015-10-04 21:41:35 +02:00
# if VDRVERSNUM >= 20104
cThreadLock ThreadLock ( m_Device ) ;
if ( m_Receiver )
m_Receiver - > SetPriority ( Priority ) ;
else
# endif
StartReceiver ( ) ;
2010-12-02 09:57:17 +01:00
}
2011-07-06 09:13:50 +02:00
void cStreamdevLiveStreamer : : GetSignal ( int * DevNum , int * Strength , int * Quality ) const
{
if ( m_Device ) {
* DevNum = m_Device - > DeviceNumber ( ) + 1 ;
* Strength = m_Device - > SignalStrength ( ) ;
* Quality = m_Device - > SignalQuality ( ) ;
}
}
2011-11-28 16:23:57 +01:00
cString cStreamdevLiveStreamer : : ToText ( ) const
{
if ( m_Device & & m_Channel ) {
return cString : : sprintf ( " DVB%-2d %3d %s " , m_Device - > DeviceNumber ( ) + 1 , m_Channel - > Number ( ) , m_Channel - > Name ( ) ) ;
}
return cString ( " " ) ;
}
2012-12-16 13:21:19 +01:00
bool cStreamdevLiveStreamer : : IsReceiving ( void ) const
{
cThreadLock ThreadLock ( m_Device ) ;
return m_Receiver & & m_Receiver - > IsAttached ( ) ;
}
2014-06-23 23:28:36 +02:00
void cStreamdevLiveStreamer : : StartReceiver ( bool Force )
2007-04-24 13:13:05 +02:00
{
2014-06-23 23:28:36 +02:00
if ( m_NumPids > 0 | | Force ) {
2004-12-30 23:43:55 +01:00
Dprintf ( " Creating Receiver to respect changed pids \n " ) ;
2010-12-02 09:57:17 +01:00
cReceiver * current = m_Receiver ;
cThreadLock ThreadLock ( m_Device ) ;
2012-12-16 13:21:19 +01:00
m_Receiver = new cStreamdevLiveReceiver ( this , m_Channel , m_Priority , m_Pids ) ;
2010-12-10 16:38:54 +01:00
if ( IsRunning ( ) )
Attach ( ) ;
2010-12-02 09:57:17 +01:00
delete current ;
2004-12-30 23:43:55 +01:00
}
2010-12-02 09:57:17 +01:00
else
DELETENULL ( m_Receiver ) ;
2004-12-30 23:43:55 +01:00
}
2014-08-10 15:57:16 +02:00
bool cStreamdevLiveStreamer : : SetChannel ( eStreamType StreamType , const int * Apid , const int * Dpid )
2005-02-08 16:34:38 +01:00
{
2004-12-30 23:43:55 +01:00
Dprintf ( " Initializing Remuxer for full channel transfer \n " ) ;
2007-04-24 13:13:05 +02:00
//printf("ca pid: %d\n", Channel->Ca());
2010-12-02 09:57:17 +01:00
const int * Apids = Apid ? Apid : m_Channel - > Apids ( ) ;
const int * Dpids = Dpid ? Dpid : m_Channel - > Dpids ( ) ;
2007-04-24 13:13:05 +02:00
2014-08-10 15:57:16 +02:00
switch ( StreamType ) {
2004-12-30 23:43:55 +01:00
case stES :
{
2005-02-10 23:24:26 +01:00
int pid = ISRADIO ( m_Channel ) ? m_Channel - > Apid ( 0 ) : m_Channel - > Vpid ( ) ;
2010-12-02 09:57:17 +01:00
if ( Apid & & Apid [ 0 ] )
pid = Apid [ 0 ] ;
else if ( Dpid & & Dpid [ 0 ] )
pid = Dpid [ 0 ] ;
2014-08-10 15:57:16 +02:00
SetRemux ( new cTS2ESRemux ( pid ) ) ;
2007-04-24 13:13:05 +02:00
return SetPids ( pid ) ;
2004-12-30 23:43:55 +01:00
}
case stPES :
2014-08-10 15:57:16 +02:00
SetRemux ( new cTS2PESRemux ( m_Channel - > Vpid ( ) , Apids , Dpids , m_Channel - > Spids ( ) ) ) ;
2007-04-24 13:13:05 +02:00
return SetPids ( m_Channel - > Vpid ( ) , Apids , Dpids , m_Channel - > Spids ( ) ) ;
2004-12-30 23:43:55 +01:00
2013-11-17 11:20:42 +01:00
# ifdef STREAMDEV_PS
2004-12-30 23:43:55 +01:00
case stPS :
2014-08-10 15:57:16 +02:00
SetRemux ( new cTS2PSRemux ( m_Channel - > Vpid ( ) , Apids , Dpids , m_Channel - > Spids ( ) ) ) ;
2007-04-24 13:13:05 +02:00
return SetPids ( m_Channel - > Vpid ( ) , Apids , Dpids , m_Channel - > Spids ( ) ) ;
2013-11-17 11:20:42 +01:00
# endif
2004-12-30 23:43:55 +01:00
2010-12-02 09:57:17 +01:00
case stEXT :
2014-08-10 15:57:16 +02:00
SetRemux ( new cExternRemux ( Connection ( ) , m_Channel , Apids , Dpids ) ) ;
2009-08-05 11:33:13 +02:00
// fall through
2004-12-30 23:43:55 +01:00
case stTS :
2007-04-24 13:13:05 +02:00
// This should never happen, but ...
if ( m_PatFilter ) {
Detach ( ) ;
DELETENULL ( m_PatFilter ) ;
}
2008-10-31 12:59:48 +01:00
// Set pids from cChannel
SetPids ( m_Channel - > Vpid ( ) , Apids , Dpids , m_Channel - > Spids ( ) ) ;
if ( m_Channel - > Vpid ( ) ! = m_Channel - > Ppid ( ) )
SetPid ( m_Channel - > Ppid ( ) , true ) ;
2007-04-24 13:13:05 +02:00
// Set pids from PMT
m_PatFilter = new cStreamdevPatFilter ( this , m_Channel ) ;
return true ;
2005-02-08 16:34:38 +01:00
case stTSPIDS :
2004-12-30 23:43:55 +01:00
Dprintf ( " pid streaming mode \n " ) ;
2014-06-23 23:28:36 +02:00
// No PIDs requested yet. Start receiver anyway to occupy device
StartReceiver ( true ) ;
2004-12-30 23:43:55 +01:00
return true ;
2009-09-18 12:41:41 +02:00
default :
return false ;
2004-12-30 23:43:55 +01:00
}
}
2016-03-21 00:28:02 +01:00
# if APIVERSNUM >= 20300
void cStreamdevLiveStreamer : : Receive ( const uchar * Data , int Length )
# else
2012-12-16 12:40:44 +01:00
void cStreamdevLiveStreamer : : Receive ( uchar * Data , int Length )
2016-03-21 00:28:02 +01:00
# endif
2012-12-16 12:40:44 +01:00
{
int p = m_ReceiveBuffer - > PutTS ( Data , Length ) ;
if ( p ! = Length )
m_ReceiveBuffer - > ReportOverflow ( Length - p ) ;
}
2014-05-18 15:24:24 +02:00
void cStreamdevLiveStreamer : : Action ( void )
{
if ( StreamdevServerSetup . LiveBufferMs ) {
// wait for first data block
int count = 0 ;
while ( Running ( ) ) {
if ( m_ReceiveBuffer - > Get ( count ) ! = NULL ) {
cCondWait : : SleepMs ( StreamdevServerSetup . LiveBufferMs ) ;
break ;
}
}
}
cStreamdevStreamer : : Action ( ) ;
}
2005-02-09 20:47:09 +01:00
int cStreamdevLiveStreamer : : Put ( const uchar * Data , int Count )
{
2009-06-30 08:04:33 +02:00
// insert si data
if ( m_PatFilter ) {
int siCount ;
uchar * siData = m_PatFilter - > Get ( siCount ) ;
if ( siData ) {
2014-08-10 15:57:16 +02:00
siCount = cStreamdevStreamer : : Put ( siData , siCount ) ;
2009-06-30 08:04:33 +02:00
if ( siCount )
m_PatFilter - > Del ( siCount ) ;
2009-06-19 08:32:38 +02:00
}
2005-02-09 20:47:09 +01:00
}
2014-08-10 15:57:16 +02:00
return cStreamdevStreamer : : Put ( Data , Count ) ;
2005-02-09 20:47:09 +01:00
}
2005-03-12 13:54:19 +01:00
void cStreamdevLiveStreamer : : Attach ( void )
{
2007-04-24 13:13:05 +02:00
Dprintf ( " cStreamdevLiveStreamer::Attach() \n " ) ;
if ( m_Device ) {
if ( m_Receiver ) {
2014-08-09 22:59:31 +02:00
if ( m_Receiver - > IsAttached ( ) )
m_Device - > Detach ( m_Receiver ) ;
2007-04-24 13:13:05 +02:00
m_Device - > AttachReceiver ( m_Receiver ) ;
}
if ( m_PatFilter ) {
m_Device - > Detach ( m_PatFilter ) ;
m_Device - > AttachFilter ( m_PatFilter ) ;
}
}
2005-03-12 13:54:19 +01:00
}
void cStreamdevLiveStreamer : : Detach ( void )
{
2007-04-24 13:13:05 +02:00
Dprintf ( " cStreamdevLiveStreamer::Detach() \n " ) ;
if ( m_Device ) {
if ( m_Receiver )
m_Device - > Detach ( m_Receiver ) ;
if ( m_PatFilter )
m_Device - > Detach ( m_PatFilter ) ;
}
2005-03-12 13:54:19 +01:00
}
2005-02-09 20:47:09 +01:00
2014-06-07 00:24:27 +02:00
bool cStreamdevLiveStreamer : : UsedByLiveTV ( cDevice * device )
{
return device = = cTransferControl : : ReceiverDevice ( ) | |
( device - > IsPrimaryDevice ( ) & & device - > HasDecoder ( ) & & ! device - > Replaying ( ) ) ;
}
cDevice * cStreamdevLiveStreamer : : SwitchDevice ( const cChannel * Channel , int Priority )
{
cDevice * device = cDevice : : GetDevice ( Channel , Priority , false ) ;
if ( ! device ) {
dsyslog ( " streamdev: GetDevice failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d) " , Channel - > Number ( ) , Channel - > Name ( ) , Priority , cDevice : : PrimaryDevice ( ) - > CardIndex ( ) , cDevice : : ActualDevice ( ) - > CardIndex ( ) ) ;
}
else if ( ! device - > IsTunedToTransponder ( Channel ) & & UsedByLiveTV ( device ) ) {
// make sure VDR main loop doesn't switch back
device - > SetOccupied ( STREAMDEVTUNETIMEOUT ) ;
if ( device - > SwitchChannel ( Channel , false ) ) {
// switched away live TV
m_SwitchLive = true ;
}
else {
dsyslog ( " streamdev: SwitchChannel (live) failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d) " , Channel - > Number ( ) , Channel - > Name ( ) , Priority , cDevice : : PrimaryDevice ( ) - > CardIndex ( ) , cDevice : : ActualDevice ( ) - > CardIndex ( ) , device - > CardIndex ( ) ) ;
device - > SetOccupied ( 0 ) ;
device = NULL ;
}
}
else if ( ! device - > SwitchChannel ( Channel , false ) ) {
dsyslog ( " streamdev: SwitchChannel failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d) " , Channel - > Number ( ) , Channel - > Name ( ) , Priority , cDevice : : PrimaryDevice ( ) - > CardIndex ( ) , cDevice : : ActualDevice ( ) - > CardIndex ( ) , device - > CardIndex ( ) ) ;
device = NULL ;
}
return device ;
}
bool cStreamdevLiveStreamer : : ProvidesChannel ( const cChannel * Channel , int Priority )
{
cDevice * device = cDevice : : GetDevice ( Channel , Priority , false , true ) ;
if ( ! device )
dsyslog ( " streamdev: No device provides channel %d (%s) at priority %d " , Channel - > Number ( ) , Channel - > Name ( ) , Priority ) ;
return device ;
}
2014-08-09 23:04:45 +02:00
void cStreamdevLiveStreamer : : ChannelChange ( const cChannel * Channel )
{
2014-08-31 00:20:35 +02:00
if ( Running ( ) & & m_Device & & m_Channel = = Channel ) {
// Check whether the Caids actually changed
// If not, no need to re-tune, probably just an Audio PID update
if ( ! memcmp ( m_Caids , Channel - > Caids ( ) , sizeof ( m_Caids ) ) ) {
dsyslog ( " streamdev: channel %d (%s) changed, but caids remained the same, not re-tuning " , Channel - > Number ( ) , Channel - > Name ( ) ) ;
}
else {
Detach ( ) ;
if ( m_Device - > SwitchChannel ( m_Channel , false ) ) {
Attach ( ) ;
dsyslog ( " streamdev: channel %d (%s) changed, re-tuned " , Channel - > Number ( ) , Channel - > Name ( ) ) ;
memcpy ( m_Caids , Channel - > Caids ( ) , sizeof ( m_Caids ) ) ;
}
else
isyslog ( " streamdev: failed to re-tune after channel %d (%s) changed " , Channel - > Number ( ) , Channel - > Name ( ) ) ;
2014-08-09 23:04:45 +02:00
}
}
}
2014-06-07 00:24:27 +02:00
void cStreamdevLiveStreamer : : MainThreadHook ( )
{
2014-06-23 23:30:55 +02:00
if ( ! m_SwitchLive & & Running ( ) & & m_Device & & ! m_Device - > IsTunedToTransponder ( m_Channel ) & & ! IsReceiving ( ) ) {
cDevice * dev = SwitchDevice ( m_Channel , m_Priority ) ;
if ( dev ) {
dsyslog ( " streamdev: Lost channel %d (%s) on device %d. Continuing on device %d. " , m_Channel - > Number ( ) , m_Channel - > Name ( ) , m_Device - > CardIndex ( ) , dev - > CardIndex ( ) ) ;
m_Device = dev ;
StartReceiver ( ) ;
}
else {
isyslog ( " streamdev: Lost channel %d (%s) on device %d. " , m_Channel - > Number ( ) , m_Channel - > Name ( ) , m_Device - > CardIndex ( ) ) ;
Stop ( ) ;
}
}
2014-06-07 00:24:27 +02:00
if ( m_SwitchLive ) {
// switched away live TV. Try previous channel on other device first
2016-03-21 00:28:02 +01:00
# if APIVERSNUM >= 20300
LOCK_CHANNELS_READ ;
if ( ! Channels - > SwitchTo ( cDevice : : CurrentChannel ( ) ) ) {
// switch to streamdev channel otherwise
Channels - > SwitchTo ( m_Channel - > Number ( ) ) ;
# else
2014-06-07 00:24:27 +02:00
if ( ! Channels . SwitchTo ( cDevice : : CurrentChannel ( ) ) ) {
// switch to streamdev channel otherwise
Channels . SwitchTo ( m_Channel - > Number ( ) ) ;
2016-03-21 00:28:02 +01:00
# endif
2014-06-07 00:24:27 +02:00
Skins . Message ( mtInfo , tr ( " Streaming active " ) ) ;
}
if ( m_Device )
m_Device - > SetOccupied ( 0 ) ;
m_SwitchLive = false ;
}
}
2005-02-10 23:24:26 +01:00
std : : string cStreamdevLiveStreamer : : Report ( void )
{
2005-02-08 18:22:35 +01:00
std : : string result ;
2004-12-30 23:43:55 +01:00
if ( m_Device ! = NULL )
2005-02-08 18:22:35 +01:00
result + = ( std : : string ) " +- Device is " + ( const char * ) itoa ( m_Device - > CardIndex ( ) ) + " \n " ;
2004-12-30 23:43:55 +01:00
if ( m_Receiver ! = NULL )
result + = " +- Receiver is allocated \n " ;
result + = " +- Pids are " ;
for ( int i = 0 ; i < MAXRECEIVEPIDS ; + + i )
if ( m_Pids [ i ] ! = 0 )
2005-02-08 18:22:35 +01:00
result + = ( std : : string ) ( const char * ) itoa ( m_Pids [ i ] ) + " , " ;
2004-12-30 23:43:55 +01:00
result + = " \n " ;
return result ;
}