mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented 'Link Layer' based CAM support
This commit is contained in:
parent
43b582a04d
commit
4e15f6d658
5
HISTORY
5
HISTORY
@ -1899,7 +1899,7 @@ Video Disk Recorder Revision History
|
||||
See INSTALL for information how to do this. Some function descriptions have
|
||||
already been adapted to Doxygen, more will follow.
|
||||
|
||||
2002-12-23: Version 1.1.21
|
||||
2003-01-06: Version 1.1.21
|
||||
|
||||
- Fixed the 'channels.conf' entries for "Studio Universal" and "Disney Channel".
|
||||
- Fixed handling channels in the "Channels" menu in case there are ':@nnn' group
|
||||
@ -1908,3 +1908,6 @@ Video Disk Recorder Revision History
|
||||
- Increased the timeout until an index file is considerd no longer to be written
|
||||
(sometimes in time shift with heavy system load the index file was closed too
|
||||
early by the replay thread).
|
||||
- Implemented "Link Layer" based CAM support, which hopefully will solve the
|
||||
problems with CAMs we had in the past. To use this you need the driver version
|
||||
2002-01-06 or higher (with the new firmware supporting the "Link Layer" protocol).
|
||||
|
4
Makefile
4
Makefile
@ -4,7 +4,7 @@
|
||||
# See the main source file 'vdr.c' for copyright information and
|
||||
# how to reach the author.
|
||||
#
|
||||
# $Id: Makefile 1.55 2002/12/15 15:15:55 kls Exp $
|
||||
# $Id: Makefile 1.56 2003/01/06 12:28:09 kls Exp $
|
||||
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
@ -32,7 +32,7 @@ INCLUDES = -I$(DVBDIR)/include
|
||||
|
||||
DTVLIB = $(DTVDIR)/libdtv.a
|
||||
|
||||
OBJS = audio.o channels.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd.o\
|
||||
OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd.o\
|
||||
dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o interface.o keys.o\
|
||||
lirc.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o rcu.o\
|
||||
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sources.o\
|
||||
|
105
ci.h
Normal file
105
ci.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* ci.h: Common Interface
|
||||
*
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: ci.h 1.1 2003/01/06 12:31:09 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __CI_H
|
||||
#define __CI_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "thread.h"
|
||||
|
||||
class cCiMMI;
|
||||
|
||||
class cCiMenu {
|
||||
friend class cCiMMI;
|
||||
private:
|
||||
enum { MAX_CIMENU_ENTRIES = 64 }; ///< XXX is there a specified maximum?
|
||||
cCiMMI *mmi;
|
||||
bool selectable;
|
||||
char *titleText;
|
||||
char *subTitleText;
|
||||
char *bottomText;
|
||||
char *entries[MAX_CIMENU_ENTRIES];
|
||||
int numEntries;
|
||||
bool AddEntry(char *s);
|
||||
cCiMenu(cCiMMI *MMI, bool Selectable);
|
||||
public:
|
||||
~cCiMenu();
|
||||
const char *TitleText(void) { return titleText; }
|
||||
const char *SubTitleText(void) { return subTitleText; }
|
||||
const char *BottomText(void) { return bottomText; }
|
||||
const char *Entry(int n) { return n < numEntries ? entries[n] : NULL; }
|
||||
int NumEntries(void) { return numEntries; }
|
||||
bool Selectable(void) { return selectable; }
|
||||
bool Select(int Index);
|
||||
bool Cancel(void);
|
||||
};
|
||||
|
||||
class cCiEnquiry {
|
||||
friend class cCiMMI;
|
||||
private:
|
||||
cCiMMI *mmi;
|
||||
char *text;
|
||||
bool blind;
|
||||
int expectedLength;
|
||||
cCiEnquiry(cCiMMI *MMI);
|
||||
public:
|
||||
~cCiEnquiry();
|
||||
const char *Text(void) { return text; }
|
||||
bool Blind(void) { return blind; }
|
||||
int ExpectedLength(void) { return expectedLength; }
|
||||
bool Reply(const char *s);
|
||||
bool Cancel(void);
|
||||
};
|
||||
|
||||
class cCiCaPmt {
|
||||
friend class cCiConditionalAccessSupport;
|
||||
private:
|
||||
int length;
|
||||
int esInfoLengthPos;
|
||||
uint8_t capmt[2048]; ///< XXX is there a specified maximum?
|
||||
public:
|
||||
cCiCaPmt(int ProgramNumber);
|
||||
void AddPid(int Pid);
|
||||
void AddCaDescriptor(int Length, uint8_t *Data);
|
||||
};
|
||||
|
||||
#define MAX_CI_SESSION 16 //XXX
|
||||
|
||||
class cCiSession;
|
||||
class cCiTransportLayer;
|
||||
class cCiTransportConnection;
|
||||
|
||||
class cCiHandler {
|
||||
private:
|
||||
cMutex mutex;
|
||||
int numSlots;
|
||||
cCiSession *sessions[MAX_CI_SESSION];
|
||||
cCiTransportLayer *tpl;
|
||||
cCiTransportConnection *tc;
|
||||
int ResourceIdToInt(const uint8_t *Data);
|
||||
bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1);
|
||||
cCiSession *GetSessionBySessionId(int SessionId);
|
||||
cCiSession *GetSessionByResourceId(int ResourceId);
|
||||
cCiSession *CreateSession(int ResourceId);
|
||||
bool OpenSession(int Length, const uint8_t *Data);
|
||||
bool CloseSession(int SessionId);
|
||||
cCiHandler(int Fd, int NumSlots);
|
||||
public:
|
||||
~cCiHandler();
|
||||
static cCiHandler *CreateCiHandler(const char *FileName);
|
||||
bool Process(void);
|
||||
bool EnterMenu(void);
|
||||
cCiMenu *GetMenu(void);
|
||||
cCiEnquiry *GetEnquiry(void);
|
||||
bool SetCaPmt(cCiCaPmt &CaPmt);
|
||||
bool Reset(void);
|
||||
};
|
||||
|
||||
#endif //__CI_H
|
4
device.c
4
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 1.35 2002/11/10 10:17:57 kls Exp $
|
||||
* $Id: device.c 1.36 2003/01/03 15:41:14 kls Exp $
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
@ -47,6 +47,7 @@ cDevice::cDevice(void)
|
||||
mute = false;
|
||||
volume = Setup.CurrentVolume;
|
||||
|
||||
ciHandler = NULL;
|
||||
player = NULL;
|
||||
|
||||
playerDetached = false;
|
||||
@ -67,6 +68,7 @@ cDevice::~cDevice()
|
||||
Detach(player);
|
||||
for (int i = 0; i < MAXRECEIVERS; i++)
|
||||
Detach(receiver[i]);
|
||||
delete ciHandler;
|
||||
}
|
||||
|
||||
void cDevice::SetUseDevice(int n)
|
||||
|
10
device.h
10
device.h
@ -4,12 +4,13 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: device.h 1.28 2002/12/15 14:40:11 kls Exp $
|
||||
* $Id: device.h 1.29 2003/01/03 15:43:48 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __DEVICE_H
|
||||
#define __DEVICE_H
|
||||
|
||||
#include "ci.h"
|
||||
#include "thread.h"
|
||||
#include "tools.h"
|
||||
|
||||
@ -211,6 +212,13 @@ protected:
|
||||
///< Type indicates some special types of PIDs, which the device may
|
||||
///< need to set in a specific way.
|
||||
|
||||
// Common Interface facilities:
|
||||
|
||||
protected:
|
||||
cCiHandler *ciHandler;
|
||||
public:
|
||||
cCiHandler *CiHandler(void) { return ciHandler; }
|
||||
|
||||
// Image Grab facilities
|
||||
|
||||
public:
|
||||
|
46
dvbdevice.c
46
dvbdevice.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: dvbdevice.c 1.40 2002/12/14 10:52:13 kls Exp $
|
||||
* $Id: dvbdevice.c 1.41 2003/01/06 14:44:27 kls Exp $
|
||||
*/
|
||||
|
||||
#include "dvbdevice.h"
|
||||
@ -43,6 +43,7 @@ extern "C" {
|
||||
#define DEV_DVB_DEMUX "demux"
|
||||
#define DEV_DVB_VIDEO "video"
|
||||
#define DEV_DVB_AUDIO "audio"
|
||||
#define DEV_DVB_CA "ca"
|
||||
|
||||
static const char *DvbName(const char *Name, int n)
|
||||
{
|
||||
@ -68,30 +69,34 @@ private:
|
||||
int fd_frontend;
|
||||
int cardIndex;
|
||||
fe_type_t frontendType;
|
||||
cCiHandler *ciHandler;
|
||||
cChannel channel;
|
||||
const char *diseqcCommands;
|
||||
bool active;
|
||||
eTunerStatus tunerStatus;
|
||||
bool caSet;
|
||||
cMutex mutex;
|
||||
cCondVar newSet;
|
||||
bool SetFrontend(void);
|
||||
virtual void Action(void);
|
||||
public:
|
||||
cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType);
|
||||
cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler);
|
||||
virtual ~cDvbTuner();
|
||||
bool IsTunedTo(const cChannel *Channel) const;
|
||||
void Set(const cChannel *Channel);
|
||||
void Set(const cChannel *Channel, bool Tune);
|
||||
bool Locked(void) { return tunerStatus == tsLocked; }
|
||||
};
|
||||
|
||||
cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType)
|
||||
cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler)
|
||||
{
|
||||
fd_frontend = Fd_Frontend;
|
||||
cardIndex = CardIndex;
|
||||
frontendType = FrontendType;
|
||||
ciHandler = CiHandler;
|
||||
diseqcCommands = NULL;
|
||||
active = false;
|
||||
tunerStatus = tsIdle;
|
||||
caSet = false;
|
||||
Start();
|
||||
}
|
||||
|
||||
@ -108,11 +113,13 @@ bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
|
||||
return tunerStatus != tsIdle && channel.Source() == Channel->Source() && channel.Frequency() == Channel->Frequency();
|
||||
}
|
||||
|
||||
void cDvbTuner::Set(const cChannel *Channel)
|
||||
void cDvbTuner::Set(const cChannel *Channel, bool Tune)
|
||||
{
|
||||
cMutexLock MutexLock(&mutex);
|
||||
channel = *Channel;
|
||||
if (Tune)
|
||||
tunerStatus = tsSet;
|
||||
caSet = false;
|
||||
newSet.Broadcast();
|
||||
}
|
||||
|
||||
@ -251,6 +258,30 @@ void cDvbTuner::Action(void)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ciHandler && !caSet) {//XXX TODO update in case the CA descriptors have changed
|
||||
uchar buffer[2048];
|
||||
int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer);
|
||||
if (length > 0) {
|
||||
cCiCaPmt CaPmt(channel.Sid());
|
||||
if (channel.Vpid()) {
|
||||
CaPmt.AddPid(channel.Vpid());
|
||||
CaPmt.AddCaDescriptor(length, buffer);
|
||||
}
|
||||
if (channel.Apid1()) {
|
||||
CaPmt.AddPid(channel.Apid1());
|
||||
CaPmt.AddCaDescriptor(length, buffer);
|
||||
}
|
||||
if (channel.Apid2()) {
|
||||
CaPmt.AddPid(channel.Apid2());
|
||||
CaPmt.AddCaDescriptor(length, buffer);
|
||||
}
|
||||
if (channel.Dpid1()) {
|
||||
CaPmt.AddPid(channel.Dpid1());
|
||||
CaPmt.AddCaDescriptor(length, buffer);
|
||||
}
|
||||
caSet = ciHandler->SetCaPmt(CaPmt);
|
||||
}
|
||||
}
|
||||
newSet.TimedWait(mutex, 1000);
|
||||
}
|
||||
dsyslog("tuner thread ended on device %d (pid=%d)", cardIndex + 1, getpid());
|
||||
@ -291,7 +322,8 @@ cDvbDevice::cDvbDevice(int n)
|
||||
siProcessor = new cSIProcessor(DvbName(DEV_DVB_DEMUX, n));
|
||||
if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) {
|
||||
frontendType = feinfo.type;
|
||||
dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType);
|
||||
ciHandler = cCiHandler::CreateCiHandler(DvbName(DEV_DVB_CA, n));
|
||||
dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType, ciHandler);
|
||||
}
|
||||
else
|
||||
LOG_ERROR;
|
||||
@ -616,8 +648,8 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
||||
DelPid(pidHandles[ptDolby].pid);
|
||||
}
|
||||
|
||||
dvbTuner->Set(Channel, DoTune);
|
||||
if (DoTune) {
|
||||
dvbTuner->Set(Channel);
|
||||
/*XXX do we still need this???
|
||||
if (!(status & FE_HAS_LOCK)) {
|
||||
esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->Number(), CardIndex() + 1);
|
||||
|
177
eit.c
177
eit.c
@ -16,7 +16,7 @@
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* $Id: eit.c 1.61 2002/11/24 14:37:38 kls Exp $
|
||||
* $Id: eit.c 1.62 2003/01/06 14:10:37 kls Exp $
|
||||
***************************************************************************/
|
||||
|
||||
#include "eit.h"
|
||||
@ -985,6 +985,68 @@ bool cEIT::IsPresentFollowing()
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- cCaDescriptor ---------------------------------------------------------
|
||||
|
||||
class cCaDescriptor : public cListObject {
|
||||
friend class cCaDescriptors;
|
||||
private:
|
||||
int source;
|
||||
int transponder;
|
||||
int serviceId;
|
||||
int caSystem;
|
||||
int length;
|
||||
uchar *data;
|
||||
public:
|
||||
cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int Length, uchar *Data);
|
||||
virtual ~cCaDescriptor();
|
||||
int Length(void) const { return length; }
|
||||
const uchar *Data(void) const { return data; }
|
||||
};
|
||||
|
||||
cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int Length, uchar *Data)
|
||||
{
|
||||
source = Source;
|
||||
transponder = Transponder;
|
||||
serviceId = ServiceId;
|
||||
caSystem = CaSystem;
|
||||
length = Length;
|
||||
data = MALLOC(uchar, length);
|
||||
memcpy(data, Data, length);
|
||||
/*//XXX just while debugging...
|
||||
char buffer[1024];
|
||||
char *q = buffer;
|
||||
q += sprintf(q, "CAM: %04X %5d %4d", source, transponder, serviceId);
|
||||
for (int i = 0; i < length; i++)
|
||||
q += sprintf(q, " %02X", data[i]);
|
||||
dsyslog(buffer);
|
||||
*///XXX
|
||||
}
|
||||
|
||||
cCaDescriptor::~cCaDescriptor()
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
// --- cCaDescriptors --------------------------------------------------------
|
||||
|
||||
class cCaDescriptors : public cList<cCaDescriptor> {
|
||||
public:
|
||||
const cCaDescriptor *Get(int Source, int Transponder, int ServiceId, int CaSystem);
|
||||
};
|
||||
|
||||
const cCaDescriptor *cCaDescriptors::Get(int Source, int Transponder, int ServiceId, int CaSystem)
|
||||
{
|
||||
for (cCaDescriptor *ca = First(); ca; ca = Next(ca)) {
|
||||
if (ca->source == Source && ca->transponder == Transponder && ca->serviceId == ServiceId) {
|
||||
if (CaSystem == -1 || ca->caSystem == CaSystem)
|
||||
return ca;
|
||||
if (CaSystem < 0)
|
||||
CaSystem++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// --- cSIProcessor ----------------------------------------------------------
|
||||
|
||||
#define MAX_FILTERS 20
|
||||
@ -993,6 +1055,8 @@ bool cEIT::IsPresentFollowing()
|
||||
int cSIProcessor::numSIProcessors = 0;
|
||||
cSchedules *cSIProcessor::schedules = NULL;
|
||||
cMutex cSIProcessor::schedulesMutex;
|
||||
cCaDescriptors *cSIProcessor::caDescriptors = NULL;
|
||||
cMutex cSIProcessor::caDescriptorsMutex;
|
||||
const char *cSIProcessor::epgDataFileName = EPGDATAFILENAME;
|
||||
time_t cSIProcessor::lastDump = time(NULL);
|
||||
|
||||
@ -1003,9 +1067,13 @@ cSIProcessor::cSIProcessor(const char *FileName)
|
||||
masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master'
|
||||
currentSource = 0;
|
||||
currentTransponder = 0;
|
||||
pmtIndex = 0;
|
||||
pmtPid = 0;
|
||||
filters = NULL;
|
||||
if (!numSIProcessors++) // the first one creates it
|
||||
if (!numSIProcessors++) { // the first one creates them
|
||||
schedules = new cSchedules;
|
||||
caDescriptors = new cCaDescriptors;
|
||||
}
|
||||
filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER));
|
||||
SetStatus(true);
|
||||
Start();
|
||||
@ -1019,8 +1087,10 @@ cSIProcessor::~cSIProcessor()
|
||||
Cancel(3);
|
||||
ShutDownFilters();
|
||||
free(filters);
|
||||
if (!--numSIProcessors) // the last one deletes it
|
||||
if (!--numSIProcessors) { // the last one deletes them
|
||||
delete schedules;
|
||||
delete caDescriptors;
|
||||
}
|
||||
free(fileName);
|
||||
}
|
||||
|
||||
@ -1075,9 +1145,13 @@ const char *cSIProcessor::GetEpgDataFileName(void)
|
||||
|
||||
void cSIProcessor::SetStatus(bool On)
|
||||
{
|
||||
LOCK_THREAD;
|
||||
ShutDownFilters();
|
||||
pmtIndex = 0;
|
||||
pmtPid = 0;
|
||||
if (On)
|
||||
{
|
||||
AddFilter(0x00, 0x00); // PAT
|
||||
AddFilter(0x14, 0x70); // TDT
|
||||
AddFilter(0x14, 0x73); // TOT
|
||||
AddFilter(0x12, 0x4e); // event info, actual TS, present/following
|
||||
@ -1089,6 +1163,8 @@ void cSIProcessor::SetStatus(bool On)
|
||||
}
|
||||
}
|
||||
|
||||
#define PMT_SCAN_TIMEOUT 10 // seconds
|
||||
|
||||
/** use the vbi device to parse all relevant SI
|
||||
information and let the classes corresponding
|
||||
to the tables write their information to the disk */
|
||||
@ -1097,6 +1173,7 @@ void cSIProcessor::Action()
|
||||
dsyslog("EIT processing thread started (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : "");
|
||||
|
||||
time_t lastCleanup = time(NULL);
|
||||
time_t lastPmtScan = time(NULL);
|
||||
|
||||
active = true;
|
||||
|
||||
@ -1162,6 +1239,37 @@ void cSIProcessor::Action()
|
||||
//dsyslog("Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen);
|
||||
switch (pid)
|
||||
{
|
||||
case 0x00:
|
||||
if (buf[0] == 0x00)
|
||||
{
|
||||
LOCK_THREAD;
|
||||
if (pmtPid && time(NULL) - lastPmtScan > PMT_SCAN_TIMEOUT) {
|
||||
DelFilter(pmtPid, 0x02);
|
||||
pmtPid = 0;
|
||||
pmtIndex++;
|
||||
lastPmtScan = time(NULL);
|
||||
}
|
||||
if (!pmtPid) {
|
||||
cMutexLock MutexLock(&schedulesMutex); // since the xMem... stuff is not thread safe, we need to use a "global" mutex
|
||||
struct LIST *pat = siParsePAT(buf);
|
||||
if (pat) {
|
||||
int Index = 0;
|
||||
for (struct Program *prg = (struct Program *)pat->Head; prg; prg = (struct Program *)xSucc(prg)) {
|
||||
if (prg->ProgramID) {
|
||||
if (Index++ == pmtIndex) {
|
||||
pmtPid = prg->NetworkPID;
|
||||
AddFilter(pmtPid, 0x02);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!pmtPid)
|
||||
pmtIndex = 0;
|
||||
}
|
||||
xMemFreeAll(NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
if (buf[0] == 0x70)
|
||||
{
|
||||
@ -1188,7 +1296,28 @@ void cSIProcessor::Action()
|
||||
dsyslog("Received stuffing section in EIT\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
default: {
|
||||
LOCK_THREAD;
|
||||
if (pid == pmtPid && buf[0] == 0x02 && currentSource && currentTransponder) {
|
||||
cMutexLock MutexLock(&schedulesMutex); // since the xMem... stuff is not thread safe, we need to use a "global" mutex
|
||||
struct Pid *pi = siParsePMT(buf);
|
||||
if (pi) {
|
||||
for (struct LIST *d = (struct LIST *)pi->Descriptors; d; d = (struct LIST *)xSucc(d)) {
|
||||
if (DescriptorTag(d) == DESCR_CA) {
|
||||
uchar *Data = ((ConditionalAccessDescriptor *)d)->Data;
|
||||
int CaSystem = (Data[2] << 8) | Data[3];
|
||||
if (!caDescriptors->Get(currentSource, currentTransponder, pi->ProgramID, CaSystem)) {
|
||||
cMutexLock MutexLock(&caDescriptorsMutex);
|
||||
caDescriptors->Add(new cCaDescriptor(currentSource, currentTransponder, pi->ProgramID, CaSystem, ((ConditionalAccessDescriptor *)d)->Amount, Data));
|
||||
}
|
||||
//XXX update???
|
||||
}
|
||||
}
|
||||
}
|
||||
xMemFreeAll(NULL);
|
||||
lastPmtScan = 0; // this triggers the next scan
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1229,7 +1358,7 @@ bool cSIProcessor::AddFilter(u_char pid, u_char tid)
|
||||
filters[a].inuse = true;
|
||||
else
|
||||
{
|
||||
esyslog("ERROR: can't set filter");
|
||||
esyslog("ERROR: can't set filter (pid=%d, tid=%02X)", pid, tid);
|
||||
close(filters[a].handle);
|
||||
return false;
|
||||
}
|
||||
@ -1248,6 +1377,21 @@ bool cSIProcessor::AddFilter(u_char pid, u_char tid)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSIProcessor::DelFilter(u_char pid, u_char tid)
|
||||
{
|
||||
for (int a = 0; a < MAX_FILTERS; a++)
|
||||
{
|
||||
if (filters[a].inuse && filters[a].pid == pid && filters[a].tid == tid)
|
||||
{
|
||||
close(filters[a].handle);
|
||||
// dsyslog("Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid);
|
||||
filters[a].inuse = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** */
|
||||
bool cSIProcessor::ShutDownFilters(void)
|
||||
{
|
||||
@ -1283,3 +1427,26 @@ void cSIProcessor::TriggerDump(void)
|
||||
cMutexLock MutexLock(&schedulesMutex);
|
||||
lastDump = 0;
|
||||
}
|
||||
|
||||
int cSIProcessor::GetCaDescriptors(int Source, int Transponder, int ServiceId, int BufSize, uchar *Data)
|
||||
{
|
||||
if (BufSize > 0 && Data) {
|
||||
cMutexLock MutexLock(&caDescriptorsMutex);
|
||||
int length = 0;
|
||||
for (int i = -1; ; i--) {
|
||||
const cCaDescriptor *d = caDescriptors->Get(Source, Transponder, ServiceId, i);
|
||||
if (d) {
|
||||
if (length + d->Length() <= BufSize) {
|
||||
memcpy(Data + length, d->Data(), d->Length());
|
||||
length += d->Length();
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
16
eit.h
16
eit.h
@ -16,7 +16,7 @@
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* $Id: eit.h 1.22 2002/11/24 12:45:55 kls Exp $
|
||||
* $Id: eit.h 1.23 2003/01/04 10:12:54 kls Exp $
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __EIT_H
|
||||
@ -134,21 +134,29 @@ typedef struct sip_filter {
|
||||
|
||||
}SIP_FILTER;
|
||||
|
||||
class cCaDescriptor;
|
||||
class cCaDescriptors;
|
||||
|
||||
class cSIProcessor : public cThread {
|
||||
private:
|
||||
static int numSIProcessors;
|
||||
static cSchedules *schedules;
|
||||
static cMutex schedulesMutex;
|
||||
static cCaDescriptors *caDescriptors;
|
||||
static cMutex caDescriptorsMutex;
|
||||
static const char *epgDataFileName;
|
||||
static time_t lastDump;
|
||||
bool masterSIProcessor;
|
||||
int currentSource;
|
||||
int currentTransponder;
|
||||
int pmtIndex;
|
||||
int pmtPid;
|
||||
SIP_FILTER *filters;
|
||||
char *fileName;
|
||||
bool active;
|
||||
void Action(void);
|
||||
bool AddFilter(u_char pid, u_char tid);
|
||||
bool DelFilter(u_char pid, u_char tid);
|
||||
bool ShutDownFilters(void);
|
||||
public:
|
||||
cSIProcessor(const char *FileName);
|
||||
@ -159,6 +167,12 @@ public:
|
||||
// Caller must provide a cMutexLock which has to survive the entire
|
||||
// time the returned cSchedules is accessed. Once the cSchedules is no
|
||||
// longer used, the cMutexLock must be destroyed.
|
||||
static int GetCaDescriptors(int Source, int Transponder, int ServiceId, int BufSize, uchar *Data);
|
||||
///< Gets all CA descriptors for a given channel.
|
||||
///< Copies all available CA descriptors for the given Source, Transponder and ServiceId
|
||||
///< into the provided buffer at Data (at most BufSize bytes).
|
||||
///< \return 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.
|
||||
static bool Read(FILE *f = NULL);
|
||||
static void Clear(void);
|
||||
void SetStatus(bool On);
|
||||
|
82
i18n.c
82
i18n.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: i18n.c 1.100 2002/11/10 12:32:30 kls Exp $
|
||||
* $Id: i18n.c 1.101 2003/01/06 12:16:28 kls Exp $
|
||||
*
|
||||
* Translations provided by:
|
||||
*
|
||||
@ -664,6 +664,38 @@ const tI18nPhrase Phrases[] = {
|
||||
"Suprascrie",
|
||||
"Átírni",
|
||||
},
|
||||
{ "Menu",
|
||||
"Menü",
|
||||
"Meni",
|
||||
"Menu",
|
||||
"Menu",
|
||||
"Menu",
|
||||
"Menu",
|
||||
"Meny",
|
||||
"Valikko",
|
||||
"Menu",
|
||||
"Menu",
|
||||
"Menou",
|
||||
"Meny",
|
||||
"Meniu",
|
||||
"Menü",
|
||||
},
|
||||
{ "Reset",
|
||||
"Reset",
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
},
|
||||
// Confirmations:
|
||||
{ "Delete channel?",
|
||||
"Kanal löschen?",
|
||||
@ -1580,6 +1612,54 @@ const tI18nPhrase Phrases[] = {
|
||||
"Spatiu scazut pe disc!",
|
||||
"A merev lemez majdnem tele!",
|
||||
},
|
||||
{ "Can't open CAM menu!",
|
||||
"CAM-Menü kann nicht geöffnet werden!",
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
},
|
||||
{ "Can't reset CAM!",
|
||||
"CAM-Reset fehlgeschlagen!",
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
},
|
||||
{ "CAM has been reset",
|
||||
"CAM wurde zurückgesetzt!",
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
"",//TODO
|
||||
},
|
||||
// Setup pages:
|
||||
{ "OSD",
|
||||
"OSD",
|
||||
|
@ -315,6 +315,29 @@ struct Descriptor {
|
||||
};
|
||||
|
||||
|
||||
/* ConditionalAccessDescriptor */
|
||||
|
||||
struct ConditionalAccessDescriptor {
|
||||
struct NODE Node;
|
||||
unsigned short Tag;
|
||||
unsigned short Amount; /* Data */
|
||||
unsigned char *Data;
|
||||
};
|
||||
|
||||
#define CreateConditionalAccessDescriptor(descr, amount, data) \
|
||||
do \
|
||||
{ \
|
||||
unsigned char *tmpptr; \
|
||||
\
|
||||
xMemAlloc (amount, &tmpptr); \
|
||||
memcpy (tmpptr, data, amount); \
|
||||
xCreateNode (((struct ConditionalAccessDescriptor *)descr), NULL); \
|
||||
((struct ConditionalAccessDescriptor *)descr)->Tag = DESCR_CA; \
|
||||
((struct ConditionalAccessDescriptor *)descr)->Amount = amount; \
|
||||
((struct ConditionalAccessDescriptor *)descr)->Data = tmpptr; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Iso639LanguageDescriptor */
|
||||
|
||||
struct Iso639LanguageDescriptor {
|
||||
|
@ -705,6 +705,12 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer)
|
||||
HILO (CastTimeShiftedEventDescriptor(Ptr)->reference_event_id));
|
||||
break;
|
||||
|
||||
case DESCR_CA:
|
||||
CreateConditionalAccessDescriptor (Descriptor,
|
||||
*(Ptr + 1) + 2, // we'll need the entire raw data!
|
||||
Ptr);
|
||||
break;
|
||||
|
||||
case DESCR_ISO_639_LANGUAGE:
|
||||
CreateIso639LanguageDescriptor (Descriptor,
|
||||
CastIso639LanguageDescriptor(Buffer)->lang_code1,
|
||||
@ -790,7 +796,6 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer)
|
||||
case DESCR_DATA_STREAM_ALIGN:
|
||||
case DESCR_TARGET_BACKGRID:
|
||||
case DESCR_VIDEO_WINDOW:
|
||||
case DESCR_CA:
|
||||
case DESCR_SYSTEM_CLOCK:
|
||||
case DESCR_MULTIPLEX_BUFFER_UTIL:
|
||||
case DESCR_COPYRIGHT:
|
||||
|
173
menu.c
173
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 1.229 2002/12/22 12:40:43 kls Exp $
|
||||
* $Id: menu.c 1.230 2003/01/06 13:35:38 kls Exp $
|
||||
*/
|
||||
|
||||
#include "menu.h"
|
||||
@ -1521,6 +1521,117 @@ eOSState cMenuCommands::ProcessKey(eKeys Key)
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuCam --------------------------------------------------------------
|
||||
|
||||
cMenuCam::cMenuCam(cCiMenu *CiMenu)
|
||||
:cOsdMenu("")
|
||||
{
|
||||
ciMenu = CiMenu;
|
||||
selected = false;
|
||||
if (ciMenu->Selectable())
|
||||
SetHasHotkeys();
|
||||
SetTitle(ciMenu->TitleText() ? ciMenu->TitleText() : "CAM");
|
||||
for (int i = 0; i < ciMenu->NumEntries(); i++)
|
||||
Add(new cOsdItem(hk(ciMenu->Entry(i))));
|
||||
//XXX implement a clean way of displaying this:
|
||||
Add(new cOsdItem(ciMenu->SubTitleText()));
|
||||
Add(new cOsdItem(ciMenu->BottomText()));
|
||||
Display();
|
||||
}
|
||||
|
||||
cMenuCam::~cMenuCam()
|
||||
{
|
||||
if (!selected)
|
||||
ciMenu->Cancel();
|
||||
delete ciMenu;
|
||||
}
|
||||
|
||||
eOSState cMenuCam::Select(void)
|
||||
{
|
||||
if (ciMenu->Selectable()) {
|
||||
ciMenu->Select(Current());
|
||||
selected = true;
|
||||
return osEnd;
|
||||
}
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
eOSState cMenuCam::ProcessKey(eKeys Key)
|
||||
{
|
||||
eOSState state = cOsdMenu::ProcessKey(Key);
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kOk: return Select();
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cMenuCamEnquiry -------------------------------------------------------
|
||||
|
||||
//XXX this is just quick and dirty - make this a separate display object
|
||||
cMenuCamEnquiry::cMenuCamEnquiry(cCiEnquiry *CiEnquiry)
|
||||
:cOsdMenu("")
|
||||
{
|
||||
ciEnquiry = CiEnquiry;
|
||||
replied = false;
|
||||
SetTitle(ciEnquiry->Text() ? ciEnquiry->Text() : "CAM");
|
||||
Display();
|
||||
}
|
||||
|
||||
cMenuCamEnquiry::~cMenuCamEnquiry()
|
||||
{
|
||||
if (!replied)
|
||||
ciEnquiry->Cancel();
|
||||
delete ciEnquiry;
|
||||
}
|
||||
|
||||
eOSState cMenuCamEnquiry::Reply(void)
|
||||
{
|
||||
ciEnquiry->Reply("1234");//XXX implement actual user input
|
||||
replied = true;
|
||||
return osEnd;
|
||||
}
|
||||
|
||||
eOSState cMenuCamEnquiry::ProcessKey(eKeys Key)
|
||||
{
|
||||
eOSState state = cOsdMenu::ProcessKey(Key);
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kOk: return Reply();
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- CamControl ------------------------------------------------------------
|
||||
|
||||
cOsdObject *CamControl(void)
|
||||
{
|
||||
for (int d = 0; d < cDevice::NumDevices(); d++) {
|
||||
cDevice *Device = cDevice::GetDevice(d);
|
||||
if (Device) {
|
||||
cCiHandler *CiHandler = Device->CiHandler();
|
||||
if (CiHandler) {
|
||||
CiHandler->Process();
|
||||
cCiMenu *CiMenu = CiHandler->GetMenu();
|
||||
if (CiMenu)
|
||||
return new cMenuCam(CiMenu);
|
||||
else {
|
||||
cCiEnquiry *CiEnquiry = CiHandler->GetEnquiry();
|
||||
if (CiEnquiry)
|
||||
return new cMenuCamEnquiry(CiEnquiry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// --- cMenuRecordingItem ----------------------------------------------------
|
||||
|
||||
class cMenuRecordingItem : public cOsdItem {
|
||||
@ -1950,6 +2061,12 @@ eOSState cMenuSetupLNB::ProcessKey(eKeys Key)
|
||||
// --- cMenuSetupCICAM -------------------------------------------------------
|
||||
|
||||
class cMenuSetupCICAM : public cMenuSetupBase {
|
||||
private:
|
||||
int helpKeys;
|
||||
void SetHelpKeys(void);
|
||||
cCiHandler *GetCurrentCiHandler(void);
|
||||
eOSState Menu(void);
|
||||
eOSState Reset(void);
|
||||
public:
|
||||
cMenuSetupCICAM(void);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
@ -1957,6 +2074,7 @@ public:
|
||||
|
||||
cMenuSetupCICAM::cMenuSetupCICAM(void)
|
||||
{
|
||||
helpKeys = -1;
|
||||
SetSection(tr("CICAM"));
|
||||
for (int d = 0; d < cDevice::NumDevices(); d++) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
@ -1965,6 +2083,46 @@ cMenuSetupCICAM::cMenuSetupCICAM(void)
|
||||
Add(new cMenuEditCaItem(buffer, &data.CaCaps[d][i]));
|
||||
}
|
||||
}
|
||||
SetHelpKeys();
|
||||
}
|
||||
|
||||
cCiHandler *cMenuSetupCICAM::GetCurrentCiHandler(void)
|
||||
{
|
||||
cDevice *Device = cDevice::GetDevice(Current() / 2);
|
||||
return Device ? Device->CiHandler() : NULL;
|
||||
}
|
||||
|
||||
void cMenuSetupCICAM::SetHelpKeys(void)
|
||||
{
|
||||
int NewHelpKeys = helpKeys;
|
||||
NewHelpKeys = GetCurrentCiHandler() ? 1 : 0;
|
||||
if (NewHelpKeys != helpKeys) {
|
||||
switch (NewHelpKeys) {
|
||||
case 0: SetHelp(NULL); break;
|
||||
case 1: SetHelp(tr("Menu"), tr("Reset"));
|
||||
}
|
||||
helpKeys = NewHelpKeys;
|
||||
}
|
||||
}
|
||||
|
||||
eOSState cMenuSetupCICAM::Menu(void)
|
||||
{
|
||||
cCiHandler *CiHandler = GetCurrentCiHandler();
|
||||
if (CiHandler && CiHandler->EnterMenu())
|
||||
return osEnd; // the CAM menu will be executed explicitly from the main loop
|
||||
else
|
||||
Interface->Error(tr("Can't open CAM menu!"));
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
eOSState cMenuSetupCICAM::Reset(void)
|
||||
{
|
||||
cCiHandler *CiHandler = GetCurrentCiHandler();
|
||||
if (CiHandler && CiHandler->Reset())
|
||||
Interface->Info(tr("CAM has been reset"));
|
||||
else
|
||||
Interface->Error(tr("Can't reset CAM!"));
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
eOSState cMenuSetupCICAM::ProcessKey(eKeys Key)
|
||||
@ -1973,6 +2131,19 @@ eOSState cMenuSetupCICAM::ProcessKey(eKeys Key)
|
||||
|
||||
if (state == osBack && Key == kOk)
|
||||
cDevice::SetCaCaps();
|
||||
else if (state == osUnknown) {
|
||||
switch (Key) {
|
||||
case kRed: if (helpKeys == 1)
|
||||
return Menu();
|
||||
break;
|
||||
case kGreen: if (helpKeys == 1)
|
||||
return Reset();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (Key != kNone)
|
||||
SetHelpKeys();
|
||||
return state;
|
||||
}
|
||||
|
||||
|
27
menu.h
27
menu.h
@ -4,12 +4,13 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: menu.h 1.51 2002/11/30 15:55:39 kls Exp $
|
||||
* $Id: menu.h 1.52 2003/01/06 10:04:05 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __MENU_H
|
||||
#define __MENU_H
|
||||
|
||||
#include "ci.h"
|
||||
#include "device.h"
|
||||
#include "osd.h"
|
||||
#include "dvbplayer.h"
|
||||
@ -58,6 +59,30 @@ public:
|
||||
eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
class cMenuCam : public cOsdMenu {
|
||||
private:
|
||||
cCiMenu *ciMenu;
|
||||
bool selected;
|
||||
eOSState Select(void);
|
||||
public:
|
||||
cMenuCam(cCiMenu *CiMenu);
|
||||
virtual ~cMenuCam();
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
class cMenuCamEnquiry : public cOsdMenu {
|
||||
private:
|
||||
cCiEnquiry *ciEnquiry;
|
||||
bool replied;
|
||||
eOSState Reply(void);
|
||||
public:
|
||||
cMenuCamEnquiry(cCiEnquiry *CiEnquiry);
|
||||
virtual ~cMenuCamEnquiry();
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
cOsdObject *CamControl(void);
|
||||
|
||||
class cMenuRecordingItem;
|
||||
|
||||
class cMenuRecordings : public cOsdMenu {
|
||||
|
5
vdr.c
5
vdr.c
@ -22,7 +22,7 @@
|
||||
*
|
||||
* The project's page is at http://www.cadsoft.de/people/kls/vdr
|
||||
*
|
||||
* $Id: vdr.c 1.139 2002/12/13 14:30:00 kls Exp $
|
||||
* $Id: vdr.c 1.140 2003/01/06 11:14:50 kls Exp $
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
@ -468,6 +468,9 @@ int main(int argc, char *argv[])
|
||||
Timer->SetPending(true);
|
||||
}
|
||||
}
|
||||
// CAM control:
|
||||
if (!Menu)
|
||||
Menu = CamControl();
|
||||
// User Input:
|
||||
cOsdObject *Interact = Menu ? Menu : cControl::Control();
|
||||
eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse());
|
||||
|
Loading…
Reference in New Issue
Block a user