mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented handling of the "CA PMT Reply" for CAMs; some preparations for being able to record several encrypted channels from the same transponder
This commit is contained in:
parent
2fecf43be9
commit
3a97be4fe9
@ -1249,6 +1249,7 @@ Marco Schl
|
|||||||
for fixing a race condition in the SPU decoder
|
for fixing a race condition in the SPU decoder
|
||||||
for fixing initializing the day index when editing the weekday parameter of a
|
for fixing initializing the day index when editing the weekday parameter of a
|
||||||
repeating timer
|
repeating timer
|
||||||
|
for figuring out some obscure length bytes the the CA PMT Reply data of AlphaCrypt CAMs
|
||||||
|
|
||||||
Jürgen Schmitz <j.schmitz@web.de>
|
Jürgen Schmitz <j.schmitz@web.de>
|
||||||
for reporting a bug in displaying the current channel when switching via the SVDRP
|
for reporting a bug in displaying the current channel when switching via the SVDRP
|
||||||
|
9
HISTORY
9
HISTORY
@ -3934,7 +3934,7 @@ Video Disk Recorder Revision History
|
|||||||
layers of subdirectories.
|
layers of subdirectories.
|
||||||
- Removed EPG bugfix #0, because it removed actually important data.
|
- Removed EPG bugfix #0, because it removed actually important data.
|
||||||
|
|
||||||
2005-11-11: Version 1.3.37
|
2005-11-26: Version 1.3.37
|
||||||
|
|
||||||
- Added compiler options "-fPIC -g" to all plugins (thanks to Rolf Ahrenberg).
|
- Added compiler options "-fPIC -g" to all plugins (thanks to Rolf Ahrenberg).
|
||||||
- Fixed initializing the day index when editing the weekday parameter of a
|
- Fixed initializing the day index when editing the weekday parameter of a
|
||||||
@ -3946,3 +3946,10 @@ Video Disk Recorder Revision History
|
|||||||
to Werner Fink). Live DD mode requires a full featured DVB card and a
|
to Werner Fink). Live DD mode requires a full featured DVB card and a
|
||||||
LinuxDVB driver with firmware version 0x2622 or higher. Older versions will
|
LinuxDVB driver with firmware version 0x2622 or higher. Older versions will
|
||||||
use Transfer Mode just like before.
|
use Transfer Mode just like before.
|
||||||
|
- Implemented handling of the "CA PMT Reply" for CAMs (thanks to Marco
|
||||||
|
Schlüßler for figuring out some obscure length bytes in the CA PMT Reply
|
||||||
|
data of AlphaCrypt CAMs).
|
||||||
|
- Some preparations for being able to record several encrypted channels from
|
||||||
|
the same transponder at the same time (or record and view different encrypted
|
||||||
|
channels), provided the CAM in use can handle this. This is work in progress
|
||||||
|
and isn't actively used, yet.
|
||||||
|
400
ci.c
400
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 1.39 2005/11/04 14:18:52 kls Exp $
|
* $Id: ci.c 1.40 2005/11/26 13:36:51 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ci.h"
|
#include "ci.h"
|
||||||
@ -845,10 +845,118 @@ bool cCiApplicationInformation::EnterMenu(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- cCiCaPmt --------------------------------------------------------------
|
||||||
|
|
||||||
|
// Ca Pmt List Management:
|
||||||
|
|
||||||
|
#define CPLM_MORE 0x00
|
||||||
|
#define CPLM_FIRST 0x01
|
||||||
|
#define CPLM_LAST 0x02
|
||||||
|
#define CPLM_ONLY 0x03
|
||||||
|
#define CPLM_ADD 0x04
|
||||||
|
#define CPLM_UPDATE 0x05
|
||||||
|
|
||||||
|
// Ca Pmt Cmd Ids:
|
||||||
|
|
||||||
|
#define CPCI_OK_DESCRAMBLING 0x01
|
||||||
|
#define CPCI_OK_MMI 0x02
|
||||||
|
#define CPCI_QUERY 0x03
|
||||||
|
#define CPCI_NOT_SELECTED 0x04
|
||||||
|
|
||||||
|
class cCiCaPmt : public cListObject {
|
||||||
|
friend class cCiConditionalAccessSupport;
|
||||||
|
private:
|
||||||
|
uint8_t cmdId;
|
||||||
|
int length;
|
||||||
|
int esInfoLengthPos;
|
||||||
|
uint8_t capmt[2048]; ///< XXX is there a specified maximum?
|
||||||
|
int caDescriptorsLength;
|
||||||
|
uint8_t caDescriptors[2048];
|
||||||
|
bool streamFlag;
|
||||||
|
void AddCaDescriptors(int Length, const uint8_t *Data);
|
||||||
|
public:
|
||||||
|
cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const unsigned short *CaSystemIds);
|
||||||
|
void SetListManagement(uint8_t ListManagement);
|
||||||
|
bool Valid(void);
|
||||||
|
void AddPid(int Pid, uint8_t StreamType);
|
||||||
|
};
|
||||||
|
|
||||||
|
cCiCaPmt::cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const unsigned short *CaSystemIds)
|
||||||
|
{
|
||||||
|
cmdId = CmdId;
|
||||||
|
caDescriptorsLength = GetCaDescriptors(Source, Transponder, ProgramNumber, CaSystemIds, sizeof(caDescriptors), caDescriptors, streamFlag);
|
||||||
|
length = 0;
|
||||||
|
capmt[length++] = CPLM_ONLY;
|
||||||
|
capmt[length++] = (ProgramNumber >> 8) & 0xFF;
|
||||||
|
capmt[length++] = ProgramNumber & 0xFF;
|
||||||
|
capmt[length++] = 0x01; // version_number, current_next_indicator - apparently vn doesn't matter, but cni must be 1
|
||||||
|
esInfoLengthPos = length;
|
||||||
|
capmt[length++] = 0x00; // program_info_length H (at program level)
|
||||||
|
capmt[length++] = 0x00; // program_info_length L
|
||||||
|
if (!streamFlag)
|
||||||
|
AddCaDescriptors(caDescriptorsLength, caDescriptors);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCiCaPmt::SetListManagement(uint8_t ListManagement)
|
||||||
|
{
|
||||||
|
capmt[0] = ListManagement;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cCiCaPmt::Valid(void)
|
||||||
|
{
|
||||||
|
return caDescriptorsLength > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCiCaPmt::AddPid(int Pid, uint8_t StreamType)
|
||||||
|
{
|
||||||
|
if (Pid) {
|
||||||
|
//XXX buffer overflow check???
|
||||||
|
capmt[length++] = StreamType;
|
||||||
|
capmt[length++] = (Pid >> 8) & 0xFF;
|
||||||
|
capmt[length++] = Pid & 0xFF;
|
||||||
|
esInfoLengthPos = length;
|
||||||
|
capmt[length++] = 0x00; // ES_info_length H (at ES level)
|
||||||
|
capmt[length++] = 0x00; // ES_info_length L
|
||||||
|
if (streamFlag)
|
||||||
|
AddCaDescriptors(caDescriptorsLength, caDescriptors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCiCaPmt::AddCaDescriptors(int Length, const uint8_t *Data)
|
||||||
|
{
|
||||||
|
if (esInfoLengthPos) {
|
||||||
|
if (length + Length < int(sizeof(capmt))) {
|
||||||
|
capmt[length++] = cmdId;
|
||||||
|
memcpy(capmt + length, Data, Length);
|
||||||
|
length += Length;
|
||||||
|
int l = length - esInfoLengthPos - 2;
|
||||||
|
capmt[esInfoLengthPos] = (l >> 8) & 0xFF;
|
||||||
|
capmt[esInfoLengthPos + 1] = l & 0xFF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: buffer overflow in CA descriptor");
|
||||||
|
esInfoLengthPos = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: adding CA descriptor without Pid!");
|
||||||
|
}
|
||||||
|
|
||||||
// --- cCiConditionalAccessSupport -------------------------------------------
|
// --- cCiConditionalAccessSupport -------------------------------------------
|
||||||
|
|
||||||
#define MAXCASYSTEMIDS 16
|
#define MAXCASYSTEMIDS 16
|
||||||
|
|
||||||
|
// CA Enable Ids:
|
||||||
|
|
||||||
|
#define CAEI_POSSIBLE 0x01
|
||||||
|
#define CAEI_POSSIBLE_COND_PURCHASE 0x02
|
||||||
|
#define CAEI_POSSIBLE_COND_TECHNICAL 0x03
|
||||||
|
#define CAEI_NOT_POSSIBLE_ENTITLEMENT 0x71
|
||||||
|
#define CAEI_NOT_POSSIBLE_TECHNICAL 0x73
|
||||||
|
|
||||||
|
#define CA_ENABLE_FLAG 0x80
|
||||||
|
|
||||||
|
#define CA_ENABLE(x) (((x) & CA_ENABLE_FLAG) ? (x) & ~CA_ENABLE_FLAG : 0)
|
||||||
|
|
||||||
class cCiConditionalAccessSupport : public cCiSession {
|
class cCiConditionalAccessSupport : public cCiSession {
|
||||||
private:
|
private:
|
||||||
int state;
|
int state;
|
||||||
@ -858,14 +966,15 @@ public:
|
|||||||
cCiConditionalAccessSupport(int SessionId, cCiTransportConnection *Tc);
|
cCiConditionalAccessSupport(int SessionId, cCiTransportConnection *Tc);
|
||||||
virtual bool Process(int Length = 0, const uint8_t *Data = NULL);
|
virtual bool Process(int Length = 0, const uint8_t *Data = NULL);
|
||||||
const unsigned short *GetCaSystemIds(void) { return caSystemIds; }
|
const unsigned short *GetCaSystemIds(void) { return caSystemIds; }
|
||||||
bool SendPMT(cCiCaPmt &CaPmt);
|
bool SendPMT(cCiCaPmt *CaPmt);
|
||||||
|
bool ReceivedReply(bool CanDescramble = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
cCiConditionalAccessSupport::cCiConditionalAccessSupport(int SessionId, cCiTransportConnection *Tc)
|
cCiConditionalAccessSupport::cCiConditionalAccessSupport(int SessionId, cCiTransportConnection *Tc)
|
||||||
:cCiSession(SessionId, RI_CONDITIONAL_ACCESS_SUPPORT, Tc)
|
:cCiSession(SessionId, RI_CONDITIONAL_ACCESS_SUPPORT, Tc)
|
||||||
{
|
{
|
||||||
dbgprotocol("New Conditional Access Support (session id %d)\n", SessionId);
|
dbgprotocol("New Conditional Access Support (session id %d)\n", SessionId);
|
||||||
state = 0;
|
state = 0; // inactive
|
||||||
caSystemIds[numCaSystemIds = 0] = 0;
|
caSystemIds[numCaSystemIds = 0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -892,7 +1001,58 @@ bool cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
|
|||||||
}
|
}
|
||||||
dbgprotocol("\n");
|
dbgprotocol("\n");
|
||||||
}
|
}
|
||||||
state = 2;
|
state = 2; // got ca info
|
||||||
|
break;
|
||||||
|
case AOT_CA_PMT_REPLY: {
|
||||||
|
dbgprotocol("%d: <== Ca Pmt Reply", SessionId());
|
||||||
|
state = 4; // got ca pmt reply
|
||||||
|
int l = 0;
|
||||||
|
const uint8_t *d = GetData(Data, l);
|
||||||
|
if (l > 1) {
|
||||||
|
unsigned short pnr = ((unsigned short)(*d) << 8) | *(d + 1);
|
||||||
|
dbgprotocol(" %d", pnr);
|
||||||
|
d += 2;
|
||||||
|
l -= 2;
|
||||||
|
if (l > 0) {
|
||||||
|
dbgprotocol(" %02X", *d);
|
||||||
|
d += 1;
|
||||||
|
l -= 1;
|
||||||
|
if (l > 0) {
|
||||||
|
if (l % 3 == 0 && l > 1) {
|
||||||
|
// The EN50221 standard defines that the next byte is supposed
|
||||||
|
// to be the CA_enable value at programme level. However, there are
|
||||||
|
// CAMs (for instance the AlphaCrypt with firmware <= 3.05) that
|
||||||
|
// insert a two byte length field here.
|
||||||
|
// This is a workaround to skip this length field:
|
||||||
|
unsigned short len = ((unsigned short)(*d) << 8) | *(d + 1);
|
||||||
|
if (len == l - 2) {
|
||||||
|
d += 2;
|
||||||
|
l -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned char caepl = *d;
|
||||||
|
dbgprotocol(" %02X", caepl);
|
||||||
|
d += 1;
|
||||||
|
l -= 1;
|
||||||
|
bool ok = true;
|
||||||
|
if (l <= 2)
|
||||||
|
ok = CA_ENABLE(caepl) == CAEI_POSSIBLE;
|
||||||
|
while (l > 2) {
|
||||||
|
unsigned short pid = ((unsigned short)(*d) << 8) | *(d + 1);
|
||||||
|
unsigned char caees = *(d + 2);
|
||||||
|
dbgprotocol(" %d=%02X", pid, caees);
|
||||||
|
d += 3;
|
||||||
|
l -= 3;
|
||||||
|
if (CA_ENABLE(caees) != CAEI_POSSIBLE)
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
if (ok)
|
||||||
|
state = 5; // descrambling possible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbgprotocol("\n");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default: esyslog("ERROR: CI conditional access support: unknown tag %06X", Tag);
|
default: esyslog("ERROR: CI conditional access support: unknown tag %06X", Tag);
|
||||||
return false;
|
return false;
|
||||||
@ -901,20 +1061,27 @@ bool cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
|
|||||||
else if (state == 0) {
|
else if (state == 0) {
|
||||||
dbgprotocol("%d: ==> Ca Info Enq\n", SessionId());
|
dbgprotocol("%d: ==> Ca Info Enq\n", SessionId());
|
||||||
SendData(AOT_CA_INFO_ENQ);
|
SendData(AOT_CA_INFO_ENQ);
|
||||||
state = 1;
|
state = 1; // enquired ca info
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cCiConditionalAccessSupport::SendPMT(cCiCaPmt &CaPmt)
|
bool cCiConditionalAccessSupport::SendPMT(cCiCaPmt *CaPmt)
|
||||||
{
|
{
|
||||||
if (state == 2) {
|
if (CaPmt && state >= 2) {
|
||||||
SendData(AOT_CA_PMT, CaPmt.length, CaPmt.capmt);
|
dbgprotocol("%d: ==> Ca Pmt\n", SessionId());
|
||||||
|
SendData(AOT_CA_PMT, CaPmt->length, CaPmt->capmt);
|
||||||
|
state = 3; // sent ca pmt
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cCiConditionalAccessSupport::ReceivedReply(bool CanDescramble)
|
||||||
|
{
|
||||||
|
return state >= (CanDescramble ? 5 : 4);
|
||||||
|
}
|
||||||
|
|
||||||
// --- cCiDateTime -----------------------------------------------------------
|
// --- cCiDateTime -----------------------------------------------------------
|
||||||
|
|
||||||
class cCiDateTime : public cCiSession {
|
class cCiDateTime : public cCiSession {
|
||||||
@ -1307,78 +1474,6 @@ bool cCiEnquiry::Abort(void)
|
|||||||
return mmi && mmi->SendCloseMMI();
|
return mmi && mmi->SendCloseMMI();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cCiCaPmt --------------------------------------------------------------
|
|
||||||
|
|
||||||
// Ca Pmt List Management:
|
|
||||||
|
|
||||||
#define CPLM_MORE 0x00
|
|
||||||
#define CPLM_FIRST 0x01
|
|
||||||
#define CPLM_LAST 0x02
|
|
||||||
#define CPLM_ONLY 0x03
|
|
||||||
#define CPLM_ADD 0x04
|
|
||||||
#define CPLM_UPDATE 0x05
|
|
||||||
|
|
||||||
// Ca Pmt Cmd Ids:
|
|
||||||
|
|
||||||
#define CPCI_OK_DESCRAMBLING 0x01
|
|
||||||
#define CPCI_OK_MMI 0x02
|
|
||||||
#define CPCI_QUERY 0x03
|
|
||||||
#define CPCI_NOT_SELECTED 0x04
|
|
||||||
|
|
||||||
cCiCaPmt::cCiCaPmt(int Source, int Transponder, int ProgramNumber, const unsigned short *CaSystemIds)
|
|
||||||
{
|
|
||||||
caDescriptorsLength = GetCaDescriptors(Source, Transponder, ProgramNumber, CaSystemIds, sizeof(caDescriptors), caDescriptors, streamFlag);
|
|
||||||
length = 0;
|
|
||||||
capmt[length++] = CPLM_ONLY;
|
|
||||||
capmt[length++] = (ProgramNumber >> 8) & 0xFF;
|
|
||||||
capmt[length++] = ProgramNumber & 0xFF;
|
|
||||||
capmt[length++] = 0x01; // version_number, current_next_indicator - apparently vn doesn't matter, but cni must be 1
|
|
||||||
esInfoLengthPos = length;
|
|
||||||
capmt[length++] = 0x00; // program_info_length H (at program level)
|
|
||||||
capmt[length++] = 0x00; // program_info_length L
|
|
||||||
if (!streamFlag)
|
|
||||||
AddCaDescriptors(caDescriptorsLength, caDescriptors);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cCiCaPmt::Valid(void)
|
|
||||||
{
|
|
||||||
return caDescriptorsLength > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cCiCaPmt::AddPid(int Pid, uint8_t StreamType)
|
|
||||||
{
|
|
||||||
if (Pid) {
|
|
||||||
//XXX buffer overflow check???
|
|
||||||
capmt[length++] = StreamType;
|
|
||||||
capmt[length++] = (Pid >> 8) & 0xFF;
|
|
||||||
capmt[length++] = Pid & 0xFF;
|
|
||||||
esInfoLengthPos = length;
|
|
||||||
capmt[length++] = 0x00; // ES_info_length H (at ES level)
|
|
||||||
capmt[length++] = 0x00; // ES_info_length L
|
|
||||||
if (streamFlag)
|
|
||||||
AddCaDescriptors(caDescriptorsLength, caDescriptors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cCiCaPmt::AddCaDescriptors(int Length, const uint8_t *Data)
|
|
||||||
{
|
|
||||||
if (esInfoLengthPos) {
|
|
||||||
if (length + Length < int(sizeof(capmt))) {
|
|
||||||
capmt[length++] = CPCI_OK_DESCRAMBLING;
|
|
||||||
memcpy(capmt + length, Data, Length);
|
|
||||||
length += Length;
|
|
||||||
int l = length - esInfoLengthPos - 2;
|
|
||||||
capmt[esInfoLengthPos] = (l >> 8) & 0xFF;
|
|
||||||
capmt[esInfoLengthPos + 1] = l & 0xFF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
esyslog("ERROR: buffer overflow in CA descriptor");
|
|
||||||
esInfoLengthPos = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
esyslog("ERROR: adding CA descriptor without Pid!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- cCiHandler -------------------------------------------------------------
|
// -- cCiHandler -------------------------------------------------------------
|
||||||
|
|
||||||
cCiHandler::cCiHandler(int Fd, int NumSlots)
|
cCiHandler::cCiHandler(int Fd, int NumSlots)
|
||||||
@ -1393,6 +1488,7 @@ cCiHandler::cCiHandler(int Fd, int NumSlots)
|
|||||||
moduleReady[i] = false;
|
moduleReady[i] = false;
|
||||||
tpl = new cCiTransportLayer(Fd, numSlots);
|
tpl = new cCiTransportLayer(Fd, numSlots);
|
||||||
tc = NULL;
|
tc = NULL;
|
||||||
|
source = transponder = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cCiHandler::~cCiHandler()
|
cCiHandler::~cCiHandler()
|
||||||
@ -1556,12 +1652,13 @@ bool cCiHandler::Ready(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cCiHandler::Process(void)
|
bool cCiHandler::Process(int Slot)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
cMutexLock MutexLock(&mutex);
|
cMutexLock MutexLock(&mutex);
|
||||||
for (int Slot = 0; Slot < numSlots; Slot++) {
|
for (int slot = 0; slot < numSlots; slot++) {
|
||||||
tc = tpl->Process(Slot);
|
if (Slot < 0 || slot == Slot) {
|
||||||
|
tc = tpl->Process(slot);
|
||||||
if (tc) {
|
if (tc) {
|
||||||
int Length;
|
int Length;
|
||||||
const uint8_t *Data = tc->Data(Length);
|
const uint8_t *Data = tc->Data(Length);
|
||||||
@ -1587,27 +1684,66 @@ bool cCiHandler::Process(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (CloseAllSessions(Slot)) {
|
else if (CloseAllSessions(slot)) {
|
||||||
tpl->ResetSlot(Slot);
|
tpl->ResetSlot(slot);
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
else if (tpl->ModuleReady(Slot)) {
|
else if (tpl->ModuleReady(slot)) {
|
||||||
dbgprotocol("Module ready in slot %d\n", Slot);
|
dbgprotocol("Module ready in slot %d\n", slot);
|
||||||
moduleReady[Slot] = true;
|
moduleReady[slot] = true;
|
||||||
tpl->NewConnection(Slot);
|
tpl->NewConnection(slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
SendCaPmt();
|
||||||
bool UserIO = false;
|
bool UserIO = false;
|
||||||
for (int i = 0; i < MAX_CI_SESSION; i++) {
|
for (int i = 0; i < MAX_CI_SESSION; i++) {
|
||||||
if (sessions[i] && sessions[i]->Process())
|
if (sessions[i] && sessions[i]->Process())
|
||||||
UserIO |= sessions[i]->HasUserIO();
|
UserIO |= sessions[i]->HasUserIO();
|
||||||
}
|
}
|
||||||
hasUserIO = UserIO;
|
hasUserIO = UserIO;
|
||||||
if (newCaSupport)
|
|
||||||
newCaSupport = result = false; // triggers new SetCaPmt at caller!
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cCiHandler::SendCaPmt(void)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
if (newCaSupport) {
|
||||||
|
newCaSupport = false;
|
||||||
|
for (int Slot = 0; Slot < numSlots; Slot++) {
|
||||||
|
cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot);
|
||||||
|
if (cas) {
|
||||||
|
// build the list of CA_PMT data:
|
||||||
|
cList<cCiCaPmt> CaPmtList;
|
||||||
|
for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
|
||||||
|
bool Active = false;
|
||||||
|
cCiCaPmt *CaPmt = new cCiCaPmt(CPCI_OK_DESCRAMBLING, source, transponder, p->programNumber, GetCaSystemIds(Slot));
|
||||||
|
if (CaPmt->Valid()) {
|
||||||
|
for (cCiCaPidData *q = p->pidList.First(); q; q = p->pidList.Next(q)) {
|
||||||
|
if (q->active) {
|
||||||
|
CaPmt->AddPid(q->pid, q->streamType);
|
||||||
|
Active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Active)
|
||||||
|
CaPmtList.Add(CaPmt);
|
||||||
|
else
|
||||||
|
delete CaPmt;
|
||||||
|
}
|
||||||
|
// send the CA_PMT data:
|
||||||
|
uint8_t ListManagement = CaPmtList.Count() > 1 ? CPLM_FIRST : CPLM_ONLY;
|
||||||
|
for (cCiCaPmt *CaPmt = CaPmtList.First(); CaPmt; CaPmt = CaPmtList.Next(CaPmt)) {
|
||||||
|
CaPmt->SetListManagement(ListManagement);
|
||||||
|
if (!cas->SendPMT(CaPmt))
|
||||||
|
newCaSupport = true;
|
||||||
|
ListManagement = CaPmt->Next() && CaPmt->Next()->Next() ? CPLM_MORE : CPLM_LAST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool cCiHandler::EnterMenu(int Slot)
|
bool cCiHandler::EnterMenu(int Slot)
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&mutex);
|
cMutexLock MutexLock(&mutex);
|
||||||
@ -1676,11 +1812,89 @@ bool cCiHandler::ProvidesCa(const unsigned short *CaSystemIds)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt, int Slot)
|
void cCiHandler::SetSource(int Source, int Transponder)
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&mutex);
|
cMutexLock MutexLock(&mutex);
|
||||||
|
if (source != Source || transponder != Transponder) {
|
||||||
|
//XXX if there are active entries, send an empty CA_PMT
|
||||||
|
caProgramList.Clear();
|
||||||
|
}
|
||||||
|
source = Source;
|
||||||
|
transponder = Transponder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCiHandler::AddPid(int ProgramNumber, int Pid, int StreamType)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
cCiCaProgramData *ProgramData = NULL;
|
||||||
|
for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
|
||||||
|
if (p->programNumber == ProgramNumber) {
|
||||||
|
ProgramData = p;
|
||||||
|
for (cCiCaPidData *q = p->pidList.First(); q; q = p->pidList.Next(q)) {
|
||||||
|
if (q->pid == Pid)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ProgramData)
|
||||||
|
caProgramList.Add(ProgramData = new cCiCaProgramData(ProgramNumber));
|
||||||
|
ProgramData->pidList.Add(new cCiCaPidData(Pid, StreamType));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCiHandler::SetPid(int Pid, bool Active)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
|
||||||
|
for (cCiCaPidData *q = p->pidList.First(); q; q = p->pidList.Next(q)) {
|
||||||
|
if (q->pid == Pid) {
|
||||||
|
q->active = Active;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cCiHandler::CanDecrypt(int ProgramNumber)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
for (int Slot = 0; Slot < numSlots; Slot++) {
|
||||||
cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot);
|
cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot);
|
||||||
return cas && cas->SendPMT(CaPmt);
|
if (cas) {
|
||||||
|
for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
|
||||||
|
if (p->programNumber == ProgramNumber) {
|
||||||
|
cCiCaPmt CaPmt(CPCI_QUERY, source, transponder, p->programNumber, GetCaSystemIds(Slot));//XXX???
|
||||||
|
if (CaPmt.Valid()) {
|
||||||
|
for (cCiCaPidData *q = p->pidList.First(); q; q = p->pidList.Next(q)) {
|
||||||
|
//XXX if (q->active)
|
||||||
|
CaPmt.AddPid(q->pid, q->streamType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cas->SendPMT(&CaPmt))
|
||||||
|
return false;//XXX
|
||||||
|
//XXX
|
||||||
|
time_t timeout = time(NULL) + 3;//XXX
|
||||||
|
while (time(NULL) <= timeout) {
|
||||||
|
Process(Slot);
|
||||||
|
cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot);
|
||||||
|
if (!cas)
|
||||||
|
return false;//XXX
|
||||||
|
if (cas->ReceivedReply(true))
|
||||||
|
return true;
|
||||||
|
//XXX remember if a slot doesn't receive a reply
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCiHandler::StartDecrypting(void)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
newCaSupport = true;
|
||||||
|
SendCaPmt();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cCiHandler::Reset(int Slot)
|
bool cCiHandler::Reset(int Slot)
|
||||||
|
69
ci.h
69
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 1.18 2005/10/30 12:31:14 kls Exp $
|
* $Id: ci.h 1.19 2005/11/26 13:37:42 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CI_H
|
#ifndef __CI_H
|
||||||
@ -13,6 +13,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
class cCiMMI;
|
class cCiMMI;
|
||||||
|
|
||||||
@ -65,25 +66,32 @@ public:
|
|||||||
bool Abort(void);
|
bool Abort(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
class cCiCaPmt {
|
|
||||||
friend class cCiConditionalAccessSupport;
|
|
||||||
private:
|
|
||||||
int length;
|
|
||||||
int esInfoLengthPos;
|
|
||||||
uint8_t capmt[2048]; ///< XXX is there a specified maximum?
|
|
||||||
int caDescriptorsLength;
|
|
||||||
uint8_t caDescriptors[2048];
|
|
||||||
bool streamFlag;
|
|
||||||
void AddCaDescriptors(int Length, const uint8_t *Data);
|
|
||||||
public:
|
|
||||||
cCiCaPmt(int Source, int Transponder, int ProgramNumber, const unsigned short *CaSystemIds);
|
|
||||||
bool Valid(void);
|
|
||||||
void AddPid(int Pid, uint8_t StreamType);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_CI_SESSION 16 //XXX
|
#define MAX_CI_SESSION 16 //XXX
|
||||||
#define MAX_CI_SLOT 16
|
#define MAX_CI_SLOT 16
|
||||||
|
|
||||||
|
class cCiCaPidData : public cListObject {
|
||||||
|
public:
|
||||||
|
bool active;
|
||||||
|
int pid;
|
||||||
|
int streamType;
|
||||||
|
cCiCaPidData(int Pid, int StreamType)
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
pid = Pid;
|
||||||
|
streamType = StreamType;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class cCiCaProgramData : public cListObject {
|
||||||
|
public:
|
||||||
|
int programNumber;
|
||||||
|
cList<cCiCaPidData> pidList;
|
||||||
|
cCiCaProgramData(int ProgramNumber)
|
||||||
|
{
|
||||||
|
programNumber = ProgramNumber;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class cCiSession;
|
class cCiSession;
|
||||||
class cCiTransportLayer;
|
class cCiTransportLayer;
|
||||||
class cCiTransportConnection;
|
class cCiTransportConnection;
|
||||||
@ -99,6 +107,9 @@ private:
|
|||||||
cCiSession *sessions[MAX_CI_SESSION];
|
cCiSession *sessions[MAX_CI_SESSION];
|
||||||
cCiTransportLayer *tpl;
|
cCiTransportLayer *tpl;
|
||||||
cCiTransportConnection *tc;
|
cCiTransportConnection *tc;
|
||||||
|
int source;
|
||||||
|
int transponder;
|
||||||
|
cList<cCiCaProgramData> caProgramList;
|
||||||
int ResourceIdToInt(const uint8_t *Data);
|
int ResourceIdToInt(const uint8_t *Data);
|
||||||
bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1);
|
bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1);
|
||||||
cCiSession *GetSessionBySessionId(int SessionId);
|
cCiSession *GetSessionBySessionId(int SessionId);
|
||||||
@ -108,12 +119,15 @@ private:
|
|||||||
bool CloseSession(int SessionId);
|
bool CloseSession(int SessionId);
|
||||||
int CloseAllSessions(int Slot);
|
int CloseAllSessions(int Slot);
|
||||||
cCiHandler(int Fd, int NumSlots);
|
cCiHandler(int Fd, int NumSlots);
|
||||||
|
void SendCaPmt(void);
|
||||||
public:
|
public:
|
||||||
~cCiHandler();
|
~cCiHandler();
|
||||||
static cCiHandler *CreateCiHandler(const char *FileName);
|
static cCiHandler *CreateCiHandler(const char *FileName);
|
||||||
int NumSlots(void) { return numSlots; }
|
int NumSlots(void) { return numSlots; }
|
||||||
bool Ready(void);
|
bool Ready(void);
|
||||||
bool Process(void);
|
bool Process(int Slot = -1);
|
||||||
|
///< Processes the given Slot. If Slot is -1, all slots are processed.
|
||||||
|
///< Returns false in case of an error.
|
||||||
bool HasUserIO(void) { return hasUserIO; }
|
bool HasUserIO(void) { return hasUserIO; }
|
||||||
bool EnterMenu(int Slot);
|
bool EnterMenu(int Slot);
|
||||||
cCiMenu *GetMenu(void);
|
cCiMenu *GetMenu(void);
|
||||||
@ -121,7 +135,24 @@ public:
|
|||||||
const char *GetCamName(int Slot);
|
const char *GetCamName(int Slot);
|
||||||
const unsigned short *GetCaSystemIds(int Slot);
|
const unsigned short *GetCaSystemIds(int Slot);
|
||||||
bool ProvidesCa(const unsigned short *CaSystemIds); //XXX Slot???
|
bool ProvidesCa(const unsigned short *CaSystemIds); //XXX Slot???
|
||||||
bool SetCaPmt(cCiCaPmt &CaPmt, int Slot);
|
void SetSource(int Source, int Transponder);
|
||||||
|
///< Sets the Source and Transponder of the device this cCiHandler is
|
||||||
|
///< currently tuned to. If Source or Transponder are different than
|
||||||
|
///< what was given in a previous call to SetSource(), any previously
|
||||||
|
///< added PIDs will be cleared.
|
||||||
|
void AddPid(int ProgramNumber, int Pid, int StreamType);
|
||||||
|
///< Adds the given PID information to the list of PIDs. A later call
|
||||||
|
///< to SetPid() will (de)activate one of these entries.
|
||||||
|
void SetPid(int Pid, bool Active);
|
||||||
|
///< Sets the given Pid (which has previously been added through a
|
||||||
|
///< call to AddPid()) to Active. If Active is true, a later call to
|
||||||
|
///< StartDecrypting() will send the full list of currently active CA_PMT
|
||||||
|
///< entries to the CAM, including this one.
|
||||||
|
bool CanDecrypt(int ProgramNumber);
|
||||||
|
///< XXX
|
||||||
|
void StartDecrypting(void);
|
||||||
|
///< Triggers sending all currently active CA_PMT entries to the CAM,
|
||||||
|
///< so that it will start decrypting.
|
||||||
bool Reset(int Slot);
|
bool Reset(int Slot);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
34
device.c
34
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 1.111 2005/11/05 15:23:58 kls Exp $
|
* $Id: device.c 1.112 2005/11/26 12:56:09 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
@ -397,6 +397,8 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
|
|||||||
DelPid(Pid, PidType);
|
DelPid(Pid, PidType);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (ciHandler)
|
||||||
|
ciHandler->SetPid(Pid, true);
|
||||||
}
|
}
|
||||||
PRINTPIDS("a");
|
PRINTPIDS("a");
|
||||||
return true;
|
return true;
|
||||||
@ -424,6 +426,8 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
|
|||||||
DelPid(Pid, PidType);
|
DelPid(Pid, PidType);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (ciHandler)
|
||||||
|
ciHandler->SetPid(Pid, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -450,6 +454,8 @@ void cDevice::DelPid(int Pid, ePidType PidType)
|
|||||||
if (pidHandles[n].used == 0) {
|
if (pidHandles[n].used == 0) {
|
||||||
pidHandles[n].handle = -1;
|
pidHandles[n].handle = -1;
|
||||||
pidHandles[n].pid = 0;
|
pidHandles[n].pid = 0;
|
||||||
|
if (ciHandler)
|
||||||
|
ciHandler->SetPid(Pid, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PRINTPIDS("E");
|
PRINTPIDS("E");
|
||||||
@ -601,12 +607,34 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
|
|||||||
sectionHandler->SetStatus(false);
|
sectionHandler->SetStatus(false);
|
||||||
sectionHandler->SetChannel(NULL);
|
sectionHandler->SetChannel(NULL);
|
||||||
}
|
}
|
||||||
|
// Tell the ciHandler about the channel switch and add all PIDs of this
|
||||||
|
// channel to it, for possible later decryption:
|
||||||
|
if (ciHandler) {
|
||||||
|
ciHandler->SetSource(Channel->Source(), Channel->Transponder());
|
||||||
|
// Men at work - please stand clear! ;-)
|
||||||
|
#ifdef XXX_DO_MULTIPLE_CA_CHANNELS
|
||||||
|
if (Channel->Ca() > CACONFBASE) {
|
||||||
|
#endif
|
||||||
|
ciHandler->AddPid(Channel->Sid(), Channel->Vpid(), 2);
|
||||||
|
for (const int *Apid = Channel->Apids(); *Apid; Apid++)
|
||||||
|
ciHandler->AddPid(Channel->Sid(), *Apid, 4);
|
||||||
|
for (const int *Dpid = Channel->Dpids(); *Dpid; Dpid++)
|
||||||
|
ciHandler->AddPid(Channel->Sid(), *Dpid, 0);
|
||||||
|
#ifdef XXX_DO_MULTIPLE_CA_CHANNELS
|
||||||
|
bool CanDecrypt = ciHandler->CanDecrypt(Channel->Sid());//XXX
|
||||||
|
dsyslog("CanDecrypt %d %d %d %s", CardIndex() + 1, CanDecrypt, Channel->Number(), Channel->Name());//XXX
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if (SetChannelDevice(Channel, LiveView)) {
|
if (SetChannelDevice(Channel, LiveView)) {
|
||||||
// Start section handling:
|
// Start section handling:
|
||||||
if (sectionHandler) {
|
if (sectionHandler) {
|
||||||
sectionHandler->SetChannel(Channel);
|
sectionHandler->SetChannel(Channel);
|
||||||
sectionHandler->SetStatus(true);
|
sectionHandler->SetStatus(true);
|
||||||
}
|
}
|
||||||
|
// Start decrypting any PIDs the might have been set in SetChannelDevice():
|
||||||
|
if (ciHandler)
|
||||||
|
ciHandler->StartDecrypting();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Result = scrFailed;
|
Result = scrFailed;
|
||||||
@ -1168,6 +1196,8 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
|
|||||||
Unlock();
|
Unlock();
|
||||||
if (!Running())
|
if (!Running())
|
||||||
Start();
|
Start();
|
||||||
|
if (ciHandler)
|
||||||
|
ciHandler->StartDecrypting();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1194,6 +1224,8 @@ void cDevice::Detach(cReceiver *Receiver)
|
|||||||
else if (receiver[i])
|
else if (receiver[i])
|
||||||
receiversLeft = true;
|
receiversLeft = true;
|
||||||
}
|
}
|
||||||
|
if (ciHandler)
|
||||||
|
ciHandler->StartDecrypting();
|
||||||
if (!receiversLeft)
|
if (!receiversLeft)
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
}
|
}
|
||||||
|
54
dvbdevice.c
54
dvbdevice.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: dvbdevice.c 1.137 2005/11/11 14:53:52 kls Exp $
|
* $Id: dvbdevice.c 1.138 2005/11/26 13:23:11 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dvbdevice.h"
|
#include "dvbdevice.h"
|
||||||
@ -35,6 +35,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define DO_REC_AND_PLAY_ON_PRIMARY_DEVICE 1
|
#define DO_REC_AND_PLAY_ON_PRIMARY_DEVICE 1
|
||||||
#define DO_MULTIPLE_RECORDINGS 1
|
#define DO_MULTIPLE_RECORDINGS 1
|
||||||
|
//#define DO_MULTIPLE_CA_CHANNELS
|
||||||
|
|
||||||
#define DEV_VIDEO "/dev/video"
|
#define DEV_VIDEO "/dev/video"
|
||||||
#define DEV_DVB_ADAPTER "/dev/dvb/adapter"
|
#define DEV_DVB_ADAPTER "/dev/dvb/adapter"
|
||||||
@ -69,15 +70,13 @@ static int DvbOpen(const char *Name, int n, int Mode, bool ReportError = false)
|
|||||||
|
|
||||||
class cDvbTuner : public cThread {
|
class cDvbTuner : public cThread {
|
||||||
private:
|
private:
|
||||||
enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked, tsCam };
|
enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked };
|
||||||
int fd_frontend;
|
int fd_frontend;
|
||||||
int cardIndex;
|
int cardIndex;
|
||||||
fe_type_t frontendType;
|
fe_type_t frontendType;
|
||||||
cCiHandler *ciHandler;
|
cCiHandler *ciHandler;
|
||||||
cChannel channel;
|
cChannel channel;
|
||||||
const char *diseqcCommands;
|
const char *diseqcCommands;
|
||||||
bool useCa;
|
|
||||||
time_t startTime;
|
|
||||||
eTunerStatus tunerStatus;
|
eTunerStatus tunerStatus;
|
||||||
cMutex mutex;
|
cMutex mutex;
|
||||||
cCondVar locked;
|
cCondVar locked;
|
||||||
@ -89,7 +88,7 @@ public:
|
|||||||
cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler);
|
cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler);
|
||||||
virtual ~cDvbTuner();
|
virtual ~cDvbTuner();
|
||||||
bool IsTunedTo(const cChannel *Channel) const;
|
bool IsTunedTo(const cChannel *Channel) const;
|
||||||
void Set(const cChannel *Channel, bool Tune, bool UseCa);
|
void Set(const cChannel *Channel, bool Tune);
|
||||||
bool Locked(int TimeoutMs = 0);
|
bool Locked(int TimeoutMs = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,9 +99,7 @@ cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCi
|
|||||||
frontendType = FrontendType;
|
frontendType = FrontendType;
|
||||||
ciHandler = CiHandler;
|
ciHandler = CiHandler;
|
||||||
diseqcCommands = NULL;
|
diseqcCommands = NULL;
|
||||||
useCa = false;
|
|
||||||
tunerStatus = tsIdle;
|
tunerStatus = tsIdle;
|
||||||
startTime = time(NULL);
|
|
||||||
if (frontendType == FE_QPSK)
|
if (frontendType == FE_QPSK)
|
||||||
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
|
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
|
||||||
SetDescription("tuner on device %d", cardIndex + 1);
|
SetDescription("tuner on device %d", cardIndex + 1);
|
||||||
@ -122,16 +119,11 @@ bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
|
|||||||
return tunerStatus != tsIdle && channel.Source() == Channel->Source() && channel.Transponder() == Channel->Transponder();
|
return tunerStatus != tsIdle && channel.Source() == Channel->Source() && channel.Transponder() == Channel->Transponder();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cDvbTuner::Set(const cChannel *Channel, bool Tune, bool UseCa)
|
void cDvbTuner::Set(const cChannel *Channel, bool Tune)
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&mutex);
|
cMutexLock MutexLock(&mutex);
|
||||||
if (Tune)
|
if (Tune)
|
||||||
tunerStatus = tsSet;
|
tunerStatus = tsSet;
|
||||||
else if (tunerStatus == tsCam)
|
|
||||||
tunerStatus = tsLocked;
|
|
||||||
useCa = UseCa;
|
|
||||||
if (Channel->Ca() && tunerStatus != tsCam)
|
|
||||||
startTime = time(NULL);
|
|
||||||
channel = *Channel;
|
channel = *Channel;
|
||||||
newSet.Broadcast();
|
newSet.Broadcast();
|
||||||
}
|
}
|
||||||
@ -309,7 +301,6 @@ void cDvbTuner::Action(void)
|
|||||||
continue;
|
continue;
|
||||||
case tsTuned:
|
case tsTuned:
|
||||||
case tsLocked:
|
case tsLocked:
|
||||||
case tsCam:
|
|
||||||
if (hasEvent) {
|
if (hasEvent) {
|
||||||
if (event.status & FE_REINIT) {
|
if (event.status & FE_REINIT) {
|
||||||
tunerStatus = tsSet;
|
tunerStatus = tsSet;
|
||||||
@ -323,30 +314,10 @@ void cDvbTuner::Action(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ciHandler) {
|
if (ciHandler)
|
||||||
if (ciHandler->Process() && useCa) {
|
ciHandler->Process();
|
||||||
if (tunerStatus == tsLocked) {
|
|
||||||
for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) {
|
|
||||||
cCiCaPmt CaPmt(channel.Source(), channel.Transponder(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
|
|
||||||
if (CaPmt.Valid()) {
|
|
||||||
CaPmt.AddPid(channel.Vpid(), 2);
|
|
||||||
CaPmt.AddPid(channel.Apid(0), 4);
|
|
||||||
CaPmt.AddPid(channel.Apid(1), 4);
|
|
||||||
CaPmt.AddPid(channel.Dpid(0), 0);
|
|
||||||
if (ciHandler->SetCaPmt(CaPmt, Slot)) {
|
|
||||||
tunerStatus = tsCam;
|
|
||||||
startTime = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (tunerStatus > tsLocked)
|
|
||||||
tunerStatus = tsLocked;
|
|
||||||
}
|
|
||||||
// in the beginning we loop more often to let the CAM connection start up fast
|
|
||||||
if (tunerStatus != tsTuned)
|
if (tunerStatus != tsTuned)
|
||||||
newSet.TimedWait(mutex, (ciHandler && (time(NULL) - startTime < 20)) ? 100 : 1000);
|
newSet.TimedWait(mutex, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -782,9 +753,12 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
|
|||||||
if (dvbTuner->IsTunedTo(Channel)) {
|
if (dvbTuner->IsTunedTo(Channel)) {
|
||||||
if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0))) {
|
if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0))) {
|
||||||
#ifdef DO_MULTIPLE_RECORDINGS
|
#ifdef DO_MULTIPLE_RECORDINGS
|
||||||
|
#ifndef DO_MULTIPLE_CA_CHANNELS
|
||||||
if (Ca() > CACONFBASE || Channel->Ca() > CACONFBASE)
|
if (Ca() > CACONFBASE || Channel->Ca() > CACONFBASE)
|
||||||
needsDetachReceivers = Ca() != Channel->Ca();
|
needsDetachReceivers = Ca() != Channel->Ca();
|
||||||
else if (!IsPrimaryDevice())
|
else
|
||||||
|
#endif
|
||||||
|
if (!IsPrimaryDevice())
|
||||||
result = true;
|
result = true;
|
||||||
#ifdef DO_REC_AND_PLAY_ON_PRIMARY_DEVICE
|
#ifdef DO_REC_AND_PLAY_ON_PRIMARY_DEVICE
|
||||||
else
|
else
|
||||||
@ -834,13 +808,13 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
|
|
||||||
// Set the tuner:
|
// Set the tuner:
|
||||||
|
|
||||||
dvbTuner->Set(Channel, DoTune, !EITScanner.UsesDevice(this)); //XXX 1.3: this is an ugly hack - find a cleaner solution//XXX
|
dvbTuner->Set(Channel, DoTune);
|
||||||
|
|
||||||
// If this channel switch was requested by the EITScanner we don't wait for
|
// If this channel switch was requested by the EITScanner we don't wait for
|
||||||
// a lock and don't set any live PIDs (the EITScanner will wait for the lock
|
// a lock and don't set any live PIDs (the EITScanner will wait for the lock
|
||||||
// by itself before setting any filters):
|
// by itself before setting any filters):
|
||||||
|
|
||||||
if (EITScanner.UsesDevice(this))
|
if (EITScanner.UsesDevice(this)) //XXX
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// PID settings:
|
// PID settings:
|
||||||
|
Loading…
Reference in New Issue
Block a user