summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY12
-rw-r--r--ci.c26
-rw-r--r--ci.h32
-rw-r--r--device.c12
-rw-r--r--menu.c19
-rw-r--r--skinlcars.c4
6 files changed, 81 insertions, 24 deletions
diff --git a/HISTORY b/HISTORY
index 8e32be5b..50ba2162 100644
--- a/HISTORY
+++ b/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.
diff --git a/ci.c b/ci.c
index fd3acd84..1096721b 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 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 ---------------------------------------------------
diff --git a/ci.h b/ci.h
index c61599e5..a66cd2a2 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 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
diff --git a/device.c b/device.c
index 9bb00b42..2b350e86 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 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);
diff --git a/menu.c b/menu.c
index f784d16f..642432ac 100644
--- a/menu.c
+++ b/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();
}
diff --git a/skinlcars.c b/skinlcars.c
index 0fae3b85..93ada5ee 100644
--- a/skinlcars.c
+++ b/skinlcars.c
@@ -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));
}