mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented the concept of 'master cams'
This commit is contained in:
parent
6121095a30
commit
9b9d15438e
12
HISTORY
12
HISTORY
@ -8882,7 +8882,7 @@ Video Disk Recorder Revision History
|
||||
- Added a short sleep to cTSBuffer::Action() to avoid high CPU usage (thanks to
|
||||
Sergey Chernyavskiy).
|
||||
|
||||
2017-01-09: Version 2.3.3
|
||||
2017-01-23: Version 2.3.3
|
||||
|
||||
- Added 'S3W ABS-3A' to sources.conf (thanks to Frank Richter).
|
||||
- Fixed a possible deadlock in the recordings handler thread.
|
||||
@ -8900,3 +8900,13 @@ Video Disk Recorder Revision History
|
||||
forward/rewind.
|
||||
- Changed 'unsigned' to 'signed' in some places to avoid trouble with abs() in
|
||||
gcc6+ (reported by Derek Kelly).
|
||||
- CAMs that can handle multiple devices at the same time can now indicate this
|
||||
by creating the first cCamSlot as usual, and every other cCamSlot by giving
|
||||
it the first one as its "MasterSlot". To VDR this means that when searching
|
||||
for a CAM that can decrypt a particular channel, it only needs to ask the
|
||||
master CAM slot whether it is suitable for decrypting, and can skip all the
|
||||
other slots belonging to the same master. This can greatly speed up channel
|
||||
switching on systems with more than one CAM (that can handle multiple devices).
|
||||
- The LCARS skin now displays the master CAM's number when a device is tuned to
|
||||
an encrypted channel.
|
||||
- The Setup/CAM menu now only displays master CAMs.
|
||||
|
26
ci.c
26
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 4.4 2017/01/09 12:51:05 kls Exp $
|
||||
* $Id: ci.c 4.5 2017/01/23 11:42:14 kls Exp $
|
||||
*/
|
||||
|
||||
#include "ci.h"
|
||||
@ -1731,11 +1731,12 @@ void cCiAdapter::Action(void)
|
||||
#define MODULE_CHECK_INTERVAL 500 // ms
|
||||
#define MODULE_RESET_TIMEOUT 2 // s
|
||||
|
||||
cCamSlot::cCamSlot(cCiAdapter *CiAdapter, bool ReceiveCaPids)
|
||||
cCamSlot::cCamSlot(cCiAdapter *CiAdapter, bool WantsTsData, cCamSlot *MasterSlot)
|
||||
{
|
||||
ciAdapter = CiAdapter;
|
||||
masterSlot = MasterSlot;
|
||||
assignedDevice = NULL;
|
||||
caPidReceiver = ReceiveCaPids ? new cCaPidReceiver : NULL;
|
||||
caPidReceiver = WantsTsData ? new cCaPidReceiver : NULL;
|
||||
caActivationReceiver = NULL;
|
||||
slotIndex = -1;
|
||||
lastModuleStatus = msReset; // avoids initial reset log message
|
||||
@ -2227,10 +2228,21 @@ uchar *cCamSlot::Decrypt(uchar *Data, int &Count)
|
||||
|
||||
cCamSlots CamSlots;
|
||||
|
||||
int cCamSlots::NumReadyMasterSlots(void)
|
||||
{
|
||||
int n = 0;
|
||||
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
|
||||
if (CamSlot->IsMasterSlot() && CamSlot->ModuleStatus() == msReady)
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
bool cCamSlots::WaitForAllCamSlotsReady(int Timeout)
|
||||
{
|
||||
bool ready = true;
|
||||
for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
|
||||
bool ready = true;
|
||||
ready = true;
|
||||
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
|
||||
if (!CamSlot->Ready()) {
|
||||
ready = false;
|
||||
@ -2238,9 +2250,11 @@ bool cCamSlots::WaitForAllCamSlotsReady(int Timeout)
|
||||
}
|
||||
}
|
||||
if (ready)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot))
|
||||
dsyslog("CAM %d: %sready, %s", CamSlot->SlotNumber(), CamSlot->Ready() ? "" : "not ", CamSlot->IsMasterSlot() ? *cString::sprintf("master (%s)", CamSlot->GetCamName() ? CamSlot->GetCamName() : "empty") : *cString::sprintf("slave of CAM %d", CamSlot->MasterSlotNumber()));
|
||||
return ready;
|
||||
}
|
||||
|
||||
// --- cChannelCamRelation ---------------------------------------------------
|
||||
|
32
ci.h
32
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 4.1 2017/01/09 12:51:05 kls Exp $
|
||||
* $Id: ci.h 4.2 2017/01/23 11:27:39 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __CI_H
|
||||
@ -16,7 +16,7 @@
|
||||
#include "thread.h"
|
||||
#include "tools.h"
|
||||
|
||||
#define MAX_CAM_SLOTS_PER_ADAPTER 8 // maximum possible value is 255
|
||||
#define MAX_CAM_SLOTS_PER_ADAPTER 16 // maximum possible value is 255 (same value as MAXDEVICES!)
|
||||
#define MAX_CONNECTIONS_PER_CAM_SLOT 8 // maximum possible value is 254
|
||||
#define CAM_READ_TIMEOUT 50 // ms
|
||||
|
||||
@ -132,6 +132,7 @@ private:
|
||||
cMutex mutex;
|
||||
cCondVar processed;
|
||||
cCiAdapter *ciAdapter;
|
||||
cCamSlot *masterSlot;
|
||||
cDevice *assignedDevice;
|
||||
cCaPidReceiver *caPidReceiver;
|
||||
cCaActivationReceiver *caActivationReceiver;
|
||||
@ -153,15 +154,28 @@ private:
|
||||
void Write(cTPDU *TPDU);
|
||||
cCiSession *GetSessionByResourceId(uint32_t ResourceId);
|
||||
public:
|
||||
cCamSlot(cCiAdapter *CiAdapter, bool WantsTsData = false);
|
||||
cCamSlot(cCiAdapter *CiAdapter, bool WantsTsData = false, cCamSlot *MasterSlot = NULL);
|
||||
///< 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 WantsTsData is true, the device this CAM slot is assigned to will
|
||||
///< call the Decrypt() function of this CAM slot, presenting it the complete
|
||||
///< TS data stream of the encrypted programme, including the CA pids.
|
||||
///< If this CAM slot is basically the same as an other one, MasterSlot can
|
||||
///< be given to indicate this. This can be used for instance for CAM slots
|
||||
///< that can do MTD ("Multi Transponder Decryption"), where the first cCamSlot
|
||||
///< is created without giving a MasterSlot, and all others are given the first
|
||||
///< one as their MasterSlot. This can speed up the search for a suitable CAM
|
||||
///< when tuning to an encrypted channel, and it also makes the Setup/CAM menu
|
||||
///< clearer because only the master CAM slots will be shown there.
|
||||
virtual ~cCamSlot();
|
||||
bool Assign(cDevice *Device, bool Query = false);
|
||||
bool IsMasterSlot(void) { return !masterSlot; }
|
||||
///< Returns true if this CAM slot itself is a master slot (which means that
|
||||
///< it doesn't have pointer to another CAM slot that's its master).
|
||||
cCamSlot *MasterSlot(void) { return masterSlot ? masterSlot : this; }
|
||||
///< Returns this CAM slot's master slot, or a pointer to itself if it is a
|
||||
///< master slot.
|
||||
virtual bool Assign(cDevice *Device, bool Query = false);
|
||||
///< Assigns this CAM slot to the given Device, if this is possible.
|
||||
///< If Query is 'true', the CI adapter of this slot only checks whether
|
||||
///< it can be assigned to the Device, but doesn't actually assign itself to it.
|
||||
@ -170,6 +184,10 @@ public:
|
||||
///< device it was previously assigned to. The value of Query
|
||||
///< is ignored in that case, and this function always returns
|
||||
///< 'true'.
|
||||
///< If a derived class reimplements this function, it can return 'false'
|
||||
///< if this CAM can't be assigned to the given Device. If the CAM can be
|
||||
///< assigned to the Device, or if Device is NULL, it must call the base
|
||||
///< class function.
|
||||
cDevice *Device(void) { return assignedDevice; }
|
||||
///< Returns the device this CAM slot is currently assigned to.
|
||||
bool WantsTsData(void) const { return caPidReceiver != NULL; }
|
||||
@ -181,6 +199,9 @@ public:
|
||||
int SlotNumber(void) { return slotNumber; }
|
||||
///< Returns the number of this CAM slot within the whole system.
|
||||
///< The first slot has the number 1.
|
||||
int MasterSlotNumber(void) { return masterSlot ? masterSlot->SlotNumber() : slotNumber; }
|
||||
///< Returns the number of this CAM's master slot within the whole system.
|
||||
///< The first slot has the number 1.
|
||||
virtual bool Reset(void);
|
||||
///< Resets the CAM in this slot.
|
||||
///< Returns true if the operation was successful.
|
||||
@ -295,6 +316,9 @@ public:
|
||||
|
||||
class cCamSlots : public cList<cCamSlot> {
|
||||
public:
|
||||
int NumReadyMasterSlots(void);
|
||||
///< Returns the number of master CAM slots in the system that are ready
|
||||
///< to decrypt.
|
||||
bool WaitForAllCamSlotsReady(int Timeout = 0);
|
||||
///< Waits until all CAM slots have become ready, or the given Timeout
|
||||
///< (seconds) has expired. While waiting, the Ready() function of each
|
||||
|
12
device.c
12
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 4.5 2017/01/09 14:25:38 kls Exp $
|
||||
* $Id: device.c 4.6 2017/01/23 11:43:05 kls Exp $
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
@ -252,7 +252,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView
|
||||
SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
|
||||
if (CamSlot->ModuleStatus() == msReady) {
|
||||
if (CamSlot->ProvidesCa(Channel->Caids())) {
|
||||
if (!ChannelCamRelations.CamChecked(Channel->GetChannelID(), CamSlot->SlotNumber())) {
|
||||
if (!ChannelCamRelations.CamChecked(Channel->GetChannelID(), CamSlot->MasterSlotNumber())) {
|
||||
SlotPriority[CamSlot->Index()] = CamSlot->Priority();
|
||||
NumUsableSlots++;
|
||||
}
|
||||
@ -300,7 +300,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView
|
||||
imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
|
||||
imp <<= 1; imp |= (NumUsableSlots || InternalCamNeeded) ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
|
||||
imp <<= 1; imp |= device[i]->AvoidRecording(); // avoid SD full featured cards
|
||||
imp <<= 1; imp |= (NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
|
||||
imp <<= 1; imp |= (NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) : 0; // prefer CAMs that are known to decrypt this channel
|
||||
imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device
|
||||
if (imp < Impact) {
|
||||
// This device has less impact than any previous one, so we take it.
|
||||
@ -1590,7 +1590,7 @@ void cDevice::Action(void)
|
||||
cCamSlot *cs = NULL;
|
||||
if (startScrambleDetection) {
|
||||
cs = CamSlot();
|
||||
CamSlotNumber = cs ? cs->SlotNumber() : 0;
|
||||
CamSlotNumber = cs ? cs->MasterSlotNumber() : 0;
|
||||
if (CamSlotNumber) {
|
||||
if (LastScrambledPacket < startScrambleDetection)
|
||||
LastScrambledPacket = startScrambleDetection;
|
||||
@ -1678,10 +1678,10 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
|
||||
Unlock();
|
||||
if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
|
||||
camSlot->StartDecrypting();
|
||||
if (CamSlots.Count() > 1) { // don't try different CAMs if there is only one
|
||||
if (CamSlots.NumReadyMasterSlots() > 1) { // don't try different CAMs if there is only one
|
||||
startScrambleDetection = time(NULL);
|
||||
scramblingTimeout = TS_SCRAMBLING_TIMEOUT;
|
||||
bool KnownToDecrypt = ChannelCamRelations.CamDecrypt(Receiver->ChannelID(), camSlot->SlotNumber());
|
||||
bool KnownToDecrypt = ChannelCamRelations.CamDecrypt(Receiver->ChannelID(), camSlot->MasterSlotNumber());
|
||||
if (KnownToDecrypt)
|
||||
scramblingTimeout *= 10; // give it time to receive ECM/EMM
|
||||
dsyslog("CAM %d: %sknown to decrypt channel %s (scramblingTimeout = %ds)", camSlot->SlotNumber(), KnownToDecrypt ? "" : "not ", *Receiver->ChannelID().ToString(), scramblingTimeout);
|
||||
|
19
menu.c
19
menu.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: menu.c 4.20 2017/01/09 14:45:50 kls Exp $
|
||||
* $Id: menu.c 4.21 2017/01/23 12:01:48 kls Exp $
|
||||
*/
|
||||
|
||||
#include "menu.h"
|
||||
@ -3770,8 +3770,15 @@ bool cMenuSetupCAMItem::Changed(void)
|
||||
else if (camSlot->IsActivating())
|
||||
// TRANSLATORS: note the leading blank!
|
||||
Activating = tr(" (activating)");
|
||||
if (cDevice *Device = camSlot->Device())
|
||||
AssignedDevice = cString::sprintf(" %s %d", tr("@ device"), Device->CardIndex() + 1);
|
||||
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
|
||||
if (CamSlot == camSlot || CamSlot->MasterSlot() == camSlot) {
|
||||
if (cDevice *Device = CamSlot->Device()) {
|
||||
if (!**AssignedDevice)
|
||||
AssignedDevice = cString::sprintf(" %s", tr("@ device"));
|
||||
AssignedDevice = cString::sprintf("%s %d", *AssignedDevice, Device->CardIndex() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
cString buffer = cString::sprintf(" %d %s%s%s", camSlot->SlotNumber(), CamName, *AssignedDevice, Activating);
|
||||
if (strcmp(buffer, Text()) != 0) {
|
||||
SetText(buffer);
|
||||
@ -3799,8 +3806,10 @@ cMenuSetupCAM::cMenuSetupCAM(void)
|
||||
SetSection(tr("CAM"));
|
||||
SetCols(15);
|
||||
SetHasHotkeys();
|
||||
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot))
|
||||
Add(new cMenuSetupCAMItem(CamSlot));
|
||||
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
|
||||
if (CamSlot->IsMasterSlot()) // we only list master CAM slots
|
||||
Add(new cMenuSetupCAMItem(CamSlot));
|
||||
}
|
||||
SetHelpKeys();
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: skinlcars.c 4.2 2016/12/22 14:05:56 kls Exp $
|
||||
* $Id: skinlcars.c 4.3 2017/01/19 15:27:48 kls Exp $
|
||||
*/
|
||||
|
||||
// "Star Trek: The Next Generation"(R) is a registered trademark of Paramount Pictures,
|
||||
@ -254,7 +254,7 @@ static bool DrawDeviceData(cOsd *Osd, const cDevice *Device, int x0, int y0, int
|
||||
LastDeviceType = DeviceType;
|
||||
// CAM:
|
||||
if (CamSlot) {
|
||||
cString s = cString::sprintf("CAM %d", CamSlot->SlotNumber());
|
||||
cString s = cString::sprintf("CAM %d", CamSlot->MasterSlotNumber());
|
||||
Osd->DrawText(x, y1 - TinyFont->Height(), s, ColorFg, ColorBg, TinyFont);
|
||||
xs = max(xs, x + TinyFont->Width(s));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user