mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented automatic PID switching and channel detection
This commit is contained in:
parent
3a1058fe1f
commit
8976ebcec5
@ -216,6 +216,8 @@ Andreas Schultz <aschultz@warp10.net>
|
|||||||
for implementing the TerrestrialDeliverySystemDescriptor in libdtv
|
for implementing the TerrestrialDeliverySystemDescriptor in libdtv
|
||||||
for fixing setting the locking pid after a timed wait
|
for fixing setting the locking pid after a timed wait
|
||||||
for changing thread handling to make it work with NPTL ("Native Posix Thread Library")
|
for changing thread handling to make it work with NPTL ("Native Posix Thread Library")
|
||||||
|
for his 'autopid' patch which was helpful when implementing automatic
|
||||||
|
channel data gathering
|
||||||
|
|
||||||
Aaron Holtzman
|
Aaron Holtzman
|
||||||
for writing 'ac3dec'
|
for writing 'ac3dec'
|
||||||
|
25
HISTORY
25
HISTORY
@ -2470,7 +2470,7 @@ Video Disk Recorder Revision History
|
|||||||
|
|
||||||
- Final release of version 1.2.6.
|
- Final release of version 1.2.6.
|
||||||
|
|
||||||
2003-12-23: Version 1.3.0
|
2004-01-04: Version 1.3.0
|
||||||
|
|
||||||
- Changed thread handling to make it work with NPTL ("Native Posix Thread Library").
|
- Changed thread handling to make it work with NPTL ("Native Posix Thread Library").
|
||||||
Thanks to Jon Burgess, Andreas Schultz, Werner Fink and Stefan Huelswitt.
|
Thanks to Jon Burgess, Andreas Schultz, Werner Fink and Stefan Huelswitt.
|
||||||
@ -2482,6 +2482,7 @@ Video Disk Recorder Revision History
|
|||||||
instead of explicit 'dsyslog()' calls inside their Action() function in order
|
instead of explicit 'dsyslog()' calls inside their Action() function in order
|
||||||
to support logging the thread ids.
|
to support logging the thread ids.
|
||||||
- Added "Slovak Link" and "Czech Link" to 'ca.conf' (thanks to Emil Petersky).
|
- Added "Slovak Link" and "Czech Link" to 'ca.conf' (thanks to Emil Petersky).
|
||||||
|
However, 'ca.conf' is now pretty much obsolete due to the automatic CA handling.
|
||||||
- Mutexes are now created with PTHREAD_MUTEX_ERRORCHECK_NP, which makes the
|
- Mutexes are now created with PTHREAD_MUTEX_ERRORCHECK_NP, which makes the
|
||||||
'lockingTid' stuff obsolete (thanks to Stefan Huelswitt).
|
'lockingTid' stuff obsolete (thanks to Stefan Huelswitt).
|
||||||
- Changed font handling to allow language specific character sets.
|
- Changed font handling to allow language specific character sets.
|
||||||
@ -2499,7 +2500,7 @@ Video Disk Recorder Revision History
|
|||||||
shortened to 'description'.
|
shortened to 'description'.
|
||||||
- Replaced 'libdtv' with 'libsi' (thanks to Marcel Wiesweg), which is thread
|
- Replaced 'libdtv' with 'libsi' (thanks to Marcel Wiesweg), which is thread
|
||||||
safe and can be used by multiple section filters simultaneously.
|
safe and can be used by multiple section filters simultaneously.
|
||||||
- Added 'cRWlock' to 'thread.[hc]'. Note that all plugin Makefiles need to
|
- Added 'cRwLock' to 'thread.[hc]'. Note that all plugin Makefiles need to
|
||||||
define _GNU_SOURCE for this to work (see the example plugin Makefiles and
|
define _GNU_SOURCE for this to work (see the example plugin Makefiles and
|
||||||
'newplugin').
|
'newplugin').
|
||||||
- Fixed a problem with crc32 in SI handling on 64bit systems (thanks to Pedro
|
- Fixed a problem with crc32 in SI handling on 64bit systems (thanks to Pedro
|
||||||
@ -2512,3 +2513,23 @@ Video Disk Recorder Revision History
|
|||||||
sections, depending on where they are found in the PMT (thanks to Hans-Peter
|
sections, depending on where they are found in the PMT (thanks to Hans-Peter
|
||||||
Raschke for reporting this one). This should make SkyCrypt CAMs work.
|
Raschke for reporting this one). This should make SkyCrypt CAMs work.
|
||||||
- Now using the 'version number' of EPG events to avoid unnecessary work.
|
- Now using the 'version number' of EPG events to avoid unnecessary work.
|
||||||
|
- Channel data is now automatically derived from the DVB data stream (inspired
|
||||||
|
by the 'autopid' patch from Andreas Schultz).
|
||||||
|
- The current channel is now automatically re-tuned if the PIDs or other settings
|
||||||
|
change. If a recording is going on on a channel that has a change in its
|
||||||
|
settings, the recording will be stopped and immediately restarted to use the
|
||||||
|
new channel settings.
|
||||||
|
- EPG events now use the complete channel ID with NID, TID and SID.
|
||||||
|
- Channel names in 'channels.conf' can now have a short form, as provided
|
||||||
|
by some tv stations (see man vdr(5)). Currently channels that provide short
|
||||||
|
names in addition to long ones are listed in the OSD as "short,long name",
|
||||||
|
as in "RTL,RTL Television". The short names will be used explicitly later.
|
||||||
|
- The Ca parameter in 'channels.conf' has been extended and now contains all the
|
||||||
|
CA system ids for the given channel. When switching to a channel VDR now tests
|
||||||
|
for a device that provides one of these CA system ids. The devices automatically
|
||||||
|
get their supported ids from the CI handler.
|
||||||
|
- The values in 'ca.conf' are currently without any real meaning. Whether or not
|
||||||
|
a channel with conditional access can be received is now determined automatically
|
||||||
|
by evaluating its CA descriptors and comparing them to the CA system ids
|
||||||
|
provided by the installed CAM. Only the special values 1-16 are used to assign
|
||||||
|
a channel to a particular device.
|
||||||
|
4
Makefile
4
Makefile
@ -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: Makefile 1.61 2003/12/21 14:45:27 kls Exp $
|
# $Id: Makefile 1.62 2003/12/25 13:38:56 kls Exp $
|
||||||
|
|
||||||
.DELETE_ON_ERROR:
|
.DELETE_ON_ERROR:
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ SILIB = $(LSIDIR)/libsi.a
|
|||||||
OBJS = audio.o channels.o ci.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 epg.o filter.o font.o i18n.o interface.o keys.o\
|
dvbplayer.o dvbspu.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\
|
||||||
lirc.o menu.o menuitems.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\
|
lirc.o menu.o menuitems.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\
|
||||||
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sections.o sources.o\
|
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o sources.o\
|
||||||
spu.o status.o svdrp.o thread.o timers.o tools.o transfer.o vdr.o videodir.o
|
spu.o status.o svdrp.o thread.o timers.o tools.o transfer.o vdr.o videodir.o
|
||||||
|
|
||||||
FIXFONT_ISO8859_1 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
|
FIXFONT_ISO8859_1 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
|
||||||
|
@ -12,3 +12,7 @@ VDR Plugin 'sky' Revision History
|
|||||||
2003-05-09: Version 0.1.1
|
2003-05-09: Version 0.1.1
|
||||||
|
|
||||||
- Changed Start() to Initialize().
|
- Changed Start() to Initialize().
|
||||||
|
|
||||||
|
2004-01-04: Version 0.2.0
|
||||||
|
|
||||||
|
- Implemented automatic PID switching and channel detection
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* See the README file for copyright information and how to reach the author.
|
* See the README file for copyright information and how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: sky.c 1.3 2003/05/09 15:27:16 kls Exp $
|
* $Id: sky.c 1.4 2004/01/04 12:30:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
#include <vdr/plugin.h>
|
#include <vdr/plugin.h>
|
||||||
#include <vdr/sources.h>
|
#include <vdr/sources.h>
|
||||||
|
|
||||||
static const char *VERSION = "0.1.1";
|
static const char *VERSION = "0.2.0";
|
||||||
static const char *DESCRIPTION = "Sky Digibox interface";
|
static const char *DESCRIPTION = "Sky Digibox interface";
|
||||||
|
|
||||||
// --- cDigiboxDevice --------------------------------------------------------
|
// --- cDigiboxDevice --------------------------------------------------------
|
||||||
@ -37,6 +37,7 @@ public:
|
|||||||
cDigiboxDevice(void);
|
cDigiboxDevice(void);
|
||||||
virtual ~cDigiboxDevice();
|
virtual ~cDigiboxDevice();
|
||||||
virtual bool ProvidesSource(int Source) const;
|
virtual bool ProvidesSource(int Source) const;
|
||||||
|
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
||||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSetChannel = NULL) const;
|
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSetChannel = NULL) const;
|
||||||
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
||||||
};
|
};
|
||||||
@ -137,13 +138,18 @@ bool cDigiboxDevice::ProvidesSource(int Source) const
|
|||||||
return source == Source;
|
return source == Source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cDigiboxDevice::ProvidesTransponder(const cChannel *Channel) const
|
||||||
|
{
|
||||||
|
return false; // can't provide any actual transponder
|
||||||
|
}
|
||||||
|
|
||||||
bool cDigiboxDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
bool cDigiboxDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
bool hasPriority = Priority < 0 || Priority > this->Priority();
|
bool hasPriority = Priority < 0 || Priority > this->Priority();
|
||||||
bool needsDetachReceivers = true;
|
bool needsDetachReceivers = true;
|
||||||
|
|
||||||
if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel->Ca())) {
|
if (ProvidesSource(Channel->Source()) && Channel->Ca() == 0x30) {//XXX
|
||||||
if (Receiving()) {
|
if (Receiving()) {
|
||||||
if (digiboxChannelNumber == Channel->Frequency()) {
|
if (digiboxChannelNumber == Channel->Frequency()) {
|
||||||
needsDetachReceivers = false;
|
needsDetachReceivers = false;
|
||||||
|
223
channels.c
223
channels.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: channels.c 1.16 2003/10/17 15:42:40 kls Exp $
|
* $Id: channels.c 1.17 2004/01/04 12:28:49 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
@ -159,6 +159,7 @@ char *cChannel::buffer = NULL;
|
|||||||
|
|
||||||
cChannel::cChannel(void)
|
cChannel::cChannel(void)
|
||||||
{
|
{
|
||||||
|
memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__);
|
||||||
strcpy(name, "Pro7");
|
strcpy(name, "Pro7");
|
||||||
frequency = 12480;
|
frequency = 12480;
|
||||||
source = cSource::FromString("S19.2E");
|
source = cSource::FromString("S19.2E");
|
||||||
@ -170,7 +171,7 @@ cChannel::cChannel(void)
|
|||||||
dpid1 = 257;
|
dpid1 = 257;
|
||||||
dpid2 = 0;
|
dpid2 = 0;
|
||||||
tpid = 32;
|
tpid = 32;
|
||||||
ca = 0;
|
caids[0] = 0;
|
||||||
nid = 0;
|
nid = 0;
|
||||||
tid = 0;
|
tid = 0;
|
||||||
sid = 888;
|
sid = 888;
|
||||||
@ -186,6 +187,28 @@ cChannel::cChannel(void)
|
|||||||
transmission = TRANSMISSION_MODE_AUTO;
|
transmission = TRANSMISSION_MODE_AUTO;
|
||||||
guard = GUARD_INTERVAL_AUTO;
|
guard = GUARD_INTERVAL_AUTO;
|
||||||
hierarchy = HIERARCHY_AUTO;
|
hierarchy = HIERARCHY_AUTO;
|
||||||
|
modification = CHANNELMOD_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
cChannel::cChannel(const cChannel *Channel)
|
||||||
|
{
|
||||||
|
*this = *Channel;
|
||||||
|
*name = 0;
|
||||||
|
vpid = 0;
|
||||||
|
ppid = 0;
|
||||||
|
apid1 = 0;
|
||||||
|
apid2 = 0;
|
||||||
|
dpid1 = 0;
|
||||||
|
dpid2 = 0;
|
||||||
|
tpid = 0;
|
||||||
|
caids[0] = 0;
|
||||||
|
nid = 0;
|
||||||
|
tid = 0;
|
||||||
|
sid = 0;
|
||||||
|
rid = 0;
|
||||||
|
number = 0;
|
||||||
|
groupSep = false;
|
||||||
|
modification = CHANNELMOD_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
cChannel& cChannel::operator= (const cChannel &Channel)
|
cChannel& cChannel::operator= (const cChannel &Channel)
|
||||||
@ -194,16 +217,117 @@ cChannel& cChannel::operator= (const cChannel &Channel)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int MHz(int frequency)
|
int cChannel::Transponder(void) const
|
||||||
{
|
{
|
||||||
while (frequency > 20000)
|
int tf = frequency;
|
||||||
frequency /= 1000;
|
while (tf > 20000)
|
||||||
return frequency;
|
tf /= 1000;
|
||||||
|
return tf;
|
||||||
}
|
}
|
||||||
|
|
||||||
tChannelID cChannel::GetChannelID(void) const
|
tChannelID cChannel::GetChannelID(void) const
|
||||||
{
|
{
|
||||||
return tChannelID(source, nid, nid ? tid : MHz(frequency), sid, rid);
|
return tChannelID(source, nid, nid ? tid : Transponder(), sid, rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cChannel::Modification(int Mask)
|
||||||
|
{
|
||||||
|
int Result = modification & Mask;
|
||||||
|
modification = CHANNELMOD_NONE;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cChannel::SetId(int Nid, int Tid, int Sid, int Rid, bool Log)
|
||||||
|
{
|
||||||
|
if (nid != Nid || tid != Tid || sid != Sid || rid != Rid) {
|
||||||
|
if (Log)
|
||||||
|
dsyslog("changing id of channel %d from %d-%d-%d-%d to %d-%d-%d-%d", Number(), nid, tid, sid, rid, Nid, Tid, Sid, Rid);
|
||||||
|
nid = Nid;
|
||||||
|
tid = Tid;
|
||||||
|
sid = Sid;
|
||||||
|
rid = Rid;
|
||||||
|
modification |= CHANNELMOD_ID;
|
||||||
|
Channels.SetModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cChannel::SetName(const char *Name, bool Log)
|
||||||
|
{
|
||||||
|
if (!isempty(Name) && strcmp(name, Name) != 0) {
|
||||||
|
if (Log)
|
||||||
|
dsyslog("changing name of channel %d from '%s' to '%s'", Number(), name, Name);
|
||||||
|
strn0cpy(name, Name, MaxChannelName);
|
||||||
|
modification |= CHANNELMOD_NAME;
|
||||||
|
Channels.SetModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cChannel::SetPids(int Vpid, int Ppid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid)
|
||||||
|
{
|
||||||
|
//XXX if (vpid != Vpid || ppid != Ppid || apid1 != Apid1 || apid2 != Apid2 || dpid1 != Dpid1 || dpid2 != Dpid2 || tpid != Tpid) {
|
||||||
|
if (vpid != Vpid || ppid != Ppid || apid1 != Apid1 || (Apid2 && apid2 != Apid2) || dpid1 != Dpid1 || dpid2 != Dpid2 || tpid != Tpid) {
|
||||||
|
dsyslog("changing pids of channel %d from %d+%d:%d,%d;%d,%d:%d to %d+%d:%d,%d;%d,%d:%d", Number(), vpid, ppid, apid1, apid2, dpid1, dpid2, tpid, Vpid, Ppid, Apid1, Apid2, Dpid1, Dpid2, Tpid);
|
||||||
|
vpid = Vpid;
|
||||||
|
ppid = Ppid;
|
||||||
|
apid1 = Apid1;
|
||||||
|
if (Apid2)//XXX should we actually react here?
|
||||||
|
apid2 = Apid2;
|
||||||
|
dpid1 = Dpid1;
|
||||||
|
dpid2 = Dpid2;
|
||||||
|
tpid = Tpid;
|
||||||
|
modification |= CHANNELMOD_PIDS;
|
||||||
|
Channels.SetModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cChannel::SetCaIds(const int *CaIds)
|
||||||
|
{
|
||||||
|
if (caids[0] && caids[0] <= 0x00FF)
|
||||||
|
return; // special values will not be overwritten
|
||||||
|
bool modified = false;
|
||||||
|
for (int i = 0; i < MAXCAIDS; i++) {
|
||||||
|
if (caids[i] != CaIds[i]) {
|
||||||
|
modified = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!caids[i] || !CaIds[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (modified) {
|
||||||
|
char OldCaIdsBuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia
|
||||||
|
char NewCaIdsBuf[MAXCAIDS * 5 + 10];
|
||||||
|
char *qo = OldCaIdsBuf;
|
||||||
|
char *qn = NewCaIdsBuf;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < MAXCAIDS; i++) {
|
||||||
|
if (i == 0 || caids[i])
|
||||||
|
qo += snprintf(qo, sizeof(OldCaIdsBuf), "%s%X", i > 0 ? "," : "", caids[i]);
|
||||||
|
if (!caids[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (i = 0; i < MAXCAIDS; i++) {
|
||||||
|
if (i == 0 || CaIds[i])
|
||||||
|
qn += snprintf(qn, sizeof(NewCaIdsBuf), "%s%X", i > 0 ? "," : "", CaIds[i]);
|
||||||
|
caids[i] = CaIds[i];
|
||||||
|
if (!CaIds[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
caids[i] = 0;
|
||||||
|
*qo = *qn = 0;
|
||||||
|
dsyslog("changing caids of channel %d from %s to %s", Number(), OldCaIdsBuf, NewCaIdsBuf);
|
||||||
|
modification |= CHANNELMOD_CA;
|
||||||
|
Channels.SetModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cChannel::SetCaDescriptors(int Level)
|
||||||
|
{
|
||||||
|
if (Level > 0) {
|
||||||
|
modification |= CHANNELMOD_CA;
|
||||||
|
Channels.SetModified();
|
||||||
|
if (Level > 1)
|
||||||
|
dsyslog("changing ca descriptors of channel %d", Number());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PrintParameter(char *p, char Name, int Value)
|
static int PrintParameter(char *p, char Name, int Value)
|
||||||
@ -290,10 +414,10 @@ const char *cChannel::ToText(cChannel *Channel)
|
|||||||
char vpidbuf[32];
|
char vpidbuf[32];
|
||||||
char *q = vpidbuf;
|
char *q = vpidbuf;
|
||||||
q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid);
|
q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid);
|
||||||
if (Channel->ppid)
|
if (Channel->ppid && Channel->ppid != Channel->vpid)
|
||||||
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
|
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
|
||||||
*q = 0;
|
*q = 0;
|
||||||
char apidbuf[32];
|
char apidbuf[MAXAPIDS * 2 * 6 + 10]; // 2: Apids and Dpids, 6: 5 digits plus delimiting ',' or ';', 10: paranoia
|
||||||
q = apidbuf;
|
q = apidbuf;
|
||||||
q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1);
|
q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1);
|
||||||
if (Channel->apid2)
|
if (Channel->apid2)
|
||||||
@ -303,7 +427,16 @@ const char *cChannel::ToText(cChannel *Channel)
|
|||||||
if (Channel->dpid2)
|
if (Channel->dpid2)
|
||||||
q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->dpid2);
|
q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->dpid2);
|
||||||
*q = 0;
|
*q = 0;
|
||||||
asprintf(&buffer, "%s:%d:%s:%s:%d:%s:%s:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->ParametersToString(), cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, Channel->tpid, Channel->ca, Channel->sid, Channel->nid, Channel->tid, Channel->rid);
|
char caidbuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia
|
||||||
|
q = caidbuf;
|
||||||
|
for (int i = 0; i < MAXCAIDS; i++) {
|
||||||
|
if (i == 0 || Channel->caids[i])
|
||||||
|
q += snprintf(q, sizeof(caidbuf), "%s%X", i > 0 ? "," : "", Channel->caids[i]);
|
||||||
|
if (!Channel->caids[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*q = 0;
|
||||||
|
asprintf(&buffer, "%s:%d:%s:%s:%d:%s:%s:%d:%s:%d:%d:%d:%d\n", s, Channel->frequency, Channel->ParametersToString(), cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, Channel->tpid, caidbuf, Channel->sid, Channel->nid, Channel->tid, Channel->rid);
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -336,12 +469,16 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
|
|||||||
char *parambuf = NULL;
|
char *parambuf = NULL;
|
||||||
char *vpidbuf = NULL;
|
char *vpidbuf = NULL;
|
||||||
char *apidbuf = NULL;
|
char *apidbuf = NULL;
|
||||||
int fields = sscanf(s, "%a[^:]:%d :%a[^:]:%a[^:] :%d :%a[^:]:%a[^:]:%d :%d :%d :%d :%d :%d ", &namebuf, &frequency, ¶mbuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpid, &ca, &sid, &nid, &tid, &rid);
|
char *caidbuf = NULL;
|
||||||
|
int fields = sscanf(s, "%a[^:]:%d :%a[^:]:%a[^:] :%d :%a[^:]:%a[^:]:%d :%a[^:]:%d :%d :%d :%d ", &namebuf, &frequency, ¶mbuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpid, &caidbuf, &sid, &nid, &tid, &rid);
|
||||||
if (fields >= 9) {
|
if (fields >= 9) {
|
||||||
if (fields == 9) {
|
if (fields == 9) {
|
||||||
// allow reading of old format
|
// allow reading of old format
|
||||||
sid = ca;
|
sid = atoi(caidbuf);
|
||||||
ca = tpid;
|
delete caidbuf;
|
||||||
|
caidbuf = NULL;
|
||||||
|
caids[0] = tpid;
|
||||||
|
caids[1] = 0;
|
||||||
tpid = 0;
|
tpid = 0;
|
||||||
}
|
}
|
||||||
vpid = ppid = 0;
|
vpid = ppid = 0;
|
||||||
@ -350,24 +487,46 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
|
|||||||
ok = false;
|
ok = false;
|
||||||
if (parambuf && sourcebuf && vpidbuf && apidbuf) {
|
if (parambuf && sourcebuf && vpidbuf && apidbuf) {
|
||||||
ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0;
|
ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0;
|
||||||
|
|
||||||
char *p = strchr(vpidbuf, '+');
|
char *p = strchr(vpidbuf, '+');
|
||||||
if (p)
|
if (p)
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
sscanf(vpidbuf, "%d", &vpid);
|
sscanf(vpidbuf, "%d", &vpid);
|
||||||
if (p)
|
if (p)
|
||||||
sscanf(p, "%d", &ppid);
|
sscanf(p, "%d", &ppid);
|
||||||
|
else
|
||||||
|
ppid = vpid;
|
||||||
|
|
||||||
p = strchr(apidbuf, ';');
|
p = strchr(apidbuf, ';');
|
||||||
if (p)
|
if (p)
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
sscanf(apidbuf, "%d ,%d ", &apid1, &apid2);
|
sscanf(apidbuf, "%d ,%d ", &apid1, &apid2);
|
||||||
if (p)
|
if (p)
|
||||||
sscanf(p, "%d ,%d ", &dpid1, &dpid2);
|
sscanf(p, "%d ,%d ", &dpid1, &dpid2);
|
||||||
|
|
||||||
|
if (caidbuf) {
|
||||||
|
char *p = caidbuf;
|
||||||
|
char *q;
|
||||||
|
int NumCaIds = 0;
|
||||||
|
while ((q = strtok(p, ",")) != NULL) {
|
||||||
|
if (NumCaIds < MAXCAIDS) {
|
||||||
|
caids[NumCaIds++] = strtol(q, NULL, 16) & 0xFFFF;
|
||||||
|
if (NumCaIds == 1 && caids[0] <= 0x00FF)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: too many CA ids!"); // no need to set ok to 'false'
|
||||||
|
p = NULL;
|
||||||
|
}
|
||||||
|
caids[NumCaIds] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
strn0cpy(name, namebuf, MaxChannelName);
|
strn0cpy(name, namebuf, MaxChannelName);
|
||||||
free(parambuf);
|
free(parambuf);
|
||||||
free(sourcebuf);
|
free(sourcebuf);
|
||||||
free(vpidbuf);
|
free(vpidbuf);
|
||||||
free(apidbuf);
|
free(apidbuf);
|
||||||
|
free(caidbuf);
|
||||||
free(namebuf);
|
free(namebuf);
|
||||||
if (!GetChannelID().Valid()) {
|
if (!GetChannelID().Valid()) {
|
||||||
esyslog("ERROR: channel data results in invalid ID!");
|
esyslog("ERROR: channel data results in invalid ID!");
|
||||||
@ -394,6 +553,12 @@ bool cChannel::Save(FILE *f)
|
|||||||
|
|
||||||
cChannels Channels;
|
cChannels Channels;
|
||||||
|
|
||||||
|
cChannels::cChannels(void)
|
||||||
|
{
|
||||||
|
maxNumber = 0;
|
||||||
|
modified = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool cChannels::Load(const char *FileName, bool AllowComments, bool MustExist)
|
bool cChannels::Load(const char *FileName, bool AllowComments, bool MustExist)
|
||||||
{
|
{
|
||||||
if (cConfig<cChannel>::Load(FileName, AllowComments, MustExist)) {
|
if (cConfig<cChannel>::Load(FileName, AllowComments, MustExist)) {
|
||||||
@ -457,10 +622,10 @@ cChannel *cChannels::GetByNumber(int Number, int SkipGap)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cChannel *cChannels::GetByServiceID(int Source, unsigned short ServiceID)
|
cChannel *cChannels::GetByServiceID(int Source, int Transponder, unsigned short ServiceID)
|
||||||
{
|
{
|
||||||
for (cChannel *channel = First(); channel; channel = Next(channel)) {
|
for (cChannel *channel = First(); channel; channel = Next(channel)) {
|
||||||
if (!channel->GroupSep() && channel->Source() == Source && channel->Sid() == ServiceID)
|
if (!channel->GroupSep() && channel->Source() == Source && ISTRANSPONDER(channel->Transponder(), Transponder) && channel->Sid() == ServiceID)
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -497,3 +662,31 @@ bool cChannels::SwitchTo(int Number)
|
|||||||
cChannel *channel = GetByNumber(Number);
|
cChannel *channel = GetByNumber(Number);
|
||||||
return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true);
|
return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cChannels::SetModified(void)
|
||||||
|
{
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cChannels::Modified(void)
|
||||||
|
{
|
||||||
|
bool Result = modified;
|
||||||
|
modified = false;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
cChannel *cChannels::NewChannel(int Source, int Transponder, const char *Name, int Nid, int Tid, int Sid, int Rid)
|
||||||
|
{
|
||||||
|
dsyslog("creating new channel '%s' on %s transponder %d with id %d-%d-%d-%d", Name, cSource::ToString(Source), Transponder, Nid, Tid, Sid, Rid);
|
||||||
|
for (cChannel *channel = First(); channel; channel = Next(channel)) {
|
||||||
|
if (!channel->GroupSep() && channel->Source() == Source && ISTRANSPONDER(channel->Transponder(), Transponder)) {
|
||||||
|
cChannel *NewChannel = new cChannel(channel);
|
||||||
|
Add(NewChannel);
|
||||||
|
ReNumber();
|
||||||
|
NewChannel->SetId(Nid, Tid, Sid, Rid, false);
|
||||||
|
NewChannel->SetName(Name, false);
|
||||||
|
return NewChannel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
52
channels.h
52
channels.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: channels.h 1.9 2003/10/26 13:32:00 kls Exp $
|
* $Id: channels.h 1.10 2004/01/04 12:26:37 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CHANNELS_H
|
#ifndef __CHANNELS_H
|
||||||
@ -12,10 +12,22 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "sources.h"
|
#include "sources.h"
|
||||||
|
#include "thread.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
#define ISTRANSPONDER(f1, f2) (abs((f1) - (f2)) < 4) //XXX
|
#define ISTRANSPONDER(f1, f2) (abs((f1) - (f2)) < 4) //XXX
|
||||||
|
|
||||||
|
#define CHANNELMOD_NONE 0x00
|
||||||
|
#define CHANNELMOD_ALL 0xFF
|
||||||
|
#define CHANNELMOD_NAME 0x01
|
||||||
|
#define CHANNELMOD_PIDS 0x02
|
||||||
|
#define CHANNELMOD_ID 0x04
|
||||||
|
#define CHANNELMOD_CA 0x10
|
||||||
|
#define CHANNELMOD_RETUNE (CHANNELMOD_PIDS | CHANNELMOD_CA)
|
||||||
|
|
||||||
|
#define MAXAPIDS 2
|
||||||
|
#define MAXCAIDS 8
|
||||||
|
|
||||||
struct tChannelParameterMap {
|
struct tChannelParameterMap {
|
||||||
int userValue;
|
int userValue;
|
||||||
int driverValue;
|
int driverValue;
|
||||||
@ -46,7 +58,7 @@ public:
|
|||||||
tChannelID(void) { source = nid = tid = sid = rid = 0; }
|
tChannelID(void) { source = nid = tid = sid = rid = 0; }
|
||||||
tChannelID(int Source, int Nid, int Tid, int Sid, int Rid = 0) { source = Source; nid = Nid; tid = Tid; sid = Sid; rid = Rid; }
|
tChannelID(int Source, int Nid, int Tid, int Sid, int Rid = 0) { source = Source; nid = Nid; tid = Tid; sid = Sid; rid = Rid; }
|
||||||
bool operator== (const tChannelID &arg) const;
|
bool operator== (const tChannelID &arg) const;
|
||||||
bool Valid(void) { return tid && sid; } // nid and rid are optional and source may be 0
|
bool Valid(void) { return tid && sid; } // nid and rid are optional and source may be 0//XXX source may not be 0???
|
||||||
tChannelID &ClrRid(void) { rid = 0; return *this; }
|
tChannelID &ClrRid(void) { rid = 0; return *this; }
|
||||||
static tChannelID FromString(const char *s);
|
static tChannelID FromString(const char *s);
|
||||||
const char *ToString(void);
|
const char *ToString(void);
|
||||||
@ -58,7 +70,7 @@ class cChannel : public cListObject {
|
|||||||
private:
|
private:
|
||||||
static char *buffer;
|
static char *buffer;
|
||||||
static const char *ToText(cChannel *Channel);
|
static const char *ToText(cChannel *Channel);
|
||||||
enum { MaxChannelName = 32 }; // 31 chars + terminating 0!
|
enum { MaxChannelName = 64 }; // 63 chars + terminating 0!
|
||||||
int __BeginData__;
|
int __BeginData__;
|
||||||
char name[MaxChannelName];
|
char name[MaxChannelName];
|
||||||
int frequency; // MHz
|
int frequency; // MHz
|
||||||
@ -69,7 +81,7 @@ private:
|
|||||||
int apid1, apid2;
|
int apid1, apid2;
|
||||||
int dpid1, dpid2;
|
int dpid1, dpid2;
|
||||||
int tpid;
|
int tpid;
|
||||||
int ca;
|
int caids[MAXCAIDS + 1]; // list is zero-terminated
|
||||||
int nid;
|
int nid;
|
||||||
int tid;
|
int tid;
|
||||||
int sid;
|
int sid;
|
||||||
@ -86,16 +98,19 @@ private:
|
|||||||
int guard;
|
int guard;
|
||||||
int hierarchy;
|
int hierarchy;
|
||||||
int __EndData__;
|
int __EndData__;
|
||||||
|
int modification;
|
||||||
const char *ParametersToString(void);
|
const char *ParametersToString(void);
|
||||||
bool StringToParameters(const char *s);
|
bool StringToParameters(const char *s);
|
||||||
public:
|
public:
|
||||||
cChannel(void);
|
cChannel(void);
|
||||||
|
cChannel(const cChannel *Channel);
|
||||||
cChannel& operator= (const cChannel &Channel);
|
cChannel& operator= (const cChannel &Channel);
|
||||||
const char *ToText(void);
|
const char *ToText(void);
|
||||||
bool Parse(const char *s, bool AllowNonUniqueID = false);
|
bool Parse(const char *s, bool AllowNonUniqueID = false);
|
||||||
bool Save(FILE *f);
|
bool Save(FILE *f);
|
||||||
const char *Name(void) const { return name; }
|
const char *Name(void) const { return name; }
|
||||||
int Frequency(void) const { return frequency; }
|
int Frequency(void) const { return frequency; } ///< Returns the actual frequency, as given in 'channels.conf'
|
||||||
|
int Transponder(void) const; ///< Returns the transponder frequency in MHz
|
||||||
int Source(void) const { return source; }
|
int Source(void) const { return source; }
|
||||||
int Srate(void) const { return srate; }
|
int Srate(void) const { return srate; }
|
||||||
int Vpid(void) const { return vpid; }
|
int Vpid(void) const { return vpid; }
|
||||||
@ -105,8 +120,11 @@ public:
|
|||||||
int Dpid1(void) const { return dpid1; }
|
int Dpid1(void) const { return dpid1; }
|
||||||
int Dpid2(void) const { return dpid2; }
|
int Dpid2(void) const { return dpid2; }
|
||||||
int Tpid(void) const { return tpid; }
|
int Tpid(void) const { return tpid; }
|
||||||
int Ca(void) const { return ca; }
|
int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; }
|
||||||
|
int Nid(void) const { return nid; }
|
||||||
|
int Tid(void) const { return tid; }
|
||||||
int Sid(void) const { return sid; }
|
int Sid(void) const { return sid; }
|
||||||
|
int Rid(void) const { return rid; }
|
||||||
int Number(void) const { return number; }
|
int Number(void) const { return number; }
|
||||||
void SetNumber(int Number) { number = Number; }
|
void SetNumber(int Number) { number = Number; }
|
||||||
bool GroupSep(void) const { return groupSep; }
|
bool GroupSep(void) const { return groupSep; }
|
||||||
@ -123,24 +141,38 @@ public:
|
|||||||
bool IsSat(void) const { return (source & cSource::st_Mask) == cSource::stSat; }
|
bool IsSat(void) const { return (source & cSource::st_Mask) == cSource::stSat; }
|
||||||
bool IsTerr(void) const { return (source & cSource::st_Mask) == cSource::stTerr; }
|
bool IsTerr(void) const { return (source & cSource::st_Mask) == cSource::stTerr; }
|
||||||
tChannelID GetChannelID(void) const;
|
tChannelID GetChannelID(void) const;
|
||||||
|
int Modification(int Mask = CHANNELMOD_ALL);
|
||||||
|
void SetId(int Nid, int Tid, int Sid, int Rid = 0, bool Log = true);
|
||||||
|
void SetName(const char *Name, bool Log = true);
|
||||||
|
void SetPids(int Vpid, int Ppid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid);
|
||||||
|
void SetCaIds(const int *CaIds); // list must be zero-terminated
|
||||||
|
void SetCaDescriptors(int Level);
|
||||||
};
|
};
|
||||||
|
|
||||||
class cChannels : public cConfig<cChannel> {
|
class cChannels : public cRwLock, public cConfig<cChannel> {
|
||||||
protected:
|
private:
|
||||||
int maxNumber;
|
int maxNumber;
|
||||||
|
bool modified;
|
||||||
|
int beingEdited;
|
||||||
public:
|
public:
|
||||||
cChannels(void) { maxNumber = 0; }
|
cChannels(void);
|
||||||
virtual bool Load(const char *FileName, bool AllowComments = false, bool MustExist = false);
|
virtual bool Load(const char *FileName, bool AllowComments = false, bool MustExist = false);
|
||||||
int GetNextGroup(int Idx); // Get next channel group
|
int GetNextGroup(int Idx); // Get next channel group
|
||||||
int GetPrevGroup(int Idx); // Get previous channel group
|
int GetPrevGroup(int Idx); // Get previous channel group
|
||||||
int GetNextNormal(int Idx); // Get next normal channel (not group)
|
int GetNextNormal(int Idx); // Get next normal channel (not group)
|
||||||
void ReNumber(void); // Recalculate 'number' based on channel type
|
void ReNumber(void); // Recalculate 'number' based on channel type
|
||||||
cChannel *GetByNumber(int Number, int SkipGap = 0);
|
cChannel *GetByNumber(int Number, int SkipGap = 0);
|
||||||
cChannel *GetByServiceID(int Source, unsigned short ServiceID);
|
cChannel *GetByServiceID(int Source, int Transponder, unsigned short ServiceID);
|
||||||
cChannel *GetByChannelID(tChannelID ChannelID, bool TryWithoutRid = false);
|
cChannel *GetByChannelID(tChannelID ChannelID, bool TryWithoutRid = false);
|
||||||
|
int BeingEdited(void) { return beingEdited; }
|
||||||
|
void IncBeingEdited(void) { beingEdited++; }
|
||||||
|
void DecBeingEdited(void) { beingEdited--; }
|
||||||
bool HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel = NULL);
|
bool HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel = NULL);
|
||||||
bool SwitchTo(int Number);
|
bool SwitchTo(int Number);
|
||||||
int MaxNumber(void) { return maxNumber; }
|
int MaxNumber(void) { return maxNumber; }
|
||||||
|
void SetModified(void);
|
||||||
|
bool Modified(void);
|
||||||
|
cChannel *NewChannel(int Source, int Transponder, const char *Name, int Nid, int Tid, int Sid, int Rid = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern cChannels Channels;
|
extern cChannels Channels;
|
||||||
|
23
ci.c
23
ci.c
@ -4,13 +4,9 @@
|
|||||||
* 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.20 2003/12/24 10:23:24 kls Exp $
|
* $Id: ci.c 1.21 2004/01/02 15:07:36 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* XXX TODO
|
|
||||||
- update CA descriptors in case they change
|
|
||||||
XXX*/
|
|
||||||
|
|
||||||
#include "ci.h"
|
#include "ci.h"
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -1570,6 +1566,23 @@ const unsigned short *cCiHandler::GetCaSystemIds(int Slot)
|
|||||||
return cas ? cas->GetCaSystemIds() : NULL;
|
return cas ? cas->GetCaSystemIds() : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cCiHandler::ProvidesCa(const unsigned short *CaSystemIds)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
for (int Slot = 0; Slot < numSlots; Slot++) {
|
||||||
|
cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot);
|
||||||
|
if (cas) {
|
||||||
|
for (const unsigned short *ids = cas->GetCaSystemIds(); ids && *ids; ids++) {
|
||||||
|
for (const unsigned short *id = CaSystemIds; *id; id++) {
|
||||||
|
if (*id == *ids)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt, int Slot)
|
bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt, int Slot)
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&mutex);
|
cMutexLock MutexLock(&mutex);
|
||||||
|
3
ci.h
3
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.11 2003/12/24 10:05:46 kls Exp $
|
* $Id: ci.h 1.12 2003/12/31 13:49:49 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CI_H
|
#ifndef __CI_H
|
||||||
@ -111,6 +111,7 @@ public:
|
|||||||
cCiMenu *GetMenu(void);
|
cCiMenu *GetMenu(void);
|
||||||
cCiEnquiry *GetEnquiry(void);
|
cCiEnquiry *GetEnquiry(void);
|
||||||
const unsigned short *GetCaSystemIds(int Slot);
|
const unsigned short *GetCaSystemIds(int Slot);
|
||||||
|
bool ProvidesCa(const unsigned short *CaSystemIds); //XXX Slot???
|
||||||
bool SetCaPmt(cCiCaPmt &CaPmt, int Slot);
|
bool SetCaPmt(cCiCaPmt &CaPmt, int Slot);
|
||||||
bool Reset(int Slot);
|
bool Reset(int Slot);
|
||||||
};
|
};
|
||||||
|
4
config.h
4
config.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: config.h 1.177 2003/10/18 11:14:33 kls Exp $
|
* $Id: config.h 1.178 2003/12/27 13:57:56 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CONFIG_H
|
#ifndef __CONFIG_H
|
||||||
@ -87,7 +87,7 @@ public:
|
|||||||
cConfig(void) { fileName = NULL; }
|
cConfig(void) { fileName = NULL; }
|
||||||
virtual ~cConfig() { free(fileName); }
|
virtual ~cConfig() { free(fileName); }
|
||||||
const char *FileName(void) { return fileName; }
|
const char *FileName(void) { return fileName; }
|
||||||
bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false)
|
virtual bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
if (FileName) {
|
if (FileName) {
|
||||||
|
42
device.c
42
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.50 2003/12/22 10:53:45 kls Exp $
|
* $Id: device.c 1.51 2004/01/04 11:30:05 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
@ -47,6 +47,7 @@ cDevice::cDevice(void)
|
|||||||
sectionHandler = NULL;
|
sectionHandler = NULL;
|
||||||
eitFilter = NULL;
|
eitFilter = NULL;
|
||||||
patFilter = NULL;
|
patFilter = NULL;
|
||||||
|
sdtFilter = NULL;
|
||||||
|
|
||||||
ciHandler = NULL;
|
ciHandler = NULL;
|
||||||
player = NULL;
|
player = NULL;
|
||||||
@ -68,8 +69,9 @@ cDevice::~cDevice()
|
|||||||
for (int i = 0; i < MAXRECEIVERS; i++)
|
for (int i = 0; i < MAXRECEIVERS; i++)
|
||||||
Detach(receiver[i]);
|
Detach(receiver[i]);
|
||||||
delete ciHandler;
|
delete ciHandler;
|
||||||
delete eitFilter;
|
delete sdtFilter;
|
||||||
delete patFilter;
|
delete patFilter;
|
||||||
|
delete eitFilter;
|
||||||
delete sectionHandler;
|
delete sectionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +159,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDe
|
|||||||
if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
|
if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
|
||||||
if (device[i]->Receiving() && !ndr)
|
if (device[i]->Receiving() && !ndr)
|
||||||
pri = 0; // receiving and allows additional receivers
|
pri = 0; // receiving and allows additional receivers
|
||||||
else if (d && !device[i]->Receiving() && device[i]->ProvidesCa(Channel->Ca()) < d->ProvidesCa(Channel->Ca()))
|
else if (d && !device[i]->Receiving() && device[i]->ProvidesCa(Channel) < d->ProvidesCa(Channel))
|
||||||
pri = 1; // free and fewer Ca's
|
pri = 1; // free and fewer Ca's
|
||||||
else if (!device[i]->Receiving() && !device[i]->IsPrimaryDevice())
|
else if (!device[i]->Receiving() && !device[i]->IsPrimaryDevice())
|
||||||
pri = 2; // free and not the primary device
|
pri = 2; // free and not the primary device
|
||||||
@ -165,7 +167,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDe
|
|||||||
pri = 3; // free
|
pri = 3; // free
|
||||||
else if (d && device[i]->Priority() < d->Priority())
|
else if (d && device[i]->Priority() < d->Priority())
|
||||||
pri = 4; // receiving but priority is lower
|
pri = 4; // receiving but priority is lower
|
||||||
else if (d && device[i]->Priority() == d->Priority() && device[i]->ProvidesCa(Channel->Ca()) < d->ProvidesCa(Channel->Ca()))
|
else if (d && device[i]->Priority() == d->Priority() && device[i]->ProvidesCa(Channel) < d->ProvidesCa(Channel))
|
||||||
pri = 5; // receiving with same priority but fewer Ca's
|
pri = 5; // receiving with same priority but fewer Ca's
|
||||||
else
|
else
|
||||||
pri = 6; // all others
|
pri = 6; // all others
|
||||||
@ -325,6 +327,7 @@ void cDevice::StartSectionHandler(void)
|
|||||||
sectionHandler = new cSectionHandler(this);
|
sectionHandler = new cSectionHandler(this);
|
||||||
AttachFilter(eitFilter = new cEitFilter);
|
AttachFilter(eitFilter = new cEitFilter);
|
||||||
AttachFilter(patFilter = new cPatFilter);
|
AttachFilter(patFilter = new cPatFilter);
|
||||||
|
AttachFilter(sdtFilter = new cSdtFilter(patFilter));
|
||||||
sectionHandler->SetStatus(true);
|
sectionHandler->SetStatus(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -349,6 +352,11 @@ bool cDevice::ProvidesSource(int Source) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cDevice::ProvidesTransponder(const cChannel *Channel) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -431,6 +439,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
|
|||||||
Result = scrNotAvailable;
|
Result = scrNotAvailable;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
Channels.Lock(false);
|
||||||
cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
|
cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
|
||||||
// Stop section handling:
|
// Stop section handling:
|
||||||
if (sectionHandler) {
|
if (sectionHandler) {
|
||||||
@ -440,12 +449,13 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
|
|||||||
if (SetChannelDevice(Channel, LiveView)) {
|
if (SetChannelDevice(Channel, LiveView)) {
|
||||||
// Start section handling:
|
// Start section handling:
|
||||||
if (sectionHandler) {
|
if (sectionHandler) {
|
||||||
sectionHandler->SetSource(Channel->Source(), Channel->Frequency());
|
sectionHandler->SetSource(Channel->Source(), Channel->Transponder());
|
||||||
sectionHandler->SetStatus(true);
|
sectionHandler->SetStatus(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Result = scrFailed;
|
Result = scrFailed;
|
||||||
|
Channels.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Result == scrOk) {
|
if (Result == scrOk) {
|
||||||
@ -462,6 +472,11 @@ bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cDevice::HasLock(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool cDevice::HasProgramme(void)
|
bool cDevice::HasProgramme(void)
|
||||||
{
|
{
|
||||||
return Replaying() || pidHandles[ptAudio].pid || pidHandles[ptVideo].pid;
|
return Replaying() || pidHandles[ptAudio].pid || pidHandles[ptVideo].pid;
|
||||||
@ -651,6 +666,7 @@ int cDevice::Priority(void) const
|
|||||||
int cDevice::CanShift(int Ca, int Priority, int UsedCards) const
|
int cDevice::CanShift(int Ca, int Priority, int UsedCards) const
|
||||||
{
|
{
|
||||||
return -1;//XXX+ too complex with multiple recordings per device
|
return -1;//XXX+ too complex with multiple recordings per device
|
||||||
|
/*XXX
|
||||||
// Test whether a receiver on this device can be shifted to another one
|
// Test whether a receiver on this device can be shifted to another one
|
||||||
// in order to perform a new receiving with the given Ca and Priority on this device:
|
// in order to perform a new receiving with the given Ca and Priority on this device:
|
||||||
int ShiftLevel = -1; // default means this device can't be shifted
|
int ShiftLevel = -1; // default means this device can't be shifted
|
||||||
@ -681,25 +697,17 @@ int cDevice::CanShift(int Ca, int Priority, int UsedCards) const
|
|||||||
else if (Priority > this->Priority())
|
else if (Priority > this->Priority())
|
||||||
ShiftLevel = 0; // no shifting necessary, this device can do the job
|
ShiftLevel = 0; // no shifting necessary, this device can do the job
|
||||||
return ShiftLevel;
|
return ShiftLevel;
|
||||||
|
XXX*/
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDevice::ProvidesCa(int Ca) const
|
int cDevice::ProvidesCa(const cChannel *Channel) const
|
||||||
{
|
{
|
||||||
|
int Ca = Channel->Ca();
|
||||||
if (Ca == CardIndex() + 1)
|
if (Ca == CardIndex() + 1)
|
||||||
return 1; // exactly _this_ card was requested
|
return 1; // exactly _this_ card was requested
|
||||||
if (Ca && Ca <= MAXDEVICES)
|
if (Ca && Ca <= MAXDEVICES)
|
||||||
return 0; // a specific card was requested, but not _this_ one
|
return 0; // a specific card was requested, but not _this_ one
|
||||||
int result = Ca ? 0 : 1; // by default every card can provide FTA
|
return !Ca; // by default every card can provide FTA
|
||||||
int others = Ca ? 1 : 0;
|
|
||||||
for (int i = 0; i < MAXCACAPS; i++) {
|
|
||||||
if (caCaps[i]) {
|
|
||||||
if (caCaps[i] == Ca)
|
|
||||||
result = 1;
|
|
||||||
else
|
|
||||||
others++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result ? result + others : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDevice::Receiving(bool CheckAny) const
|
bool cDevice::Receiving(bool CheckAny) const
|
||||||
|
13
device.h
13
device.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: device.h 1.36 2003/12/22 10:52:39 kls Exp $
|
* $Id: device.h 1.37 2004/01/04 11:52:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DEVICE_H
|
#ifndef __DEVICE_H
|
||||||
@ -14,6 +14,7 @@
|
|||||||
#include "eit.h"
|
#include "eit.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "pat.h"
|
#include "pat.h"
|
||||||
|
#include "sdt.h"
|
||||||
#include "sections.h"
|
#include "sections.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
@ -131,7 +132,8 @@ public:
|
|||||||
///< Returns the card index of this device (0 ... MAXDEVICES - 1).
|
///< Returns the card index of this device (0 ... MAXDEVICES - 1).
|
||||||
int DeviceNumber(void) const;
|
int DeviceNumber(void) const;
|
||||||
///< Returns the number of this device (0 ... MAXDEVICES - 1).
|
///< Returns the number of this device (0 ... MAXDEVICES - 1).
|
||||||
int ProvidesCa(int Ca) const;
|
virtual int ProvidesCa(const cChannel *Channel) const;//XXX PLUGINS.html!!!
|
||||||
|
//XXX describe changed functionality!!!
|
||||||
///< Checks whether this device provides the given value in its
|
///< Checks whether this device provides the given value in its
|
||||||
///< caCaps. Returns 0 if the value is not provided, 1 if only this
|
///< caCaps. Returns 0 if the value is not provided, 1 if only this
|
||||||
///< value is provided, and > 1 if this and other values are provided.
|
///< value is provided, and > 1 if this and other values are provided.
|
||||||
@ -161,6 +163,8 @@ protected:
|
|||||||
public:
|
public:
|
||||||
virtual bool ProvidesSource(int Source) const;
|
virtual bool ProvidesSource(int Source) const;
|
||||||
///< Returns true if this device can provide the given source.
|
///< Returns true if this device can provide the given source.
|
||||||
|
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
||||||
|
///< XXX -> PLUGINS.html!
|
||||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
||||||
///< Returns true if this device can provide the given channel.
|
///< Returns true if this device can provide the given channel.
|
||||||
///< In case the device has cReceivers attached to it or it is the primary
|
///< In case the device has cReceivers attached to it or it is the primary
|
||||||
@ -192,6 +196,10 @@ protected:
|
|||||||
public:
|
public:
|
||||||
static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; }
|
static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; }
|
||||||
///< Returns the number of the current channel on the primary device.
|
///< Returns the number of the current channel on the primary device.
|
||||||
|
virtual bool HasLock(void);//XXX PLUGINS.html
|
||||||
|
///< Returns true if the device has a lock on the requested transponder.
|
||||||
|
///< Default is true, a specific device implementation may return false
|
||||||
|
///< to indicate that it is not ready yet.
|
||||||
virtual bool HasProgramme(void);
|
virtual bool HasProgramme(void);
|
||||||
///< Returns true if the device is currently showing any programme to
|
///< Returns true if the device is currently showing any programme to
|
||||||
///< the user, either through replaying or live.
|
///< the user, either through replaying or live.
|
||||||
@ -232,6 +240,7 @@ private:
|
|||||||
cSectionHandler *sectionHandler;
|
cSectionHandler *sectionHandler;
|
||||||
cEitFilter *eitFilter;
|
cEitFilter *eitFilter;
|
||||||
cPatFilter *patFilter;
|
cPatFilter *patFilter;
|
||||||
|
cSdtFilter *sdtFilter;
|
||||||
protected:
|
protected:
|
||||||
void StartSectionHandler(void);
|
void StartSectionHandler(void);
|
||||||
///< A derived device that provides section data must call
|
///< A derived device that provides section data must call
|
||||||
|
77
dvbdevice.c
77
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.75 2003/12/24 09:57:29 kls Exp $
|
* $Id: dvbdevice.c 1.76 2004/01/04 12:28:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dvbdevice.h"
|
#include "dvbdevice.h"
|
||||||
@ -86,7 +86,7 @@ public:
|
|||||||
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 UseCa);
|
||||||
bool Locked(void) { return tunerStatus == tsLocked; }
|
bool Locked(void) { return tunerStatus >= tsLocked; }
|
||||||
};
|
};
|
||||||
|
|
||||||
cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler)
|
cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler)
|
||||||
@ -114,19 +114,18 @@ cDvbTuner::~cDvbTuner()
|
|||||||
|
|
||||||
bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
|
bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
|
||||||
{
|
{
|
||||||
return tunerStatus != tsIdle && channel.Source() == Channel->Source() && channel.Frequency() == Channel->Frequency();
|
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, bool UseCa)
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&mutex);
|
cMutexLock MutexLock(&mutex);
|
||||||
bool CaChange = !(Channel->GetChannelID() == channel.GetChannelID());
|
|
||||||
if (Tune)
|
if (Tune)
|
||||||
tunerStatus = tsSet;
|
tunerStatus = tsSet;
|
||||||
else if (tunerStatus == tsCam && CaChange)
|
else if (tunerStatus == tsCam)
|
||||||
tunerStatus = tsTuned;
|
tunerStatus = tsTuned;
|
||||||
useCa = UseCa;
|
useCa = UseCa;
|
||||||
if (Channel->Ca() && CaChange)
|
if (Channel->Ca() && tunerStatus != tsCam)
|
||||||
startTime = time(NULL);
|
startTime = time(NULL);
|
||||||
channel = *Channel;
|
channel = *Channel;
|
||||||
newSet.Broadcast();
|
newSet.Broadcast();
|
||||||
@ -268,29 +267,27 @@ void cDvbTuner::Action(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tunerStatus >= tsLocked) {
|
}
|
||||||
if (ciHandler) {
|
if (ciHandler) {
|
||||||
if (ciHandler->Process() && useCa) {
|
if (ciHandler->Process() && useCa) {
|
||||||
if (tunerStatus != tsCam) {//XXX TODO update in case the CA descriptors have changed
|
if (tunerStatus == tsLocked) {
|
||||||
for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) {
|
for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) {
|
||||||
cCiCaPmt CaPmt(channel.Source(), channel.Frequency(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
|
cCiCaPmt CaPmt(channel.Source(), channel.Frequency(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
|
||||||
if (CaPmt.Valid()) {
|
if (CaPmt.Valid()) {
|
||||||
CaPmt.AddPid(channel.Vpid(), 2);
|
CaPmt.AddPid(channel.Vpid(), 2);
|
||||||
CaPmt.AddPid(channel.Apid1(), 4);
|
CaPmt.AddPid(channel.Apid1(), 4);
|
||||||
CaPmt.AddPid(channel.Apid2(), 4);
|
CaPmt.AddPid(channel.Apid2(), 4);
|
||||||
CaPmt.AddPid(channel.Dpid1(), 0);
|
CaPmt.AddPid(channel.Dpid1(), 0);
|
||||||
if (ciHandler->SetCaPmt(CaPmt, Slot)) {
|
if (ciHandler->SetCaPmt(CaPmt, Slot)) {
|
||||||
tunerStatus = tsCam;
|
tunerStatus = tsCam;
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
tunerStatus = tsLocked;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (tunerStatus > tsLocked)
|
||||||
|
tunerStatus = tsLocked;
|
||||||
}
|
}
|
||||||
// in the beginning we loop more often to let the CAM connection start up fast
|
// in the beginning we loop more often to let the CAM connection start up fast
|
||||||
newSet.TimedWait(mutex, (ciHandler && (time(NULL) - startTime < 20)) ? 100 : 1000);
|
newSet.TimedWait(mutex, (ciHandler && (time(NULL) - startTime < 20)) ? 100 : 1000);
|
||||||
@ -436,6 +433,17 @@ bool cDvbDevice::HasDecoder(void) const
|
|||||||
return fd_video >= 0 && fd_audio >= 0;
|
return fd_video >= 0 && fd_audio >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cDvbDevice::ProvidesCa(const cChannel *Channel) const
|
||||||
|
{
|
||||||
|
if (Channel->Ca() >= 0x0100 && ciHandler) {
|
||||||
|
unsigned short ids[MAXCAIDS + 1];
|
||||||
|
for (int i = 0; i <= MAXCAIDS; i++) // '<=' copies the terminating 0!
|
||||||
|
ids[i] = Channel->Ca(i);
|
||||||
|
return ciHandler->ProvidesCa(ids);
|
||||||
|
}
|
||||||
|
return cDevice::ProvidesCa(Channel);
|
||||||
|
}
|
||||||
|
|
||||||
cOsdBase *cDvbDevice::NewOsd(int x, int y)
|
cOsdBase *cDvbDevice::NewOsd(int x, int y)
|
||||||
{
|
{
|
||||||
return new cDvbOsd(x, y);
|
return new cDvbOsd(x, y);
|
||||||
@ -661,13 +669,18 @@ bool cDvbDevice::ProvidesSource(int Source) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
|
||||||
|
{
|
||||||
|
return ProvidesSource(Channel->Source()) && ((Channel->Source() & cSource::st_Mask) != cSource::stSat || Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()));
|
||||||
|
}
|
||||||
|
|
||||||
bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
bool hasPriority = Priority < 0 || Priority > this->Priority();
|
bool hasPriority = Priority < 0 || Priority > this->Priority();
|
||||||
bool needsDetachReceivers = false;
|
bool needsDetachReceivers = false;
|
||||||
|
|
||||||
if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel->Ca())) {
|
if ((Channel->Vpid() || Channel->Apid1()) && ProvidesSource(Channel->Source()) && ProvidesCa(Channel)) {
|
||||||
result = hasPriority;
|
result = hasPriority;
|
||||||
if (Priority >= 0 && Receiving()) {
|
if (Priority >= 0 && Receiving()) {
|
||||||
if (dvbTuner->IsTunedTo(Channel)) {
|
if (dvbTuner->IsTunedTo(Channel)) {
|
||||||
@ -736,15 +749,14 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
if (TurnOffLivePIDs)
|
if (TurnOffLivePIDs)
|
||||||
TurnOffLiveMode();
|
TurnOffLiveMode();
|
||||||
|
|
||||||
dvbTuner->Set(Channel, DoTune, !EITScanner.UsesDevice(this)); //XXX 1.3: this is an ugly hack - find a cleaner solution
|
dvbTuner->Set(Channel, DoTune, !EITScanner.UsesDevice(this)); //XXX 1.3: this is an ugly hack - find a cleaner solution//XXX
|
||||||
|
|
||||||
// PID settings:
|
// PID settings:
|
||||||
|
|
||||||
if (TurnOnLivePIDs) {
|
if (TurnOnLivePIDs) {
|
||||||
aPid1 = Channel->Apid1();
|
aPid1 = Channel->Apid1();
|
||||||
aPid2 = Channel->Apid2();
|
aPid2 = Channel->Apid2();
|
||||||
int pPid = Channel->Ppid() ? Channel->Ppid() : Channel->Vpid();
|
if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(Channel->Apid1(), ptAudio) && AddPid(Channel->Vpid(), ptVideo))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
|
||||||
if (!(AddPid(pPid, ptPcr) && AddPid(Channel->Apid1(), ptAudio) && AddPid(Channel->Vpid(), ptVideo))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
|
|
||||||
esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
|
esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -758,6 +770,11 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cDvbDevice::HasLock(void)
|
||||||
|
{
|
||||||
|
return dvbTuner->Locked();
|
||||||
|
}
|
||||||
|
|
||||||
void cDvbDevice::SetVolumeDevice(int Volume)
|
void cDvbDevice::SetVolumeDevice(int Volume)
|
||||||
{
|
{
|
||||||
if (HasDecoder()) {
|
if (HasDecoder()) {
|
||||||
|
@ -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.h 1.25 2003/12/21 14:04:00 kls Exp $
|
* $Id: dvbdevice.h 1.26 2004/01/03 10:21:50 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DVBDEVICE_H
|
#ifndef __DVBDEVICE_H
|
||||||
@ -44,6 +44,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
cDvbDevice(int n);
|
cDvbDevice(int n);
|
||||||
virtual ~cDvbDevice();
|
virtual ~cDvbDevice();
|
||||||
|
virtual int ProvidesCa(const cChannel *Channel) const;
|
||||||
virtual bool HasDecoder(void) const;
|
virtual bool HasDecoder(void) const;
|
||||||
|
|
||||||
// OSD facilities
|
// OSD facilities
|
||||||
@ -61,9 +62,12 @@ private:
|
|||||||
void TurnOffLiveMode(void);
|
void TurnOffLiveMode(void);
|
||||||
public:
|
public:
|
||||||
virtual bool ProvidesSource(int Source) const;
|
virtual bool ProvidesSource(int Source) const;
|
||||||
|
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
||||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
||||||
protected:
|
protected:
|
||||||
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
||||||
|
public:
|
||||||
|
virtual bool HasLock(void);
|
||||||
|
|
||||||
// PID handle facilities
|
// PID handle facilities
|
||||||
|
|
||||||
|
10
eit.c
10
eit.c
@ -8,7 +8,7 @@
|
|||||||
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
||||||
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
|
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
|
||||||
*
|
*
|
||||||
* $Id: eit.c 1.83 2003/12/25 12:48:47 kls Exp $
|
* $Id: eit.c 1.84 2004/01/02 22:27:29 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "eit.h"
|
#include "eit.h"
|
||||||
@ -29,12 +29,10 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
|
|||||||
if (!CheckCRCAndParse())
|
if (!CheckCRCAndParse())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//XXX TODO use complete channel ID
|
tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId());
|
||||||
cChannel *channel = Channels.GetByServiceID(Source, getServiceId());
|
cChannel *channel = Channels.GetByChannelID(channelID, true);
|
||||||
if (!channel)
|
if (!channel)
|
||||||
return; // only collect data for known channels
|
return; // only collect data for known channels
|
||||||
tChannelID channelID = channel->GetChannelID();
|
|
||||||
channelID.ClrRid();
|
|
||||||
|
|
||||||
cEvent *rEvent = NULL;
|
cEvent *rEvent = NULL;
|
||||||
|
|
||||||
@ -82,7 +80,7 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
|
|||||||
// Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like
|
// Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like
|
||||||
// the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
|
// the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
|
||||||
// each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
|
// each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
|
||||||
// to the Sat.1/Pro7 transponder, events will keep toggling because ot the bogus version numbers.
|
// to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers.
|
||||||
if (Tid == pEvent->TableID() && pEvent->Version() == getVersionNumber())
|
if (Tid == pEvent->TableID() && pEvent->Version() == getVersionNumber())
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
144
eitscan.c
144
eitscan.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: eitscan.c 1.14 2003/09/06 13:06:13 kls Exp $
|
* $Id: eitscan.c 1.15 2004/01/04 12:28:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "eitscan.h"
|
#include "eitscan.h"
|
||||||
@ -12,6 +12,68 @@
|
|||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
#include "dvbdevice.h"
|
#include "dvbdevice.h"
|
||||||
|
|
||||||
|
// --- cScanData -------------------------------------------------------------
|
||||||
|
|
||||||
|
class cScanData : public cListObject {
|
||||||
|
private:
|
||||||
|
int source;
|
||||||
|
int transponder;
|
||||||
|
public:
|
||||||
|
cScanData(int Source, int Transponder);
|
||||||
|
virtual bool operator< (const cListObject &ListObject);
|
||||||
|
int Source(void) { return source; }
|
||||||
|
int Transponder(void) { return transponder; }
|
||||||
|
cChannel *GetChannel(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
cScanData::cScanData(int Source, int Transponder)
|
||||||
|
{
|
||||||
|
source = Source;
|
||||||
|
transponder = Transponder;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScanData::operator< (const cListObject &ListObject)
|
||||||
|
{
|
||||||
|
cScanData *sd = (cScanData *)&ListObject;
|
||||||
|
return source < sd->source || source == sd->source && transponder < sd->transponder;
|
||||||
|
}
|
||||||
|
|
||||||
|
//XXX this might be done differently later...
|
||||||
|
cChannel *cScanData::GetChannel(void)
|
||||||
|
{
|
||||||
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
||||||
|
if (!Channel->GroupSep() && Channel->Source() == source && ISTRANSPONDER(Channel->Transponder(), transponder))
|
||||||
|
return Channel;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cScanList -------------------------------------------------------------
|
||||||
|
|
||||||
|
class cScanList : public cList<cScanData> {
|
||||||
|
public:
|
||||||
|
cScanList(void);
|
||||||
|
void AddTransponder(const cChannel *Channel);
|
||||||
|
};
|
||||||
|
|
||||||
|
cScanList::cScanList(void)
|
||||||
|
{
|
||||||
|
for (cChannel *ch = Channels.First(); ch; ch = Channels.Next(ch))
|
||||||
|
AddTransponder(ch);
|
||||||
|
Sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScanList::AddTransponder(const cChannel *Channel)
|
||||||
|
{
|
||||||
|
for (cScanData *sd = First(); sd; sd = Next(sd)) {
|
||||||
|
if (sd->Source() == Channel->Source() && sd->Transponder() == Channel->Transponder())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Add(new cScanData(Channel->Source(), Channel->Transponder()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cEITScanner -----------------------------------------------------------
|
||||||
|
|
||||||
cEITScanner EITScanner;
|
cEITScanner EITScanner;
|
||||||
|
|
||||||
cEITScanner::cEITScanner(void)
|
cEITScanner::cEITScanner(void)
|
||||||
@ -20,24 +82,12 @@ cEITScanner::cEITScanner(void)
|
|||||||
currentDevice = NULL;
|
currentDevice = NULL;
|
||||||
currentChannel = 0;
|
currentChannel = 0;
|
||||||
memset(lastChannel, 0, sizeof(lastChannel));
|
memset(lastChannel, 0, sizeof(lastChannel));
|
||||||
numTransponders = 0;
|
scanList = NULL;
|
||||||
transponders = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cEITScanner::~cEITScanner()
|
cEITScanner::~cEITScanner()
|
||||||
{
|
{
|
||||||
free(transponders);
|
delete scanList;
|
||||||
}
|
|
||||||
|
|
||||||
bool cEITScanner::TransponderScanned(cChannel *Channel)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < numTransponders; i++) {
|
|
||||||
if (transponders[i] == Channel->Frequency())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
transponders = (int *)realloc(transponders, ++numTransponders * sizeof(int));
|
|
||||||
transponders[numTransponders - 1] = Channel->Frequency();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cEITScanner::Activity(void)
|
void cEITScanner::Activity(void)
|
||||||
@ -54,37 +104,51 @@ void cEITScanner::Process(void)
|
|||||||
if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
|
if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
|
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
|
||||||
for (int i = 0; i < cDevice::NumDevices(); i++) {
|
if (Channels.Lock(false, 10)) {
|
||||||
cDevice *Device = cDevice::GetDevice(i);
|
if (!scanList)
|
||||||
if (Device && Device->CardIndex() < MAXDVBDEVICES) {
|
scanList = new cScanList();
|
||||||
if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
|
for (bool AnyDeviceSwitched = false; !AnyDeviceSwitched; ) {
|
||||||
if (!(Device->Receiving(true) || Device->Replaying())) {
|
cScanData *ScanData = NULL;
|
||||||
for (;;) {
|
for (int i = 0; i < cDevice::NumDevices(); i++) {
|
||||||
cChannel *Channel = Channels.GetByNumber(lastChannel[Device->DeviceNumber()] + 1, 1);
|
cDevice *Device = cDevice::GetDevice(i);
|
||||||
if (Channel) {
|
if (Device) {
|
||||||
lastChannel[Device->DeviceNumber()] = Channel->Number();
|
if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
|
||||||
if (Channel->Sid() && Device->ProvidesChannel(Channel) && !TransponderScanned(Channel)) {
|
if (!(Device->Receiving(true) || Device->Replaying())) {
|
||||||
if (Device == cDevice::PrimaryDevice() && !currentChannel) {
|
if (!ScanData)
|
||||||
currentChannel = Device->CurrentChannel();
|
ScanData = scanList->First();
|
||||||
|
if (ScanData) {
|
||||||
|
cChannel *Channel = ScanData->GetChannel();
|
||||||
|
//XXX if (Device->ProvidesTransponder(Channel)) {
|
||||||
|
if ((!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= 0x0100) && Device->ProvidesTransponder(Channel)) { //XXX temporary for the 'sky' plugin
|
||||||
|
if (Device == cDevice::PrimaryDevice() && !currentChannel)
|
||||||
|
currentChannel = Device->CurrentChannel();
|
||||||
|
currentDevice = Device;//XXX see also dvbdevice.c!!!
|
||||||
|
Device->SwitchChannel(Channel, false);
|
||||||
|
currentDevice = NULL;
|
||||||
|
scanList->Del(ScanData);
|
||||||
|
ScanData = NULL;
|
||||||
|
AnyDeviceSwitched = true;
|
||||||
}
|
}
|
||||||
currentDevice = Device;
|
|
||||||
Device->SwitchChannel(Channel, false);
|
|
||||||
currentDevice = NULL;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else {
|
break;
|
||||||
if (lastChannel[Device->DeviceNumber()])
|
|
||||||
numTransponders = 0;
|
|
||||||
lastChannel[Device->DeviceNumber()] = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (ScanData && !AnyDeviceSwitched) {
|
||||||
|
scanList->Del(ScanData);
|
||||||
|
ScanData = NULL;
|
||||||
|
}
|
||||||
|
if (!scanList->Count()) {
|
||||||
|
delete scanList;
|
||||||
|
scanList = NULL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Channels.Unlock();
|
||||||
lastScan = time(NULL);
|
lastScan = time(NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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: eitscan.h 1.4 2003/09/06 13:05:51 kls Exp $
|
* $Id: eitscan.h 1.5 2004/01/03 13:08:39 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __EITSCAN_H
|
#ifndef __EITSCAN_H
|
||||||
@ -13,6 +13,8 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
class cScanList;
|
||||||
|
|
||||||
class cEITScanner {
|
class cEITScanner {
|
||||||
private:
|
private:
|
||||||
enum { ActivityTimeout = 60,
|
enum { ActivityTimeout = 60,
|
||||||
@ -22,8 +24,7 @@ private:
|
|||||||
cDevice *currentDevice;
|
cDevice *currentDevice;
|
||||||
int currentChannel;
|
int currentChannel;
|
||||||
int lastChannel[MAXDEVICES];
|
int lastChannel[MAXDEVICES];
|
||||||
int numTransponders, *transponders;
|
cScanList *scanList;
|
||||||
bool TransponderScanned(cChannel *Channel);
|
|
||||||
public:
|
public:
|
||||||
cEITScanner(void);
|
cEITScanner(void);
|
||||||
~cEITScanner();
|
~cEITScanner();
|
||||||
|
4
epg.h
4
epg.h
@ -7,7 +7,7 @@
|
|||||||
* Original version (as used in VDR before 1.3.0) written by
|
* Original version (as used in VDR before 1.3.0) written by
|
||||||
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
||||||
*
|
*
|
||||||
* $Id: epg.h 1.2 2003/12/24 13:20:35 kls Exp $
|
* $Id: epg.h 1.3 2004/01/03 17:00:25 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __EPG_H
|
#ifndef __EPG_H
|
||||||
@ -110,7 +110,7 @@ class cSchedules : public cList<cSchedule> {
|
|||||||
friend class cSchedule;
|
friend class cSchedule;
|
||||||
friend class cSchedulesLock;
|
friend class cSchedulesLock;
|
||||||
private:
|
private:
|
||||||
cRWlock rwlock;
|
cRwLock rwlock;
|
||||||
static cSchedules schedules;
|
static cSchedules schedules;
|
||||||
static const char *epgDataFileName;
|
static const char *epgDataFileName;
|
||||||
static time_t lastCleanup;
|
static time_t lastCleanup;
|
||||||
|
65
menu.c
65
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 1.275 2003/12/22 10:05:14 kls Exp $
|
* $Id: menu.c 1.276 2004/01/04 11:12:43 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
@ -581,7 +581,7 @@ void cMenuEditChannel::Setup(void)
|
|||||||
Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0x1FFF));
|
Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0x1FFF));
|
||||||
Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0x1FFF));
|
Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0x1FFF));
|
||||||
Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF));
|
Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF));
|
||||||
Add(new cMenuEditCaItem( tr("CA"), &data.ca, true));
|
Add(new cMenuEditCaItem( tr("CA"), &data.caids[0], true));//XXX
|
||||||
Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 0));
|
Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 0));
|
||||||
/* XXX not yet used
|
/* XXX not yet used
|
||||||
Add(new cMenuEditIntItem( tr("Nid"), &data.nid, 0));
|
Add(new cMenuEditIntItem( tr("Nid"), &data.nid, 0));
|
||||||
@ -615,7 +615,6 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key)
|
|||||||
if (channel) {
|
if (channel) {
|
||||||
*channel = data;
|
*channel = data;
|
||||||
isyslog("edited channel %d %s", channel->Number(), data.ToText());
|
isyslog("edited channel %d %s", channel->Number(), data.ToText());
|
||||||
Timers.Save();
|
|
||||||
state = osBack;
|
state = osBack;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -626,7 +625,7 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key)
|
|||||||
isyslog("added channel %d %s", channel->Number(), data.ToText());
|
isyslog("added channel %d %s", channel->Number(), data.ToText());
|
||||||
state = osUser1;
|
state = osUser1;
|
||||||
}
|
}
|
||||||
Channels.Save();
|
Channels.SetModified();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Interface->Error(tr("Channel settings are not unique!"));
|
Interface->Error(tr("Channel settings are not unique!"));
|
||||||
@ -682,6 +681,7 @@ protected:
|
|||||||
virtual void Move(int From, int To);
|
virtual void Move(int From, int To);
|
||||||
public:
|
public:
|
||||||
cMenuChannels(void);
|
cMenuChannels(void);
|
||||||
|
~cMenuChannels();
|
||||||
virtual eOSState ProcessKey(eKeys Key);
|
virtual eOSState ProcessKey(eKeys Key);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -693,6 +693,12 @@ cMenuChannels::cMenuChannels(void)
|
|||||||
Add(new cMenuChannelItem(channel), channel->Number() == cDevice::CurrentChannel());
|
Add(new cMenuChannelItem(channel), channel->Number() == cDevice::CurrentChannel());
|
||||||
}
|
}
|
||||||
SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark"));
|
SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark"));
|
||||||
|
Channels.IncBeingEdited();
|
||||||
|
}
|
||||||
|
|
||||||
|
cMenuChannels::~cMenuChannels()
|
||||||
|
{
|
||||||
|
Channels.DecBeingEdited();
|
||||||
}
|
}
|
||||||
|
|
||||||
cChannel *cMenuChannels::GetChannel(int Index)
|
cChannel *cMenuChannels::GetChannel(int Index)
|
||||||
@ -704,11 +710,10 @@ cChannel *cMenuChannels::GetChannel(int Index)
|
|||||||
void cMenuChannels::Propagate(void)
|
void cMenuChannels::Propagate(void)
|
||||||
{
|
{
|
||||||
Channels.ReNumber();
|
Channels.ReNumber();
|
||||||
Channels.Save();
|
|
||||||
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
|
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
|
||||||
ci->Set();
|
ci->Set();
|
||||||
Timers.Save(); // channel numbering has changed!
|
|
||||||
Display();
|
Display();
|
||||||
|
Channels.SetModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
eOSState cMenuChannels::Switch(void)
|
eOSState cMenuChannels::Switch(void)
|
||||||
@ -1380,22 +1385,24 @@ void cMenuSchedule::PrepareSchedule(cChannel *Channel)
|
|||||||
free(buffer);
|
free(buffer);
|
||||||
if (schedules) {
|
if (schedules) {
|
||||||
const cSchedule *Schedule = schedules->GetSchedule(Channel->GetChannelID());
|
const cSchedule *Schedule = schedules->GetSchedule(Channel->GetChannelID());
|
||||||
int num = Schedule->NumEvents();
|
if (Schedule) {
|
||||||
const cEvent **pArray = MALLOC(const cEvent *, num);
|
int num = Schedule->NumEvents();
|
||||||
if (pArray) {
|
const cEvent **pArray = MALLOC(const cEvent *, num);
|
||||||
time_t now = time(NULL);
|
if (pArray) {
|
||||||
int numreal = 0;
|
time_t now = time(NULL);
|
||||||
for (int a = 0; a < num; a++) {
|
int numreal = 0;
|
||||||
const cEvent *Event = Schedule->GetEventNumber(a);
|
for (int a = 0; a < num; a++) {
|
||||||
if (Event->StartTime() + Event->Duration() > now)
|
const cEvent *Event = Schedule->GetEventNumber(a);
|
||||||
pArray[numreal++] = Event;
|
if (Event->StartTime() + Event->Duration() > now)
|
||||||
}
|
pArray[numreal++] = Event;
|
||||||
|
}
|
||||||
qsort(pArray, numreal, sizeof(cEvent *), CompareEventTime);
|
|
||||||
|
qsort(pArray, numreal, sizeof(cEvent *), CompareEventTime);
|
||||||
for (int a = 0; a < numreal; a++)
|
|
||||||
Add(new cMenuScheduleItem(pArray[a]));
|
for (int a = 0; a < numreal; a++)
|
||||||
free(pArray);
|
Add(new cMenuScheduleItem(pArray[a]));
|
||||||
|
free(pArray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3219,6 +3226,20 @@ void cRecordControls::Process(time_t t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cRecordControls::ChannelDataModified(cChannel *Channel)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
|
if (RecordControls[i]) {
|
||||||
|
if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) {
|
||||||
|
isyslog("stopping recording due to modification of channel %d", Channel->Number());
|
||||||
|
RecordControls[i]->Stop(true);
|
||||||
|
// This will restart the recording, maybe even from a different
|
||||||
|
// device in case conditional access has changed.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool cRecordControls::Active(void)
|
bool cRecordControls::Active(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
|
3
menu.h
3
menu.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: menu.h 1.58 2003/12/21 15:27:07 kls Exp $
|
* $Id: menu.h 1.59 2004/01/04 11:01:13 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MENU_H
|
#ifndef __MENU_H
|
||||||
@ -143,6 +143,7 @@ public:
|
|||||||
static const char *GetInstantId(const char *LastInstantId);
|
static const char *GetInstantId(const char *LastInstantId);
|
||||||
static cRecordControl *GetRecordControl(const char *FileName);
|
static cRecordControl *GetRecordControl(const char *FileName);
|
||||||
static void Process(time_t t);
|
static void Process(time_t t);
|
||||||
|
static void ChannelDataModified(cChannel *Channel);
|
||||||
static bool Active(void);
|
static bool Active(void);
|
||||||
static void Shutdown(void);
|
static void Shutdown(void);
|
||||||
};
|
};
|
||||||
|
350
pat.c
350
pat.c
@ -4,45 +4,39 @@
|
|||||||
* 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: pat.c 1.2 2003/12/24 10:23:33 kls Exp $
|
* $Id: pat.c 1.3 2004/01/04 12:27:06 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pat.h"
|
#include "pat.h"
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include "channels.h"
|
||||||
#include "libsi/section.h"
|
#include "libsi/section.h"
|
||||||
#include "libsi/descriptor.h"
|
#include "libsi/descriptor.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
#define PMT_SCAN_TIMEOUT 10 // seconds
|
#define PMT_SCAN_TIMEOUT 10 // seconds
|
||||||
|
|
||||||
// --- cCaDescriptor ---------------------------------------------------------
|
// --- cCaDescriptor ---------------------------------------------------------
|
||||||
|
|
||||||
class cCaDescriptor : public cListObject {
|
class cCaDescriptor : public cListObject {
|
||||||
friend class cCaDescriptors;
|
|
||||||
private:
|
private:
|
||||||
int source;
|
|
||||||
int transponder;
|
|
||||||
int serviceId;
|
|
||||||
int caSystem;
|
int caSystem;
|
||||||
int providerId;
|
|
||||||
int caPid;
|
|
||||||
bool stream;
|
bool stream;
|
||||||
int length;
|
int length;
|
||||||
uchar *data;
|
uchar *data;
|
||||||
public:
|
public:
|
||||||
cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int ProviderId, int CaPid, bool Stream, int Length, const uchar *Data);
|
cCaDescriptor(int CaSystem, int CaPid, bool Stream, int Length, const uchar *Data);
|
||||||
virtual ~cCaDescriptor();
|
virtual ~cCaDescriptor();
|
||||||
|
bool operator== (const cCaDescriptor &arg) const;
|
||||||
|
int CaSystem(void) { return caSystem; }
|
||||||
|
int Stream(void) { return stream; }
|
||||||
int Length(void) const { return length; }
|
int Length(void) const { return length; }
|
||||||
const uchar *Data(void) const { return data; }
|
const uchar *Data(void) const { return data; }
|
||||||
};
|
};
|
||||||
|
|
||||||
cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int ProviderId, int CaPid, bool Stream, int Length, const uchar *Data)
|
cCaDescriptor::cCaDescriptor(int CaSystem, int CaPid, bool Stream, int Length, const uchar *Data)
|
||||||
{
|
{
|
||||||
source = Source;
|
|
||||||
transponder = Transponder;
|
|
||||||
serviceId = ServiceId;
|
|
||||||
caSystem = CaSystem;
|
caSystem = CaSystem;
|
||||||
providerId = ProviderId;
|
|
||||||
caPid = CaPid;
|
|
||||||
stream = Stream;
|
stream = Stream;
|
||||||
length = Length + 6;
|
length = Length + 6;
|
||||||
data = MALLOC(uchar, length);
|
data = MALLOC(uchar, length);
|
||||||
@ -54,15 +48,6 @@ cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaS
|
|||||||
data[5] = CaPid & 0xFF;
|
data[5] = CaPid & 0xFF;
|
||||||
if (Length)
|
if (Length)
|
||||||
memcpy(&data[6], Data, Length);
|
memcpy(&data[6], Data, Length);
|
||||||
//#define DEBUG_CA_DESCRIPTORS 1
|
|
||||||
#ifdef DEBUG_CA_DESCRIPTORS
|
|
||||||
char buffer[1024];
|
|
||||||
char *q = buffer;
|
|
||||||
q += sprintf(q, "CAM: %04X %5d %5d %04X %6X %04X %d -", source, transponder, serviceId, caSystem, providerId, caPid, stream);
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
q += sprintf(q, " %02X", data[i]);
|
|
||||||
dsyslog(buffer);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cCaDescriptor::~cCaDescriptor()
|
cCaDescriptor::~cCaDescriptor()
|
||||||
@ -70,75 +55,121 @@ cCaDescriptor::~cCaDescriptor()
|
|||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cCaDescriptors --------------------------------------------------------
|
bool cCaDescriptor::operator== (const cCaDescriptor &arg) const
|
||||||
|
|
||||||
class cCaDescriptors : public cList<cCaDescriptor> {
|
|
||||||
private:
|
|
||||||
cMutex mutex;
|
|
||||||
public:
|
|
||||||
void NewCaDescriptor(int Source, int Transponder, int ServiceId, SI::CaDescriptor *d, bool Stream);
|
|
||||||
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag);
|
|
||||||
};
|
|
||||||
|
|
||||||
void cCaDescriptors::NewCaDescriptor(int Source, int Transponder, int ServiceId, SI::CaDescriptor *d, bool Stream)
|
|
||||||
{
|
{
|
||||||
// The code for determining the ProviderID was taken from 'libdtv'
|
return length == arg.length && memcmp(data, arg.data, length) == 0;
|
||||||
// written by Rolf Hakenes <hakenes@hippomi.de>.
|
|
||||||
|
|
||||||
const uchar *Data = d->privateData.getData();
|
|
||||||
int Length = d->privateData.getLength();
|
|
||||||
int ProviderID = 0;
|
|
||||||
|
|
||||||
switch (d->getCaType() >> 8) {
|
|
||||||
case 0x01: // SECA
|
|
||||||
ProviderID = (Data[0] << 8) | Data[1];
|
|
||||||
break;
|
|
||||||
case 0x05: // Viaccess ? (France Telecom)
|
|
||||||
for (int i = 0; i < Length; i++) {
|
|
||||||
if (Data[i] == 0x14 && Data[i + 1] == 0x03) {
|
|
||||||
ProviderID = (Data[i + 2] << 16) |
|
|
||||||
(Data[i + 3] << 8) |
|
|
||||||
(Data[i + 4] & 0xf0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cMutexLock MutexLock(&mutex);
|
|
||||||
for (cCaDescriptor *ca = First(); ca; ca = Next(ca)) {
|
|
||||||
if (ca->source == Source && ca->transponder == Transponder && ca->serviceId == ServiceId && ca->caSystem == d->getCaType() && ca->providerId == ProviderID && ca->caPid == d->getCaPid())
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Add(new cCaDescriptor(Source, Transponder, ServiceId, d->getCaType(), ProviderID, d->getCaPid(), Stream, Length, Data));
|
|
||||||
//XXX update???
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cCaDescriptors::GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
|
// --- cCaDescriptors --------------------------------------------------------
|
||||||
|
|
||||||
|
class cCaDescriptors : public cListObject {
|
||||||
|
private:
|
||||||
|
int source;
|
||||||
|
int transponder;
|
||||||
|
int serviceId;
|
||||||
|
int numCaIds;
|
||||||
|
int caIds[MAXCAIDS + 1];
|
||||||
|
cList<cCaDescriptor> caDescriptors;
|
||||||
|
void AddCaId(int CaId);
|
||||||
|
public:
|
||||||
|
cCaDescriptors(int Source, int Transponder, int ServiceId);
|
||||||
|
bool operator== (const cCaDescriptors &arg) const;
|
||||||
|
bool Is(int Source, int Transponder, int ServiceId);
|
||||||
|
bool Is(cCaDescriptors * CaDescriptors);
|
||||||
|
bool Empty(void) { return caDescriptors.Count() == 0; }
|
||||||
|
void AddCaDescriptor(SI::CaDescriptor *d, bool Stream);
|
||||||
|
int GetCaDescriptors(const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag);
|
||||||
|
const int *CaIds(void) { return caIds; }
|
||||||
|
};
|
||||||
|
|
||||||
|
cCaDescriptors::cCaDescriptors(int Source, int Transponder, int ServiceId)
|
||||||
|
{
|
||||||
|
source = Source;
|
||||||
|
transponder = Transponder;
|
||||||
|
serviceId = ServiceId;
|
||||||
|
numCaIds = 0;
|
||||||
|
caIds[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cCaDescriptors::operator== (const cCaDescriptors &arg) const
|
||||||
|
{
|
||||||
|
cCaDescriptor *ca1 = caDescriptors.First();
|
||||||
|
cCaDescriptor *ca2 = arg.caDescriptors.First();
|
||||||
|
while (ca1 && ca2) {
|
||||||
|
if (!(*ca1 == *ca2))
|
||||||
|
return false;
|
||||||
|
ca1 = caDescriptors.Next(ca1);
|
||||||
|
ca2 = arg.caDescriptors.Next(ca2);
|
||||||
|
}
|
||||||
|
return !ca1 && !ca2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cCaDescriptors::Is(int Source, int Transponder, int ServiceId)
|
||||||
|
{
|
||||||
|
return source == Source && transponder == Transponder && serviceId == ServiceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cCaDescriptors::Is(cCaDescriptors * CaDescriptors)
|
||||||
|
{
|
||||||
|
return Is(CaDescriptors->source, CaDescriptors->transponder, CaDescriptors->serviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCaDescriptors::AddCaId(int CaId)
|
||||||
|
{
|
||||||
|
if (numCaIds < MAXCAIDS) {
|
||||||
|
for (int i = 0; i < numCaIds; i++) {
|
||||||
|
if (caIds[i] == CaId)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
caIds[numCaIds++] = CaId;
|
||||||
|
caIds[numCaIds] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cCaDescriptors::AddCaDescriptor(SI::CaDescriptor *d, bool Stream)
|
||||||
|
{
|
||||||
|
cCaDescriptor *nca = new cCaDescriptor(d->getCaType(), d->getCaPid(), Stream, d->privateData.getLength(), d->privateData.getData());
|
||||||
|
for (cCaDescriptor *ca = caDescriptors.First(); ca; ca = caDescriptors.Next(ca)) {
|
||||||
|
if (*ca == *nca) {
|
||||||
|
delete nca;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AddCaId(nca->CaSystem());
|
||||||
|
caDescriptors.Add(nca);
|
||||||
|
//#define DEBUG_CA_DESCRIPTORS 1
|
||||||
|
#ifdef DEBUG_CA_DESCRIPTORS
|
||||||
|
char buffer[1024];
|
||||||
|
char *q = buffer;
|
||||||
|
q += sprintf(q, "CAM: %04X %5d %5d %04X %d -", source, transponder, serviceId, d->getCaType(), Stream);
|
||||||
|
for (int i = 0; i < nca->Length(); i++)
|
||||||
|
q += sprintf(q, " %02X", nca->Data()[i]);
|
||||||
|
dsyslog(buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int cCaDescriptors::GetCaDescriptors(const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
|
||||||
{
|
{
|
||||||
if (!CaSystemIds || !*CaSystemIds)
|
if (!CaSystemIds || !*CaSystemIds)
|
||||||
return 0;
|
return 0;
|
||||||
if (BufSize > 0 && Data) {
|
if (BufSize > 0 && Data) {
|
||||||
cMutexLock MutexLock(&mutex);
|
|
||||||
int length = 0;
|
int length = 0;
|
||||||
int IsStream = -1;
|
int IsStream = -1;
|
||||||
for (cCaDescriptor *d = First(); d; d = Next(d)) {
|
for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) {
|
||||||
if (d->source == Source && d->transponder == Transponder && d->serviceId == ServiceId) {
|
const unsigned short *caids = CaSystemIds;
|
||||||
const unsigned short *caids = CaSystemIds;
|
do {
|
||||||
do {
|
if (d->CaSystem() == *caids) {
|
||||||
if (d->caSystem == *caids) {
|
if (length + d->Length() <= BufSize) {
|
||||||
if (length + d->Length() <= BufSize) {
|
if (IsStream >= 0 && IsStream != d->Stream())
|
||||||
if (IsStream >= 0 && IsStream != d->stream)
|
dsyslog("CAM: different stream flag in CA descriptors");
|
||||||
dsyslog("CAM: different stream flag in CA descriptors");
|
IsStream = d->Stream();
|
||||||
IsStream = d->stream;
|
memcpy(Data + length, d->Data(), d->Length());
|
||||||
memcpy(Data + length, d->Data(), d->Length());
|
length += d->Length();
|
||||||
length += d->Length();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
} while (*++caids);
|
else
|
||||||
}
|
return -1;
|
||||||
|
}
|
||||||
|
} while (*++caids);
|
||||||
}
|
}
|
||||||
StreamFlag = IsStream == 1;
|
StreamFlag = IsStream == 1;
|
||||||
return length;
|
return length;
|
||||||
@ -146,11 +177,52 @@ int cCaDescriptors::GetCaDescriptors(int Source, int Transponder, int ServiceId,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cCaDescriptors CaDescriptors;
|
// --- cCaDescriptorHandler --------------------------------------------------
|
||||||
|
|
||||||
|
class cCaDescriptorHandler : public cList<cCaDescriptors> {
|
||||||
|
private:
|
||||||
|
cMutex mutex;
|
||||||
|
public:
|
||||||
|
int AddCaDescriptors(cCaDescriptors *CaDescriptors);
|
||||||
|
// Returns 0 if this is an already known descriptor,
|
||||||
|
// 1 if it is an all new descriptor with actual contents,
|
||||||
|
// and 2 if an existing descriptor was changed.
|
||||||
|
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag);
|
||||||
|
};
|
||||||
|
|
||||||
|
int cCaDescriptorHandler::AddCaDescriptors(cCaDescriptors *CaDescriptors)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
|
||||||
|
if (ca->Is(CaDescriptors)) {
|
||||||
|
if (*ca == *CaDescriptors) {
|
||||||
|
delete CaDescriptors;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Del(ca);
|
||||||
|
Add(CaDescriptors);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Add(CaDescriptors);
|
||||||
|
return CaDescriptors->Empty() ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
|
||||||
|
if (ca->Is(Source, Transponder, ServiceId))
|
||||||
|
return ca->GetCaDescriptors(CaSystemIds, BufSize, Data, StreamFlag);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cCaDescriptorHandler CaDescriptorHandler;
|
||||||
|
|
||||||
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
|
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
|
||||||
{
|
{
|
||||||
return CaDescriptors.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, StreamFlag);
|
return CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, StreamFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cPatFilter ------------------------------------------------------------
|
// --- cPatFilter ------------------------------------------------------------
|
||||||
@ -160,6 +232,7 @@ cPatFilter::cPatFilter(void)
|
|||||||
pmtIndex = 0;
|
pmtIndex = 0;
|
||||||
pmtPid = 0;
|
pmtPid = 0;
|
||||||
lastPmtScan = 0;
|
lastPmtScan = 0;
|
||||||
|
numPmtEntries = 0;
|
||||||
Set(0x00, 0x00); // PAT
|
Set(0x00, 0x00); // PAT
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,6 +242,28 @@ void cPatFilter::SetStatus(bool On)
|
|||||||
pmtIndex = 0;
|
pmtIndex = 0;
|
||||||
pmtPid = 0;
|
pmtPid = 0;
|
||||||
lastPmtScan = 0;
|
lastPmtScan = 0;
|
||||||
|
numPmtEntries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPatFilter::Trigger(void)
|
||||||
|
{
|
||||||
|
numPmtEntries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cPatFilter::PmtVersionChanged(int PmtPid, int Version)
|
||||||
|
{
|
||||||
|
Version <<= 16;
|
||||||
|
for (int i = 0; i < numPmtEntries; i++) {
|
||||||
|
if ((pmtVersion[i] & 0x0000FFFF) == PmtPid) {
|
||||||
|
bool Changed = (pmtVersion[i] & 0x00FF0000) != Version;
|
||||||
|
if (Changed)
|
||||||
|
pmtVersion[i] = PmtPid | Version;
|
||||||
|
return Changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numPmtEntries < MAXPMTENTRIES)
|
||||||
|
pmtVersion[numPmtEntries++] = PmtPid | Version;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
||||||
@ -206,21 +301,78 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
|
|||||||
SI::PMT pmt(Data, false);
|
SI::PMT pmt(Data, false);
|
||||||
if (!pmt.CheckCRCAndParse())
|
if (!pmt.CheckCRCAndParse())
|
||||||
return;
|
return;
|
||||||
SI::CaDescriptor *d;
|
if (!PmtVersionChanged(pmtPid, pmt.getVersionNumber())) {
|
||||||
// Scan the common loop:
|
lastPmtScan = 0; // this triggers the next scan
|
||||||
for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)pmt.commonDescriptors.getNext(it, SI::CaDescriptorTag)); ) {
|
return;
|
||||||
CaDescriptors.NewCaDescriptor(Source(), Transponder(), pmt.getServiceId(), d, false);
|
}
|
||||||
delete d;
|
if (!Channels.Lock(true, 10)) {
|
||||||
}
|
numPmtEntries = 0; // to make sure we try again
|
||||||
// Scan the stream-specific loop:
|
return;
|
||||||
SI::PMT::Stream stream;
|
}
|
||||||
for (SI::Loop::Iterator it; pmt.streamLoop.hasNext(it); ) {
|
cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId());
|
||||||
stream = pmt.streamLoop.getNext(it);
|
if (Channel) {
|
||||||
for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)stream.streamDescriptors.getNext(it, SI::CaDescriptorTag)); ) {
|
SI::CaDescriptor *d;
|
||||||
CaDescriptors.NewCaDescriptor(Source(), Transponder(), pmt.getServiceId(), d, true);
|
cCaDescriptors *CaDescriptors = new cCaDescriptors(Channel->Source(), Channel->Transponder(), Channel->Sid());
|
||||||
delete d;
|
// Scan the common loop:
|
||||||
}
|
for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)pmt.commonDescriptors.getNext(it, SI::CaDescriptorTag)); ) {
|
||||||
}
|
CaDescriptors->AddCaDescriptor(d, false);
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
// Scan the stream-specific loop:
|
||||||
|
SI::PMT::Stream stream;
|
||||||
|
int Vpid = 0;
|
||||||
|
int Ppid = pmt.getPCRPid();
|
||||||
|
int Apids[MAXAPIDS] = { 0 };
|
||||||
|
int Dpids[MAXAPIDS] = { 0 };
|
||||||
|
int Tpid = 0;
|
||||||
|
int NumApids = 0;
|
||||||
|
int NumDpids = 0;
|
||||||
|
for (SI::Loop::Iterator it; pmt.streamLoop.hasNext(it); ) {
|
||||||
|
stream = pmt.streamLoop.getNext(it);
|
||||||
|
switch (stream.getStreamType()) {
|
||||||
|
case 1: // STREAMTYPE_11172_VIDEO
|
||||||
|
case 2: // STREAMTYPE_13818_VIDEO
|
||||||
|
Vpid = stream.getPid();
|
||||||
|
break;
|
||||||
|
case 3: // STREAMTYPE_11172_AUDIO
|
||||||
|
case 4: // STREAMTYPE_13818_AUDIO
|
||||||
|
{
|
||||||
|
if (NumApids < MAXAPIDS)
|
||||||
|
Apids[NumApids++] = stream.getPid();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5: // STREAMTYPE_13818_PRIVATE
|
||||||
|
case 6: // STREAMTYPE_13818_PES_PRIVATE
|
||||||
|
//XXX case 8: // STREAMTYPE_13818_DSMCC
|
||||||
|
{
|
||||||
|
SI::Descriptor *d;
|
||||||
|
for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
|
||||||
|
switch (d->getDescriptorTag()) {
|
||||||
|
case SI::AC3DescriptorTag:
|
||||||
|
if (NumDpids < MAXAPIDS)
|
||||||
|
Dpids[NumDpids++] = stream.getPid();
|
||||||
|
break;
|
||||||
|
case SI::TeletextDescriptorTag:
|
||||||
|
Tpid = stream.getPid();
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//default: printf("PID: %5d %5d %2d %3d %3d\n", pmt.getServiceId(), stream.getPid(), stream.getStreamType(), pmt.getVersionNumber(), Channel->Number());//XXX
|
||||||
|
}
|
||||||
|
for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)stream.streamDescriptors.getNext(it, SI::CaDescriptorTag)); ) {
|
||||||
|
CaDescriptors->AddCaDescriptor(d, true);
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Channel->SetPids(Vpid, Ppid, Apids[0], Apids[1], Dpids[0], Dpids[1], Tpid);
|
||||||
|
Channel->SetCaIds(CaDescriptors->CaIds());
|
||||||
|
Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors));
|
||||||
|
}
|
||||||
lastPmtScan = 0; // this triggers the next scan
|
lastPmtScan = 0; // this triggers the next scan
|
||||||
|
Channels.Unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
pat.h
9
pat.h
@ -4,25 +4,30 @@
|
|||||||
* 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: pat.h 1.2 2003/12/24 10:08:22 kls Exp $
|
* $Id: pat.h 1.3 2004/01/03 13:47:54 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PAT_H
|
#ifndef __PAT_H
|
||||||
#define __PAT_H
|
#define __PAT_H
|
||||||
|
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "thread.h"
|
|
||||||
|
#define MAXPMTENTRIES 64
|
||||||
|
|
||||||
class cPatFilter : public cFilter {
|
class cPatFilter : public cFilter {
|
||||||
private:
|
private:
|
||||||
time_t lastPmtScan;
|
time_t lastPmtScan;
|
||||||
int pmtIndex;
|
int pmtIndex;
|
||||||
int pmtPid;
|
int pmtPid;
|
||||||
|
int pmtVersion[MAXPMTENTRIES];
|
||||||
|
int numPmtEntries;
|
||||||
|
bool PmtVersionChanged(int PmtPid, int Version);
|
||||||
protected:
|
protected:
|
||||||
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
|
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
|
||||||
public:
|
public:
|
||||||
cPatFilter(void);
|
cPatFilter(void);
|
||||||
virtual void SetStatus(bool On);
|
virtual void SetStatus(bool On);
|
||||||
|
void Trigger(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag);
|
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag);
|
||||||
|
146
sdt.c
Normal file
146
sdt.c
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* sdt.c: SDT section filter
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: sdt.c 1.1 2004/01/04 11:54:42 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sdt.h"
|
||||||
|
#include "channels.h"
|
||||||
|
#include "libsi/section.h"
|
||||||
|
#include "libsi/descriptor.h"
|
||||||
|
|
||||||
|
// --- cSDT ------------------------------------------------------------------
|
||||||
|
|
||||||
|
class cSDT : public SI::SDT {
|
||||||
|
public:
|
||||||
|
cSDT(int Source, int Transponder, uchar &lastSdtVersion, cPatFilter *PatFilter, const u_char *Data);
|
||||||
|
};
|
||||||
|
|
||||||
|
cSDT::cSDT(int Source, int Transponder, uchar &lastSdtVersion, cPatFilter *PatFilter, const u_char *Data)
|
||||||
|
:SI::SDT(Data, false)
|
||||||
|
{
|
||||||
|
if (!CheckCRCAndParse())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (getVersionNumber() == lastSdtVersion)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!Channels.Lock(true, 10))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lastSdtVersion = getVersionNumber();
|
||||||
|
|
||||||
|
SI::SDT::Service SiSdtService;
|
||||||
|
for (SI::Loop::Iterator it; serviceLoop.hasNext(it); ) {
|
||||||
|
SiSdtService = serviceLoop.getNext(it);
|
||||||
|
|
||||||
|
cChannel *Channel = Channels.GetByChannelID(tChannelID(Source, getOriginalNetworkId(), getTransportStreamId(), SiSdtService.getServiceId()));
|
||||||
|
if (!Channel)
|
||||||
|
Channel = Channels.GetByChannelID(tChannelID(Source, 0, Transponder, SiSdtService.getServiceId()));
|
||||||
|
|
||||||
|
SI::Descriptor *d;
|
||||||
|
for (SI::Loop::Iterator it2; (d = SiSdtService.serviceDescriptors.getNext(it2)); ) {
|
||||||
|
switch (d->getDescriptorTag()) {
|
||||||
|
case SI::ServiceDescriptorTag: {
|
||||||
|
SI::ServiceDescriptor *sd = (SI::ServiceDescriptor *)d;
|
||||||
|
switch (sd->getServiceType()) {
|
||||||
|
case 0x01: // digital television service
|
||||||
|
//XXX TODO case 0x02: // digital radio sound service
|
||||||
|
//XXX TODO case 0x04: // NVOD reference service
|
||||||
|
//XXX TODO case 0x05: // NVOD time-shifted service
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
char *p = sd->serviceName.getText(buffer);
|
||||||
|
char NameBuf[1024];
|
||||||
|
char ShortNameBuf[1024];
|
||||||
|
char *pn = NameBuf;
|
||||||
|
char *ps = ShortNameBuf;
|
||||||
|
int IsShortName = 0;
|
||||||
|
while (*p) {
|
||||||
|
if ((uchar)*p == 0x86)
|
||||||
|
IsShortName++;
|
||||||
|
else if ((uchar)*p == 0x87)
|
||||||
|
IsShortName--;
|
||||||
|
else {
|
||||||
|
*pn++ = *p;
|
||||||
|
if (IsShortName)
|
||||||
|
*ps++ = *p;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
*pn = *ps = 0;
|
||||||
|
pn = NameBuf;
|
||||||
|
if (*NameBuf && *ShortNameBuf) {
|
||||||
|
*ps++ = ',';
|
||||||
|
strcpy(ps, NameBuf);
|
||||||
|
pn = ShortNameBuf;
|
||||||
|
}
|
||||||
|
if (Channel) {
|
||||||
|
Channel->SetId(getOriginalNetworkId(), getTransportStreamId(), SiSdtService.getServiceId());
|
||||||
|
Channel->SetName(pn);
|
||||||
|
// Using SiSdtService.getFreeCaMode() is no good, because some
|
||||||
|
// tv stations set this flag even for non-encrypted channels :-(
|
||||||
|
// The special value 0xFFFF was supposed to mean "unknown encryption"
|
||||||
|
// and would have been overwritten with real CA values later:
|
||||||
|
// Channel->SetCa(SiSdtService.getFreeCaMode() ? 0xFFFF : 0);
|
||||||
|
}
|
||||||
|
else if (*pn) {
|
||||||
|
Channel = Channels.NewChannel(Source, Transponder, pn, getOriginalNetworkId(), getTransportStreamId(), SiSdtService.getServiceId());
|
||||||
|
PatFilter->Trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// Using the CaIdentifierDescriptor is no good, because some tv stations
|
||||||
|
// just don't use it. The actual CA values are collected in pat.c:
|
||||||
|
/*
|
||||||
|
case SI::CaIdentifierDescriptorTag: {
|
||||||
|
SI::CaIdentifierDescriptor *cid = (SI::CaIdentifierDescriptor *)d;
|
||||||
|
if (Channel) {
|
||||||
|
for (SI::Loop::Iterator it; cid->identifiers.hasNext(it); )
|
||||||
|
Channel->SetCa(cid->identifiers.getNext(it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
case SI::NVODReferenceDescriptorTag: {
|
||||||
|
SI::NVODReferenceDescriptor *nrd = (SI::NVODReferenceDescriptor *)d;
|
||||||
|
for (SI::Loop::Iterator it; nrd->serviceLoop.hasNext(it); ) {
|
||||||
|
SI::NVODReferenceDescriptor::Service Service = nrd->serviceLoop.getNext(it);
|
||||||
|
//printf(" %04X-%04X-%04X\n", Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId());//XXX TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Channels.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- cSdtFilter ------------------------------------------------------------
|
||||||
|
|
||||||
|
cSdtFilter::cSdtFilter(cPatFilter *PatFilter)
|
||||||
|
{
|
||||||
|
lastSdtVersion = 0xFF;
|
||||||
|
patFilter = PatFilter;
|
||||||
|
Set(0x11, 0x42); // SDT
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSdtFilter::SetStatus(bool On)
|
||||||
|
{
|
||||||
|
cFilter::SetStatus(On);
|
||||||
|
lastSdtVersion = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
||||||
|
{
|
||||||
|
if (Source() && Transponder())
|
||||||
|
cSDT SDT(Source(), Transponder(), lastSdtVersion, patFilter, Data);
|
||||||
|
}
|
27
sdt.h
Normal file
27
sdt.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* sdt.h: SDT section filter
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: sdt.h 1.1 2004/01/03 13:49:55 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SDT_H
|
||||||
|
#define __SDT_H
|
||||||
|
|
||||||
|
#include "filter.h"
|
||||||
|
#include "pat.h"
|
||||||
|
|
||||||
|
class cSdtFilter : public cFilter {
|
||||||
|
private:
|
||||||
|
uchar lastSdtVersion;
|
||||||
|
cPatFilter *patFilter;
|
||||||
|
protected:
|
||||||
|
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
|
||||||
|
public:
|
||||||
|
cSdtFilter(cPatFilter *PatFilter);
|
||||||
|
virtual void SetStatus(bool On);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__SDT_H
|
13
sections.c
13
sections.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: sections.c 1.1 2003/12/22 11:17:38 kls Exp $
|
* $Id: sections.c 1.2 2004/01/03 12:54:01 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sections.h"
|
#include "sections.h"
|
||||||
@ -108,23 +108,25 @@ void cSectionHandler::Detach(cFilter *Filter)
|
|||||||
|
|
||||||
void cSectionHandler::SetSource(int Source, int Transponder)
|
void cSectionHandler::SetSource(int Source, int Transponder)
|
||||||
{
|
{
|
||||||
|
Lock();
|
||||||
source = Source;
|
source = Source;
|
||||||
transponder = Transponder;
|
transponder = Transponder;
|
||||||
|
Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSectionHandler::SetStatus(bool On)
|
void cSectionHandler::SetStatus(bool On)
|
||||||
{
|
{
|
||||||
|
Lock();
|
||||||
if (on != On) {
|
if (on != On) {
|
||||||
Lock();
|
|
||||||
statusCount++;
|
statusCount++;
|
||||||
for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
|
for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
|
||||||
fi->SetStatus(false);
|
fi->SetStatus(false);
|
||||||
if (On)
|
if (On)
|
||||||
fi->SetStatus(true);
|
fi->SetStatus(true);
|
||||||
}
|
}
|
||||||
Unlock();
|
|
||||||
on = On;
|
on = On;
|
||||||
}
|
}
|
||||||
|
Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSectionHandler::Action(void)
|
void cSectionHandler::Action(void)
|
||||||
@ -144,6 +146,9 @@ void cSectionHandler::Action(void)
|
|||||||
Unlock();
|
Unlock();
|
||||||
|
|
||||||
if (poll(pfd, NumFilters, 1000) != 0) {
|
if (poll(pfd, NumFilters, 1000) != 0) {
|
||||||
|
bool DeviceHasLock = device->HasLock();
|
||||||
|
if (!DeviceHasLock)
|
||||||
|
usleep(100000);
|
||||||
for (int i = 0; i < NumFilters; i++) {
|
for (int i = 0; i < NumFilters; i++) {
|
||||||
if (pfd[i].revents & POLLIN) {
|
if (pfd[i].revents & POLLIN) {
|
||||||
cFilterHandle *fh = NULL;
|
cFilterHandle *fh = NULL;
|
||||||
@ -158,6 +163,8 @@ void cSectionHandler::Action(void)
|
|||||||
// Read section data:
|
// Read section data:
|
||||||
unsigned char buf[4096]; // max. allowed size for any EIT section
|
unsigned char buf[4096]; // max. allowed size for any EIT section
|
||||||
int r = safe_read(fh->handle, buf, sizeof(buf));
|
int r = safe_read(fh->handle, buf, sizeof(buf));
|
||||||
|
if (!DeviceHasLock)
|
||||||
|
continue; // we do the read anyway, to flush any data that might have come from a different transponder
|
||||||
if (r > 3) { // minimum number of bytes necessary to get section length
|
if (r > 3) { // minimum number of bytes necessary to get section length
|
||||||
int len = (((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF)) + 3;
|
int len = (((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF)) + 3;
|
||||||
if (len == r) {
|
if (len == r) {
|
||||||
|
9
svdrp.c
9
svdrp.c
@ -10,7 +10,7 @@
|
|||||||
* and interact with the Video Disk Recorder - or write a full featured
|
* and interact with the Video Disk Recorder - or write a full featured
|
||||||
* graphical interface that sits on top of an SVDRP connection.
|
* graphical interface that sits on top of an SVDRP connection.
|
||||||
*
|
*
|
||||||
* $Id: svdrp.c 1.56 2003/12/21 13:37:10 kls Exp $
|
* $Id: svdrp.c 1.57 2003/12/28 10:09:30 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "svdrp.h"
|
#include "svdrp.h"
|
||||||
@ -476,7 +476,7 @@ void cSVDRP::CmdDELC(const char *Option)
|
|||||||
}
|
}
|
||||||
Channels.Del(channel);
|
Channels.Del(channel);
|
||||||
Channels.ReNumber();
|
Channels.ReNumber();
|
||||||
Channels.Save();
|
Channels.SetModified();
|
||||||
isyslog("channel %s deleted", Option);
|
isyslog("channel %s deleted", Option);
|
||||||
Reply(250, "Channel \"%s\" deleted", Option);
|
Reply(250, "Channel \"%s\" deleted", Option);
|
||||||
}
|
}
|
||||||
@ -810,9 +810,8 @@ void cSVDRP::CmdMODC(const char *Option)
|
|||||||
if (Channels.HasUniqueChannelID(&ch, channel)) {
|
if (Channels.HasUniqueChannelID(&ch, channel)) {
|
||||||
*channel = ch;
|
*channel = ch;
|
||||||
Channels.ReNumber();
|
Channels.ReNumber();
|
||||||
Channels.Save();
|
Channels.SetModified();
|
||||||
isyslog("modifed channel %d %s", channel->Number(), channel->ToText());
|
isyslog("modifed channel %d %s", channel->Number(), channel->ToText());
|
||||||
Timers.Save();
|
|
||||||
Reply(250, "%d %s", channel->Number(), channel->ToText());
|
Reply(250, "%d %s", channel->Number(), channel->ToText());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -886,7 +885,7 @@ void cSVDRP::CmdNEWC(const char *Option)
|
|||||||
*channel = ch;
|
*channel = ch;
|
||||||
Channels.Add(channel);
|
Channels.Add(channel);
|
||||||
Channels.ReNumber();
|
Channels.ReNumber();
|
||||||
Channels.Save();
|
Channels.SetModified();
|
||||||
isyslog("new channel %d %s", channel->Number(), channel->ToText());
|
isyslog("new channel %d %s", channel->Number(), channel->ToText());
|
||||||
Reply(250, "%d %s", channel->Number(), channel->ToText());
|
Reply(250, "%d %s", channel->Number(), channel->ToText());
|
||||||
}
|
}
|
||||||
|
12
thread.c
12
thread.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: thread.c 1.29 2003/12/21 15:17:24 kls Exp $
|
* $Id: thread.c 1.30 2004/01/03 16:59:33 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
@ -80,20 +80,20 @@ void cCondVar::Signal(void)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// --- cRWlock ---------------------------------------------------------------
|
// --- cRwLock ---------------------------------------------------------------
|
||||||
|
|
||||||
cRWlock::cRWlock(bool PreferWriter)
|
cRwLock::cRwLock(bool PreferWriter)
|
||||||
{
|
{
|
||||||
pthread_rwlockattr_t attr = { PreferWriter ? PTHREAD_RWLOCK_PREFER_WRITER_NP : PTHREAD_RWLOCK_PREFER_READER_NP };
|
pthread_rwlockattr_t attr = { PreferWriter ? PTHREAD_RWLOCK_PREFER_WRITER_NP : PTHREAD_RWLOCK_PREFER_READER_NP };
|
||||||
pthread_rwlock_init(&rwlock, &attr);
|
pthread_rwlock_init(&rwlock, &attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
cRWlock::~cRWlock()
|
cRwLock::~cRwLock()
|
||||||
{
|
{
|
||||||
pthread_rwlock_destroy(&rwlock);
|
pthread_rwlock_destroy(&rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cRWlock::Lock(bool Write, int TimeoutMs)
|
bool cRwLock::Lock(bool Write, int TimeoutMs)
|
||||||
{
|
{
|
||||||
int Result = 0;
|
int Result = 0;
|
||||||
struct timespec abstime;
|
struct timespec abstime;
|
||||||
@ -108,7 +108,7 @@ bool cRWlock::Lock(bool Write, int TimeoutMs)
|
|||||||
return Result == 0;
|
return Result == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cRWlock::Unlock(void)
|
void cRwLock::Unlock(void)
|
||||||
{
|
{
|
||||||
pthread_rwlock_unlock(&rwlock);
|
pthread_rwlock_unlock(&rwlock);
|
||||||
}
|
}
|
||||||
|
8
thread.h
8
thread.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: thread.h 1.19 2003/12/21 15:44:31 kls Exp $
|
* $Id: thread.h 1.20 2004/01/03 16:58:50 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __THREAD_H
|
#ifndef __THREAD_H
|
||||||
@ -28,12 +28,12 @@ public:
|
|||||||
//void Signal(void);
|
//void Signal(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
class cRWlock {
|
class cRwLock {
|
||||||
private:
|
private:
|
||||||
pthread_rwlock_t rwlock;
|
pthread_rwlock_t rwlock;
|
||||||
public:
|
public:
|
||||||
cRWlock(bool PreferWriter = false);
|
cRwLock(bool PreferWriter = false);
|
||||||
~cRWlock();
|
~cRwLock();
|
||||||
bool Lock(bool Write, int TimeoutMs = 0);
|
bool Lock(bool Write, int TimeoutMs = 0);
|
||||||
void Unlock(void);
|
void Unlock(void);
|
||||||
};
|
};
|
||||||
|
8
timers.c
8
timers.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: timers.c 1.7 2003/12/13 13:06:29 kls Exp $
|
* $Id: timers.c 1.8 2003/12/27 13:10:04 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
@ -216,8 +216,10 @@ bool cTimer::Parse(const char *s)
|
|||||||
strn0cpy(file, filebuffer, MaxFileName);
|
strn0cpy(file, filebuffer, MaxFileName);
|
||||||
strreplace(file, '|', ':');
|
strreplace(file, '|', ':');
|
||||||
strreplace(summary, '|', '\n');
|
strreplace(summary, '|', '\n');
|
||||||
tChannelID cid = tChannelID::FromString(channelbuffer);
|
if (isnumber(channelbuffer))
|
||||||
channel = cid.Valid() ? Channels.GetByChannelID(cid, true) : Channels.GetByNumber(atoi(channelbuffer));
|
channel = Channels.GetByNumber(atoi(channelbuffer));
|
||||||
|
else
|
||||||
|
channel = Channels.GetByChannelID(tChannelID::FromString(channelbuffer), true);
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
esyslog("ERROR: channel %s not defined", channelbuffer);
|
esyslog("ERROR: channel %s not defined", channelbuffer);
|
||||||
result = false;
|
result = false;
|
||||||
|
43
vdr.5
43
vdr.5
@ -8,7 +8,7 @@
|
|||||||
.\" License as specified in the file COPYING that comes with the
|
.\" License as specified in the file COPYING that comes with the
|
||||||
.\" vdr distribution.
|
.\" vdr distribution.
|
||||||
.\"
|
.\"
|
||||||
.\" $Id: vdr.5 1.20 2003/05/29 11:58:57 kls Exp $
|
.\" $Id: vdr.5 1.21 2004/01/02 15:24:21 kls Exp $
|
||||||
.\"
|
.\"
|
||||||
.TH vdr 5 "1 Jun 2003" "1.2.0" "Video Disk Recorder Files"
|
.TH vdr 5 "1 Jun 2003" "1.2.0" "Video Disk Recorder Files"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
@ -45,7 +45,7 @@ Such a delimiter will not appear in the Channels menu.
|
|||||||
A \fBchannel definition\fR is a line with channel data, where the fields
|
A \fBchannel definition\fR is a line with channel data, where the fields
|
||||||
are separated by ':' characters. Example:
|
are separated by ':' characters. Example:
|
||||||
|
|
||||||
\fBRTL:12188:h:S19.2E:27500:163:104:105:0:12003:0:0:0\fR
|
\fBRTL,RTL Television:12188:h:S19.2E:27500:163:104:105:0:12003:1:1089:0\fR
|
||||||
|
|
||||||
The line number of a channel definition (not counting group separators,
|
The line number of a channel definition (not counting group separators,
|
||||||
and based on a possible previous '@...' parameter)
|
and based on a possible previous '@...' parameter)
|
||||||
@ -57,6 +57,13 @@ to right):
|
|||||||
.B Name
|
.B Name
|
||||||
The channel's name (if the name originally contains a ':' character
|
The channel's name (if the name originally contains a ':' character
|
||||||
it has to be replaced by '|').
|
it has to be replaced by '|').
|
||||||
|
Some tv stations provide a way of deriving a "short name" from the
|
||||||
|
channel name, which can be used in situations where there is not
|
||||||
|
much space for displaying a long name. If a short name is available
|
||||||
|
for this channel, it preceeds the full name and is delimited by a comma,
|
||||||
|
as in
|
||||||
|
|
||||||
|
\fBRTL,RTL Television:...\fR
|
||||||
.TP
|
.TP
|
||||||
.B Frequency
|
.B Frequency
|
||||||
The transponder frequency (as an integer). For DVB-S this value is in MHz. For DVB-C
|
The transponder frequency (as an integer). For DVB-S this value is in MHz. For DVB-C
|
||||||
@ -119,23 +126,33 @@ the audio PIDs, separated by a semicolon, as in
|
|||||||
The teletext PID.
|
The teletext PID.
|
||||||
.TP
|
.TP
|
||||||
.B Conditional access
|
.B Conditional access
|
||||||
An integer defining how this channel can be accessed:
|
A hexadecimal integer defining how this channel can be accessed:
|
||||||
.TS
|
.TS
|
||||||
tab (@);
|
tab (@);
|
||||||
l l.
|
l l.
|
||||||
\fB0\fR@Free To Air
|
\fB0000\fR@Free To Air
|
||||||
\fB1...4\fR@explicitly requires the DVB card with the given number
|
\fB0001...000F\fR@explicitly requires the device with the given number
|
||||||
\fB>=100\fR@requires a specific decryption method defined in \fIca.conf\fR
|
\fB0010...00FF\fR@reserved for user defined assignments defined in \fIca.conf\fR
|
||||||
|
\fB0100...FFFF\fR@specific decryption methods as broadcast in the data stream\fR
|
||||||
.TE
|
.TE
|
||||||
|
Values in the range 0001...00FF will not be overwritten, all other values
|
||||||
|
will be automatically replaced by the actual CA system identifiers received
|
||||||
|
from the data stream. If there is more than one CA system id broadcast, they
|
||||||
|
will be separated by commas, as in
|
||||||
|
|
||||||
|
.B ...:1702,1722,1801:...
|
||||||
|
|
||||||
|
The values are in hex because that's the way they are defined in the "ETR 162"
|
||||||
|
document. Leading zeros may be omitted.
|
||||||
.TP
|
.TP
|
||||||
.B SID
|
.B SID
|
||||||
The Service ID of this channel.
|
The Service ID of this channel.
|
||||||
.TP
|
.TP
|
||||||
.B NID
|
.B NID
|
||||||
The Network ID of this channel (for future use, currently always 0).
|
The Network ID of this channel.
|
||||||
.TP
|
.TP
|
||||||
.B TID
|
.B TID
|
||||||
The Transport stream ID of this channel (for future use, currently always 0).
|
The Transport stream ID of this channel.
|
||||||
.TP
|
.TP
|
||||||
.B RID
|
.B RID
|
||||||
The Radio ID of this channel (typically 0, may be used to distinguish channels where
|
The Radio ID of this channel (typically 0, may be used to distinguish channels where
|
||||||
@ -144,12 +161,12 @@ NID, TID and SID are all equal).
|
|||||||
A particular channel can be uniquely identified by its \fBchannel\ ID\fR,
|
A particular channel can be uniquely identified by its \fBchannel\ ID\fR,
|
||||||
which is a string that looks like this:
|
which is a string that looks like this:
|
||||||
|
|
||||||
\fBS19.2E-0-12188-12003-0\fR
|
\fBS19.2E-1-1089-12003-0\fR
|
||||||
|
|
||||||
The components of this string are the \fBSource\fR (S19.2E), \fBFrequency\fR
|
The components of this string are the \fBSource\fR (S19.2E), \fBNID\fR
|
||||||
(12188, MHz) and \fBSID\fR (12003) as defined above. The parts that are currently
|
(1), \fBTID\fR (1089), \fBSID\fR (12003) and \fBRID\fR (0) as defined above.
|
||||||
\fB0\fR are reserved for future use (the last part can be omitted if it is \fB0\fR,
|
The last part can be omitted if it is \fB0\fR,
|
||||||
so the above example could also be written as \fBS19.2E-0-12188-12003\fR).
|
so the above example could also be written as S19.2E-1-1089-12003).
|
||||||
.br
|
.br
|
||||||
The \fBchannel\ ID\fR is used in the \fItimers.conf\fR and \fIepg.data\fR
|
The \fBchannel\ ID\fR is used in the \fItimers.conf\fR and \fIepg.data\fR
|
||||||
files to properly identify the channels.
|
files to properly identify the channels.
|
||||||
|
21
vdr.c
21
vdr.c
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
* The project's page is at http://www.cadsoft.de/vdr
|
* The project's page is at http://www.cadsoft.de/vdr
|
||||||
*
|
*
|
||||||
* $Id: vdr.c 1.171 2003/12/22 13:29:24 kls Exp $
|
* $Id: vdr.c 1.172 2004/01/04 11:12:05 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -511,6 +511,25 @@ int main(int argc, char *argv[])
|
|||||||
dsyslog("max. latency time %d seconds", MaxLatencyTime);
|
dsyslog("max. latency time %d seconds", MaxLatencyTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Handle channel modifications:
|
||||||
|
if (!Channels.BeingEdited() && Channels.Modified()) {
|
||||||
|
if (Channels.Lock(false, 100)) {
|
||||||
|
Channels.Save(); //XXX only after user changes???
|
||||||
|
Timers.Save();
|
||||||
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
||||||
|
if (Channel && Channel->Modification(CHANNELMOD_RETUNE)) {
|
||||||
|
cRecordControls::ChannelDataModified(Channel);
|
||||||
|
if (Channel->Number() == cDevice::CurrentChannel()) {
|
||||||
|
if (!cDevice::PrimaryDevice()->Replaying()) {
|
||||||
|
isyslog("retuning due to modification of channel %d", Channel->Number());
|
||||||
|
Channels.SwitchTo(Channel->Number());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Channels.Unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
// Channel display:
|
// Channel display:
|
||||||
if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
|
if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
|
||||||
if (!Menu)
|
if (!Menu)
|
||||||
|
Loading…
Reference in New Issue
Block a user