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
|
- Added a short sleep to cTSBuffer::Action() to avoid high CPU usage (thanks to
|
||||||
Sergey Chernyavskiy).
|
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).
|
- Added 'S3W ABS-3A' to sources.conf (thanks to Frank Richter).
|
||||||
- Fixed a possible deadlock in the recordings handler thread.
|
- Fixed a possible deadlock in the recordings handler thread.
|
||||||
@ -8900,3 +8900,13 @@ Video Disk Recorder Revision History
|
|||||||
forward/rewind.
|
forward/rewind.
|
||||||
- Changed 'unsigned' to 'signed' in some places to avoid trouble with abs() in
|
- Changed 'unsigned' to 'signed' in some places to avoid trouble with abs() in
|
||||||
gcc6+ (reported by Derek Kelly).
|
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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "ci.h"
|
||||||
@ -1731,11 +1731,12 @@ void cCiAdapter::Action(void)
|
|||||||
#define MODULE_CHECK_INTERVAL 500 // ms
|
#define MODULE_CHECK_INTERVAL 500 // ms
|
||||||
#define MODULE_RESET_TIMEOUT 2 // s
|
#define MODULE_RESET_TIMEOUT 2 // s
|
||||||
|
|
||||||
cCamSlot::cCamSlot(cCiAdapter *CiAdapter, bool ReceiveCaPids)
|
cCamSlot::cCamSlot(cCiAdapter *CiAdapter, bool WantsTsData, cCamSlot *MasterSlot)
|
||||||
{
|
{
|
||||||
ciAdapter = CiAdapter;
|
ciAdapter = CiAdapter;
|
||||||
|
masterSlot = MasterSlot;
|
||||||
assignedDevice = NULL;
|
assignedDevice = NULL;
|
||||||
caPidReceiver = ReceiveCaPids ? new cCaPidReceiver : NULL;
|
caPidReceiver = WantsTsData ? new cCaPidReceiver : NULL;
|
||||||
caActivationReceiver = NULL;
|
caActivationReceiver = NULL;
|
||||||
slotIndex = -1;
|
slotIndex = -1;
|
||||||
lastModuleStatus = msReset; // avoids initial reset log message
|
lastModuleStatus = msReset; // avoids initial reset log message
|
||||||
@ -2227,10 +2228,21 @@ uchar *cCamSlot::Decrypt(uchar *Data, int &Count)
|
|||||||
|
|
||||||
cCamSlots CamSlots;
|
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 cCamSlots::WaitForAllCamSlotsReady(int Timeout)
|
||||||
{
|
{
|
||||||
|
bool ready = true;
|
||||||
for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
|
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)) {
|
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
|
||||||
if (!CamSlot->Ready()) {
|
if (!CamSlot->Ready()) {
|
||||||
ready = false;
|
ready = false;
|
||||||
@ -2238,9 +2250,11 @@ bool cCamSlots::WaitForAllCamSlotsReady(int Timeout)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ready)
|
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 ---------------------------------------------------
|
// --- cChannelCamRelation ---------------------------------------------------
|
||||||
|
32
ci.h
32
ci.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __CI_H
|
||||||
@ -16,7 +16,7 @@
|
|||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "tools.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 MAX_CONNECTIONS_PER_CAM_SLOT 8 // maximum possible value is 254
|
||||||
#define CAM_READ_TIMEOUT 50 // ms
|
#define CAM_READ_TIMEOUT 50 // ms
|
||||||
|
|
||||||
@ -132,6 +132,7 @@ private:
|
|||||||
cMutex mutex;
|
cMutex mutex;
|
||||||
cCondVar processed;
|
cCondVar processed;
|
||||||
cCiAdapter *ciAdapter;
|
cCiAdapter *ciAdapter;
|
||||||
|
cCamSlot *masterSlot;
|
||||||
cDevice *assignedDevice;
|
cDevice *assignedDevice;
|
||||||
cCaPidReceiver *caPidReceiver;
|
cCaPidReceiver *caPidReceiver;
|
||||||
cCaActivationReceiver *caActivationReceiver;
|
cCaActivationReceiver *caActivationReceiver;
|
||||||
@ -153,15 +154,28 @@ private:
|
|||||||
void Write(cTPDU *TPDU);
|
void Write(cTPDU *TPDU);
|
||||||
cCiSession *GetSessionByResourceId(uint32_t ResourceId);
|
cCiSession *GetSessionByResourceId(uint32_t ResourceId);
|
||||||
public:
|
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.
|
///< Creates a new CAM slot for the given CiAdapter.
|
||||||
///< The CiAdapter will take care of deleting the CAM slot,
|
///< The CiAdapter will take care of deleting the CAM slot,
|
||||||
///< so the caller must not delete it!
|
///< so the caller must not delete it!
|
||||||
///< If WantsTsData is true, the device this CAM slot is assigned to will
|
///< 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
|
///< call the Decrypt() function of this CAM slot, presenting it the complete
|
||||||
///< TS data stream of the encrypted programme, including the CA pids.
|
///< 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();
|
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.
|
///< 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
|
///< 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.
|
///< 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
|
///< device it was previously assigned to. The value of Query
|
||||||
///< is ignored in that case, and this function always returns
|
///< is ignored in that case, and this function always returns
|
||||||
///< 'true'.
|
///< '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; }
|
cDevice *Device(void) { return assignedDevice; }
|
||||||
///< Returns the device this CAM slot is currently assigned to.
|
///< Returns the device this CAM slot is currently assigned to.
|
||||||
bool WantsTsData(void) const { return caPidReceiver != NULL; }
|
bool WantsTsData(void) const { return caPidReceiver != NULL; }
|
||||||
@ -181,6 +199,9 @@ public:
|
|||||||
int SlotNumber(void) { return slotNumber; }
|
int SlotNumber(void) { return slotNumber; }
|
||||||
///< Returns the number of this CAM slot within the whole system.
|
///< Returns the number of this CAM slot within the whole system.
|
||||||
///< The first slot has the number 1.
|
///< 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);
|
virtual bool Reset(void);
|
||||||
///< Resets the CAM in this slot.
|
///< Resets the CAM in this slot.
|
||||||
///< Returns true if the operation was successful.
|
///< Returns true if the operation was successful.
|
||||||
@ -295,6 +316,9 @@ public:
|
|||||||
|
|
||||||
class cCamSlots : public cList<cCamSlot> {
|
class cCamSlots : public cList<cCamSlot> {
|
||||||
public:
|
public:
|
||||||
|
int NumReadyMasterSlots(void);
|
||||||
|
///< Returns the number of master CAM slots in the system that are ready
|
||||||
|
///< to decrypt.
|
||||||
bool WaitForAllCamSlotsReady(int Timeout = 0);
|
bool WaitForAllCamSlotsReady(int Timeout = 0);
|
||||||
///< Waits until all CAM slots have become ready, or the given Timeout
|
///< Waits until all CAM slots have become ready, or the given Timeout
|
||||||
///< (seconds) has expired. While waiting, the Ready() function of each
|
///< (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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#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
|
SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
|
||||||
if (CamSlot->ModuleStatus() == msReady) {
|
if (CamSlot->ModuleStatus() == msReady) {
|
||||||
if (CamSlot->ProvidesCa(Channel->Caids())) {
|
if (CamSlot->ProvidesCa(Channel->Caids())) {
|
||||||
if (!ChannelCamRelations.CamChecked(Channel->GetChannelID(), CamSlot->SlotNumber())) {
|
if (!ChannelCamRelations.CamChecked(Channel->GetChannelID(), CamSlot->MasterSlotNumber())) {
|
||||||
SlotPriority[CamSlot->Index()] = CamSlot->Priority();
|
SlotPriority[CamSlot->Index()] = CamSlot->Priority();
|
||||||
NumUsableSlots++;
|
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 |= 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 |= (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 |= 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
|
imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device
|
||||||
if (imp < Impact) {
|
if (imp < Impact) {
|
||||||
// This device has less impact than any previous one, so we take it.
|
// This device has less impact than any previous one, so we take it.
|
||||||
@ -1590,7 +1590,7 @@ void cDevice::Action(void)
|
|||||||
cCamSlot *cs = NULL;
|
cCamSlot *cs = NULL;
|
||||||
if (startScrambleDetection) {
|
if (startScrambleDetection) {
|
||||||
cs = CamSlot();
|
cs = CamSlot();
|
||||||
CamSlotNumber = cs ? cs->SlotNumber() : 0;
|
CamSlotNumber = cs ? cs->MasterSlotNumber() : 0;
|
||||||
if (CamSlotNumber) {
|
if (CamSlotNumber) {
|
||||||
if (LastScrambledPacket < startScrambleDetection)
|
if (LastScrambledPacket < startScrambleDetection)
|
||||||
LastScrambledPacket = startScrambleDetection;
|
LastScrambledPacket = startScrambleDetection;
|
||||||
@ -1678,10 +1678,10 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
|
|||||||
Unlock();
|
Unlock();
|
||||||
if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
|
if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
|
||||||
camSlot->StartDecrypting();
|
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);
|
startScrambleDetection = time(NULL);
|
||||||
scramblingTimeout = TS_SCRAMBLING_TIMEOUT;
|
scramblingTimeout = TS_SCRAMBLING_TIMEOUT;
|
||||||
bool KnownToDecrypt = ChannelCamRelations.CamDecrypt(Receiver->ChannelID(), camSlot->SlotNumber());
|
bool KnownToDecrypt = ChannelCamRelations.CamDecrypt(Receiver->ChannelID(), camSlot->MasterSlotNumber());
|
||||||
if (KnownToDecrypt)
|
if (KnownToDecrypt)
|
||||||
scramblingTimeout *= 10; // give it time to receive ECM/EMM
|
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);
|
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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "menu.h"
|
||||||
@ -3770,8 +3770,15 @@ bool cMenuSetupCAMItem::Changed(void)
|
|||||||
else if (camSlot->IsActivating())
|
else if (camSlot->IsActivating())
|
||||||
// TRANSLATORS: note the leading blank!
|
// TRANSLATORS: note the leading blank!
|
||||||
Activating = tr(" (activating)");
|
Activating = tr(" (activating)");
|
||||||
if (cDevice *Device = camSlot->Device())
|
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
|
||||||
AssignedDevice = cString::sprintf(" %s %d", tr("@ device"), Device->CardIndex() + 1);
|
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);
|
cString buffer = cString::sprintf(" %d %s%s%s", camSlot->SlotNumber(), CamName, *AssignedDevice, Activating);
|
||||||
if (strcmp(buffer, Text()) != 0) {
|
if (strcmp(buffer, Text()) != 0) {
|
||||||
SetText(buffer);
|
SetText(buffer);
|
||||||
@ -3799,8 +3806,10 @@ cMenuSetupCAM::cMenuSetupCAM(void)
|
|||||||
SetSection(tr("CAM"));
|
SetSection(tr("CAM"));
|
||||||
SetCols(15);
|
SetCols(15);
|
||||||
SetHasHotkeys();
|
SetHasHotkeys();
|
||||||
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot))
|
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
|
||||||
Add(new cMenuSetupCAMItem(CamSlot));
|
if (CamSlot->IsMasterSlot()) // we only list master CAM slots
|
||||||
|
Add(new cMenuSetupCAMItem(CamSlot));
|
||||||
|
}
|
||||||
SetHelpKeys();
|
SetHelpKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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,
|
// "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;
|
LastDeviceType = DeviceType;
|
||||||
// CAM:
|
// CAM:
|
||||||
if (CamSlot) {
|
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);
|
Osd->DrawText(x, y1 - TinyFont->Height(), s, ColorFg, ColorBg, TinyFont);
|
||||||
xs = max(xs, x + TinyFont->Width(s));
|
xs = max(xs, x + TinyFont->Width(s));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user