diff --git a/HISTORY b/HISTORY index 89dffaab..a5aa6526 100644 --- a/HISTORY +++ b/HISTORY @@ -8032,7 +8032,7 @@ Video Disk Recorder Revision History the last replayed recording (if any) by pressing Ok repeatedly in the Recordings menu. -2013-12-29: Version 2.1.3 +2014-01-01: Version 2.1.3 - Changed the return value of cPositioner::HorizonLongitude() to 0 in case the latitude of the antenna location is beyond +/-81 degrees. @@ -8091,7 +8091,10 @@ Video Disk Recorder Revision History Skyttä). - The new function cCamSlot::Decrypt() can be used by derived classes to implement a CAM slot that can be freely assigned to any device, without being directly inserted - into the full TS data stream in hardware. + into the full TS data stream in hardware. A derived class that implements Decrypt() + will also need to set the new parameter ReceiveCaPids in the call to the cCamSlot + base class constructor to true, in order to receive the CA pid TS packets that + contain data necessary for decrypting. - Many member functions of cCamSlot have been made virtual to allow for easier implementation of derived classes. - cTSBuffer now provides the number of available bytes in its Get() function. diff --git a/ci.c b/ci.c index 92aaf722..2d9735e5 100644 --- a/ci.c +++ b/ci.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ci.c 3.2 2013/12/29 15:51:08 kls Exp $ + * $Id: ci.c 3.3 2014/01/01 12:33:27 kls Exp $ */ #include "ci.h" @@ -19,6 +19,7 @@ #include #include "device.h" #include "pat.h" +#include "receiver.h" #include "tools.h" // Set these to 'true' for debug output: @@ -102,6 +103,16 @@ static char *GetString(int &Length, const uint8_t **Data) return NULL; } +// --- cCaPidReceiver -------------------------------------------------------- + +// A dummy receiver, just used to make the device receive the CA pids. + +class cCaPidReceiver : public cReceiver { +public: + virtual ~cCaPidReceiver() { Detach(); } + virtual void Receive(uchar *Data, int Length) {} + }; + // --- cTPDU ----------------------------------------------------------------- #define MAX_TPDU_SIZE 2048 @@ -570,7 +581,7 @@ bool cCiApplicationInformation::EnterMenu(void) #define CPCI_QUERY 0x03 #define CPCI_NOT_SELECTED 0x04 -class cCiCaPmt : public cListObject { +class cCiCaPmt { friend class cCiConditionalAccessSupport; private: uint8_t cmdId; @@ -1553,9 +1564,10 @@ cCamSlots CamSlots; #define MODULE_CHECK_INTERVAL 500 // ms #define MODULE_RESET_TIMEOUT 2 // s -cCamSlot::cCamSlot(cCiAdapter *CiAdapter) +cCamSlot::cCamSlot(cCiAdapter *CiAdapter, bool ReceiveCaPids) { ciAdapter = CiAdapter; + caPidReceiver = ReceiveCaPids ? new cCaPidReceiver : NULL; slotIndex = -1; lastModuleStatus = msReset; // avoids initial reset log message resetTime = 0; @@ -1572,6 +1584,7 @@ cCamSlot::cCamSlot(cCiAdapter *CiAdapter) cCamSlot::~cCamSlot() { + delete caPidReceiver; CamSlots.Del(this, false); DeleteAllConnections(); } @@ -1802,6 +1815,10 @@ void cCamSlot::SendCaPmt(uint8_t CmdId) const int *CaSystemIds = cas->GetCaSystemIds(); if (CaSystemIds && *CaSystemIds) { if (caProgramList.Count()) { + if (caPidReceiver && caPidReceiver->NumPids()) { + if (cDevice *d = Device()) + d->Detach(caPidReceiver); + } for (int Loop = 1; Loop <= 2; Loop++) { for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) { if (p->modified || resendPmt) { @@ -1814,6 +1831,15 @@ void cCamSlot::SendCaPmt(uint8_t CmdId) } } if ((Loop == 1) != Active) { // first remove, then add + if (caPidReceiver) { + int CaPids[MAXRECEIVEPIDS + 1]; + if (GetCaPids(source, transponder, p->programNumber, CaSystemIds, MAXRECEIVEPIDS + 1, CaPids) > 0) { + if (Loop == 1) + caPidReceiver->DelPids(CaPids); + else + caPidReceiver->AddPids(CaPids); + } + } if (cas->RepliesToQuery()) CaPmt.SetListManagement(Active ? CPLM_ADD : CPLM_UPDATE); if (Active || cas->RepliesToQuery()) @@ -1823,6 +1849,10 @@ void cCamSlot::SendCaPmt(uint8_t CmdId) } } } + if (caPidReceiver && caPidReceiver->NumPids()) { + if (cDevice *d = Device()) + d->AttachReceiver(caPidReceiver); + } resendPmt = false; } else { diff --git a/ci.h b/ci.h index f41c0dae..1d6f5d1f 100644 --- a/ci.h +++ b/ci.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ci.h 3.1 2013/12/28 13:20:08 kls Exp $ + * $Id: ci.h 3.2 2014/01/01 12:13:04 kls Exp $ */ #ifndef __CI_H @@ -121,6 +121,7 @@ class cTPDU; class cCiTransportConnection; class cCiSession; class cCiCaProgramData; +class cReceiver; class cCamSlot : public cListObject { friend class cCiAdapter; @@ -129,6 +130,7 @@ private: cMutex mutex; cCondVar processed; cCiAdapter *ciAdapter; + cReceiver *caPidReceiver; int slotIndex; int slotNumber; cCiTransportConnection *tc[MAX_CONNECTIONS_PER_CAM_SLOT + 1]; // connection numbering starts with 1 @@ -147,10 +149,13 @@ private: void Write(cTPDU *TPDU); cCiSession *GetSessionByResourceId(uint32_t ResourceId); public: - cCamSlot(cCiAdapter *CiAdapter); + cCamSlot(cCiAdapter *CiAdapter, bool ReceiveCaPids = false); ///< Creates a new CAM slot for the given CiAdapter. ///< The CiAdapter will take care of deleting the CAM slot, ///< so the caller must not delete it! + ///< If ReceiveCaPids is true, the CAM slot will take care that the CA pids + ///< of the selected programmes will be included in the TS data stream that + ///< is presented to the Decrypt() function. virtual ~cCamSlot(); bool Assign(cDevice *Device, bool Query = false); ///< Assigns this CAM slot to the given Device, if this is possible. @@ -243,6 +248,9 @@ public: ///< Data pointing to the TS packet immediately following the previous ///< one. However, it can not be assumed that a call to Decrypt() with ///< a Data pointer of P will be followed by a call with P + TS_SIZE. + ///< A derived class that implements this function will also need + ///< to set the ReceiveCaPids parameter in the call to the base class + ///< constructor to true in order to receive the CA pid data. }; class cCamSlots : public cList {}; diff --git a/device.c b/device.c index c9a70173..4db3ddd7 100644 --- a/device.c +++ b/device.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 3.5 2013/12/28 12:56:24 kls Exp $ + * $Id: device.c 3.6 2014/01/01 11:51:17 kls Exp $ */ #include "device.h" @@ -1666,7 +1666,7 @@ bool cDevice::AttachReceiver(cReceiver *Receiver) Receiver->device = this; receiver[i] = Receiver; Unlock(); - if (camSlot) { + if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver camSlot->StartDecrypting(); startScrambleDetection = time(NULL); } @@ -1697,7 +1697,7 @@ void cDevice::Detach(cReceiver *Receiver) else if (receiver[i]) receiversLeft = true; } - if (camSlot) + if (camSlot && Receiver->priority > MINPRIORITY) // priority check to avoid an infinite loop with the CAM slot's caPidReceiver camSlot->StartDecrypting(); if (!receiversLeft) Cancel(-1); diff --git a/pat.c b/pat.c index a7791e2a..9f5f12de 100644 --- a/pat.c +++ b/pat.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: pat.c 2.19 2012/11/25 14:12:21 kls Exp $ + * $Id: pat.c 3.1 2014/01/01 12:02:39 kls Exp $ */ #include "pat.h" @@ -21,6 +21,7 @@ class cCaDescriptor : public cListObject { private: int caSystem; + int caPid; int esPid; int length; uchar *data; @@ -29,6 +30,7 @@ public: virtual ~cCaDescriptor(); bool operator== (const cCaDescriptor &arg) const; int CaSystem(void) { return caSystem; } + int CaPid(void) { return caPid; } int EsPid(void) { return esPid; } int Length(void) const { return length; } const uchar *Data(void) const { return data; } @@ -37,6 +39,7 @@ public: cCaDescriptor::cCaDescriptor(int CaSystem, int CaPid, int EsPid, int Length, const uchar *Data) { caSystem = CaSystem; + caPid = CaPid; esPid = EsPid; length = Length + 6; data = MALLOC(uchar, length); @@ -79,6 +82,7 @@ public: bool Empty(void) { return caDescriptors.Count() == 0; } void AddCaDescriptor(SI::CaDescriptor *d, int EsPid); int GetCaDescriptors(const int *CaSystemIds, int BufSize, uchar *Data, int EsPid); + int GetCaPids(const int *CaSystemIds, int BufSize, int *Pids); const int *CaIds(void) { return caIds; } }; @@ -179,6 +183,30 @@ int cCaDescriptors::GetCaDescriptors(const int *CaSystemIds, int BufSize, uchar return -1; } +int cCaDescriptors::GetCaPids(const int *CaSystemIds, int BufSize, int *Pids) +{ + if (!CaSystemIds || !*CaSystemIds) + return 0; + if (BufSize > 0 && Pids) { + int numPids = 0; + for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) { + const int *caids = CaSystemIds; + do { + if (d->CaSystem() == *caids) { + if (numPids + 1 < BufSize) { + Pids[numPids++] = d->CaPid(); + Pids[numPids] = 0; + } + else + return -1; + } + } while (*++caids); + } + return numPids; + } + return -1; +} + // --- cCaDescriptorHandler -------------------------------------------------- class cCaDescriptorHandler : public cList { @@ -190,6 +218,7 @@ public: // 1 if it is an all new descriptor with actual contents, // and 2 if an existing descriptor was changed. int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid); + int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids); }; int cCaDescriptorHandler::AddCaDescriptors(cCaDescriptors *CaDescriptors) @@ -220,6 +249,16 @@ int cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int Serv return 0; } +int cCaDescriptorHandler::GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids) +{ + cMutexLock MutexLock(&mutex); + for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) { + if (ca->Is(Source, Transponder, ServiceId)) + return ca->GetCaPids(CaSystemIds, BufSize, Pids); + } + return 0; +} + cCaDescriptorHandler CaDescriptorHandler; int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid) @@ -227,6 +266,11 @@ int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSy return CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, EsPid); } +int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids) +{ + return CaDescriptorHandler.GetCaPids(Source, Transponder, ServiceId, CaSystemIds, BufSize, Pids); +} + // --- cPatFilter ------------------------------------------------------------ cPatFilter::cPatFilter(void) diff --git a/pat.h b/pat.h index 08da051f..b45e720e 100644 --- a/pat.h +++ b/pat.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: pat.h 2.3 2013/02/16 15:20:24 kls Exp $ + * $Id: pat.h 3.1 2013/12/30 11:32:40 kls Exp $ */ #ifndef __PAT_H @@ -39,7 +39,13 @@ int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSy ///< are copied that match one of the given CA system IDs. ///< Returns the number of bytes copied into Data (0 if no CA descriptors are ///< available), or -1 if BufSize was too small to hold all CA descriptors. - ///< The return value tells whether these CA descriptors are to be used - ///< for the individual streams. + +int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids); + ///< Gets all CA pids for a given channel. + ///< Copies all available CA pids from the CA descriptors for the given Source, Transponder and ServiceId + ///< into the provided buffer at Pids (at most BufSize - 1 entries, the list will be zero-terminated). + ///< Only the CA pids of those CA descriptors are copied that match one of the given CA system IDs. + ///< Returns the number of pids copied into Pids (0 if no CA descriptors are + ///< available), or -1 if BufSize was too small to hold all CA pids. #endif //__PAT_H diff --git a/receiver.c b/receiver.c index bde60e46..de5d0aea 100644 --- a/receiver.c +++ b/receiver.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: receiver.c 2.7 2012/06/02 13:20:38 kls Exp $ + * $Id: receiver.c 3.1 2014/01/01 12:03:00 kls Exp $ */ #include "receiver.h" @@ -72,6 +72,28 @@ bool cReceiver::SetPids(const cChannel *Channel) return true; } +void cReceiver::DelPid(int Pid) +{ + if (Pid) { + for (int i = 0; i < numPids; i++) { + if (pids[i] == Pid) { + for ( ; i < numPids; i++) // we also copy the terminating 0! + pids[i] = pids[i + 1]; + numPids--; + return; + } + } + } +} + +void cReceiver::DelPids(const int *Pids) +{ + if (Pids) { + while (*Pids) + DelPid(*Pids++); + } +} + bool cReceiver::WantsPid(int Pid) { if (Pid) { diff --git a/receiver.h b/receiver.h index 775dabdf..8d6fee66 100644 --- a/receiver.h +++ b/receiver.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: receiver.h 2.9 2012/09/02 09:27:20 kls Exp $ + * $Id: receiver.h 3.1 2014/01/01 11:45:09 kls Exp $ */ #ifndef __RECEIVER_H @@ -64,7 +64,13 @@ public: ///< through ChannelID(). The ChannelID is necessary to allow the device ///< that will be used for this receiver to detect and store whether the ///< channel can be decrypted in case this is an encrypted channel. + void DelPid(int Pid); + ///< Deletes the given Pid from the list of PIDs of this receiver. + void DelPids(const int *Pids); + ///< Deletes the given zero terminated list of Pids from the list of PIDs of this + ///< receiver. tChannelID ChannelID(void) { return channelID; } + int NumPids(void) const { return numPids; } bool IsAttached(void) { return device != NULL; } ///< Returns true if this receiver is (still) attached to a device. ///< A receiver may be automatically detached from its device in