summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2004-01-04 12:30:00 +0100
committerKlaus Schmidinger <vdr@tvdr.de>2004-01-04 12:30:00 +0100
commit8976ebcec5ca1ac03c54209b7cc12e9d14915c6b (patch)
tree8562202f489ee585c1252b2cb4a9e61b3e200efe
parent3a1058fe1fca6d10cea42786aa54abf3d0bd0b94 (diff)
downloadvdr-8976ebcec5ca1ac03c54209b7cc12e9d14915c6b.tar.gz
vdr-8976ebcec5ca1ac03c54209b7cc12e9d14915c6b.tar.bz2
Implemented automatic PID switching and channel detection
-rw-r--r--CONTRIBUTORS2
-rw-r--r--HISTORY25
-rw-r--r--Makefile4
-rw-r--r--PLUGINS/src/sky/HISTORY4
-rw-r--r--PLUGINS/src/sky/sky.c12
-rw-r--r--channels.c223
-rw-r--r--channels.h52
-rw-r--r--ci.c23
-rw-r--r--ci.h3
-rw-r--r--config.h4
-rw-r--r--device.c42
-rw-r--r--device.h13
-rw-r--r--dvbdevice.c77
-rw-r--r--dvbdevice.h6
-rw-r--r--eit.c10
-rw-r--r--eitscan.c144
-rw-r--r--eitscan.h7
-rw-r--r--epg.h4
-rw-r--r--menu.c65
-rw-r--r--menu.h3
-rw-r--r--pat.c332
-rw-r--r--pat.h9
-rw-r--r--sdt.c146
-rw-r--r--sdt.h27
-rw-r--r--sections.c13
-rw-r--r--svdrp.c9
-rw-r--r--thread.c12
-rw-r--r--thread.h8
-rw-r--r--timers.c8
-rw-r--r--vdr.543
-rw-r--r--vdr.c21
31 files changed, 1060 insertions, 291 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 1ae39e7d..d2f715dd 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -216,6 +216,8 @@ Andreas Schultz <aschultz@warp10.net>
for implementing the TerrestrialDeliverySystemDescriptor in libdtv
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 his 'autopid' patch which was helpful when implementing automatic
+ channel data gathering
Aaron Holtzman
for writing 'ac3dec'
diff --git a/HISTORY b/HISTORY
index ad2701bd..fe1e166a 100644
--- a/HISTORY
+++ b/HISTORY
@@ -2470,7 +2470,7 @@ Video Disk Recorder Revision History
- 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").
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
to support logging the thread ids.
- 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
'lockingTid' stuff obsolete (thanks to Stefan Huelswitt).
- Changed font handling to allow language specific character sets.
@@ -2499,7 +2500,7 @@ Video Disk Recorder Revision History
shortened to 'description'.
- Replaced 'libdtv' with 'libsi' (thanks to Marcel Wiesweg), which is thread
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
'newplugin').
- 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
Raschke for reporting this one). This should make SkyCrypt CAMs 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.
diff --git a/Makefile b/Makefile
index 5b3e743f..cc3a3a95 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# 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:
@@ -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\
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\
- 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
FIXFONT_ISO8859_1 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
diff --git a/PLUGINS/src/sky/HISTORY b/PLUGINS/src/sky/HISTORY
index d41904e6..d3da71ec 100644
--- a/PLUGINS/src/sky/HISTORY
+++ b/PLUGINS/src/sky/HISTORY
@@ -12,3 +12,7 @@ VDR Plugin 'sky' Revision History
2003-05-09: Version 0.1.1
- Changed Start() to Initialize().
+
+2004-01-04: Version 0.2.0
+
+- Implemented automatic PID switching and channel detection
diff --git a/PLUGINS/src/sky/sky.c b/PLUGINS/src/sky/sky.c
index ae591378..0f2da6e9 100644
--- a/PLUGINS/src/sky/sky.c
+++ b/PLUGINS/src/sky/sky.c
@@ -3,7 +3,7 @@
*
* 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>
@@ -14,7 +14,7 @@
#include <vdr/plugin.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";
// --- cDigiboxDevice --------------------------------------------------------
@@ -37,6 +37,7 @@ public:
cDigiboxDevice(void);
virtual ~cDigiboxDevice();
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 SetChannelDevice(const cChannel *Channel, bool LiveView);
};
@@ -137,13 +138,18 @@ bool cDigiboxDevice::ProvidesSource(int Source) const
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 result = false;
bool hasPriority = Priority < 0 || Priority > this->Priority();
bool needsDetachReceivers = true;
- if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel->Ca())) {
+ if (ProvidesSource(Channel->Source()) && Channel->Ca() == 0x30) {//XXX
if (Receiving()) {
if (digiboxChannelNumber == Channel->Frequency()) {
needsDetachReceivers = false;
diff --git a/channels.c b/channels.c
index 69ff3c91..9a7965f5 100644
--- a/channels.c
+++ b/channels.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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"
@@ -159,6 +159,7 @@ char *cChannel::buffer = NULL;
cChannel::cChannel(void)
{
+ memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__);
strcpy(name, "Pro7");
frequency = 12480;
source = cSource::FromString("S19.2E");
@@ -170,7 +171,7 @@ cChannel::cChannel(void)
dpid1 = 257;
dpid2 = 0;
tpid = 32;
- ca = 0;
+ caids[0] = 0;
nid = 0;
tid = 0;
sid = 888;
@@ -186,6 +187,28 @@ cChannel::cChannel(void)
transmission = TRANSMISSION_MODE_AUTO;
guard = GUARD_INTERVAL_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)
@@ -194,16 +217,117 @@ cChannel& cChannel::operator= (const cChannel &Channel)
return *this;
}
-static int MHz(int frequency)
+int cChannel::Transponder(void) const
{
- while (frequency > 20000)
- frequency /= 1000;
- return frequency;
+ int tf = frequency;
+ while (tf > 20000)
+ tf /= 1000;
+ return tf;
}
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)
@@ -290,10 +414,10 @@ const char *cChannel::ToText(cChannel *Channel)
char vpidbuf[32];
char *q = vpidbuf;
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 = 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 += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1);
if (Channel->apid2)
@@ -303,7 +427,16 @@ const char *cChannel::ToText(cChannel *Channel)
if (Channel->dpid2)
q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->dpid2);
*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;
}
@@ -336,12 +469,16 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
char *parambuf = NULL;
char *vpidbuf = NULL;
char *apidbuf = NULL;
- int fields = sscanf(s, "%a[^:]:%d :%a[^:]:%a[^:] :%d :%a[^:]:%a[^:]:%d :%d :%d :%d :%d :%d ", &namebuf, &frequency, &parambuf, &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, &parambuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpid, &caidbuf, &sid, &nid, &tid, &rid);
if (fields >= 9) {
if (fields == 9) {
// allow reading of old format
- sid = ca;
- ca = tpid;
+ sid = atoi(caidbuf);
+ delete caidbuf;
+ caidbuf = NULL;
+ caids[0] = tpid;
+ caids[1] = 0;
tpid = 0;
}
vpid = ppid = 0;
@@ -350,24 +487,46 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
ok = false;
if (parambuf && sourcebuf && vpidbuf && apidbuf) {
ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0;
+
char *p = strchr(vpidbuf, '+');
if (p)
*p++ = 0;
sscanf(vpidbuf, "%d", &vpid);
if (p)
sscanf(p, "%d", &ppid);
+ else
+ ppid = vpid;
+
p = strchr(apidbuf, ';');
if (p)
*p++ = 0;
sscanf(apidbuf, "%d ,%d ", &apid1, &apid2);
if (p)
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);
free(parambuf);
free(sourcebuf);
free(vpidbuf);
free(apidbuf);
+ free(caidbuf);
free(namebuf);
if (!GetChannelID().Valid()) {
esyslog("ERROR: channel data results in invalid ID!");
@@ -394,6 +553,12 @@ bool cChannel::Save(FILE *f)
cChannels Channels;
+cChannels::cChannels(void)
+{
+ maxNumber = 0;
+ modified = false;
+}
+
bool cChannels::Load(const char *FileName, bool AllowComments, bool MustExist)
{
if (cConfig<cChannel>::Load(FileName, AllowComments, MustExist)) {
@@ -457,10 +622,10 @@ cChannel *cChannels::GetByNumber(int Number, int SkipGap)
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)) {
- 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 NULL;
@@ -497,3 +662,31 @@ bool cChannels::SwitchTo(int Number)
cChannel *channel = GetByNumber(Number);
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;
+}
diff --git a/channels.h b/channels.h
index 6fa1758c..c3d9ad4e 100644
--- a/channels.h
+++ b/channels.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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
@@ -12,10 +12,22 @@
#include "config.h"
#include "sources.h"
+#include "thread.h"
#include "tools.h"
#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 {
int userValue;
int driverValue;
@@ -46,7 +58,7 @@ public:
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; }
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; }
static tChannelID FromString(const char *s);
const char *ToString(void);
@@ -58,7 +70,7 @@ class cChannel : public cListObject {
private:
static char *buffer;
static const char *ToText(cChannel *Channel);
- enum { MaxChannelName = 32 }; // 31 chars + terminating 0!
+ enum { MaxChannelName = 64 }; // 63 chars + terminating 0!
int __BeginData__;
char name[MaxChannelName];
int frequency; // MHz
@@ -69,7 +81,7 @@ private:
int apid1, apid2;
int dpid1, dpid2;
int tpid;
- int ca;
+ int caids[MAXCAIDS + 1]; // list is zero-terminated
int nid;
int tid;
int sid;
@@ -86,16 +98,19 @@ private:
int guard;
int hierarchy;
int __EndData__;
+ int modification;
const char *ParametersToString(void);
bool StringToParameters(const char *s);
public:
cChannel(void);
+ cChannel(const cChannel *Channel);
cChannel& operator= (const cChannel &Channel);
const char *ToText(void);
bool Parse(const char *s, bool AllowNonUniqueID = false);
bool Save(FILE *f);
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 Srate(void) const { return srate; }
int Vpid(void) const { return vpid; }
@@ -105,8 +120,11 @@ public:
int Dpid1(void) const { return dpid1; }
int Dpid2(void) const { return dpid2; }
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 Rid(void) const { return rid; }
int Number(void) const { return number; }
void SetNumber(int Number) { number = Number; }
bool GroupSep(void) const { return groupSep; }
@@ -123,24 +141,38 @@ public:
bool IsSat(void) const { return (source & cSource::st_Mask) == cSource::stSat; }
bool IsTerr(void) const { return (source & cSource::st_Mask) == cSource::stTerr; }
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> {
-protected:
+class cChannels : public cRwLock, public cConfig<cChannel> {
+private:
int maxNumber;
+ bool modified;
+ int beingEdited;
public:
- cChannels(void) { maxNumber = 0; }
+ cChannels(void);
virtual bool Load(const char *FileName, bool AllowComments = false, bool MustExist = false);
int GetNextGroup(int Idx); // Get next channel group
int GetPrevGroup(int Idx); // Get previous channel group
int GetNextNormal(int Idx); // Get next normal channel (not group)
void ReNumber(void); // Recalculate 'number' based on channel type
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);
+ int BeingEdited(void) { return beingEdited; }
+ void IncBeingEdited(void) { beingEdited++; }
+ void DecBeingEdited(void) { beingEdited--; }
bool HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel = NULL);
bool SwitchTo(int Number);
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;
diff --git a/ci.c b/ci.c
index a6f60562..760052de 100644
--- a/ci.c
+++ b/ci.c
@@ -4,13 +4,9 @@
* See the main source file 'vdr.c' for copyright information and
* 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 <asm/unaligned.h>
#include <ctype.h>
@@ -1570,6 +1566,23 @@ const unsigned short *cCiHandler::GetCaSystemIds(int Slot)
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)
{
cMutexLock MutexLock(&mutex);
diff --git a/ci.h b/ci.h
index 673bad21..71eccd8d 100644
--- a/ci.h
+++ b/ci.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: ci.h 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
@@ -111,6 +111,7 @@ public:
cCiMenu *GetMenu(void);
cCiEnquiry *GetEnquiry(void);
const unsigned short *GetCaSystemIds(int Slot);
+ bool ProvidesCa(const unsigned short *CaSystemIds); //XXX Slot???
bool SetCaPmt(cCiCaPmt &CaPmt, int Slot);
bool Reset(int Slot);
};
diff --git a/config.h b/config.h
index 9125d2c8..08368e4c 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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
@@ -87,7 +87,7 @@ public:
cConfig(void) { fileName = NULL; }
virtual ~cConfig() { free(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();
if (FileName) {
diff --git a/device.c b/device.c
index 20cbe5c5..8f73a142 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 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"
@@ -47,6 +47,7 @@ cDevice::cDevice(void)
sectionHandler = NULL;
eitFilter = NULL;
patFilter = NULL;
+ sdtFilter = NULL;
ciHandler = NULL;
player = NULL;
@@ -68,8 +69,9 @@ cDevice::~cDevice()
for (int i = 0; i < MAXRECEIVERS; i++)
Detach(receiver[i]);
delete ciHandler;
- delete eitFilter;
+ delete sdtFilter;
delete patFilter;
+ delete eitFilter;
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]->Receiving() && !ndr)
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
else if (!device[i]->Receiving() && !device[i]->IsPrimaryDevice())
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
else if (d && device[i]->Priority() < d->Priority())
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
else
pri = 6; // all others
@@ -325,6 +327,7 @@ void cDevice::StartSectionHandler(void)
sectionHandler = new cSectionHandler(this);
AttachFilter(eitFilter = new cEitFilter);
AttachFilter(patFilter = new cPatFilter);
+ AttachFilter(sdtFilter = new cSdtFilter(patFilter));
sectionHandler->SetStatus(true);
}
}
@@ -349,6 +352,11 @@ bool cDevice::ProvidesSource(int Source) const
return false;
}
+bool cDevice::ProvidesTransponder(const cChannel *Channel) const
+{
+ return false;
+}
+
bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
{
return false;
@@ -431,6 +439,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
Result = scrNotAvailable;
}
else {
+ Channels.Lock(false);
cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
// Stop section handling:
if (sectionHandler) {
@@ -440,12 +449,13 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
if (SetChannelDevice(Channel, LiveView)) {
// Start section handling:
if (sectionHandler) {
- sectionHandler->SetSource(Channel->Source(), Channel->Frequency());
+ sectionHandler->SetSource(Channel->Source(), Channel->Transponder());
sectionHandler->SetStatus(true);
}
}
else
Result = scrFailed;
+ Channels.Unlock();
}
if (Result == scrOk) {
@@ -462,6 +472,11 @@ bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
return false;
}
+bool cDevice::HasLock(void)
+{
+ return true;
+}
+
bool cDevice::HasProgramme(void)
{
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
{
return -1;//XXX+ too complex with multiple recordings per device
+ /*XXX
// 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:
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())
ShiftLevel = 0; // no shifting necessary, this device can do the job
return ShiftLevel;
+ XXX*/
}
-int cDevice::ProvidesCa(int Ca) const
+int cDevice::ProvidesCa(const cChannel *Channel) const
{
+ int Ca = Channel->Ca();
if (Ca == CardIndex() + 1)
return 1; // exactly _this_ card was requested
if (Ca && Ca <= MAXDEVICES)
return 0; // a specific card was requested, but not _this_ one
- int result = Ca ? 0 : 1; // 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;
+ return !Ca; // by default every card can provide FTA
}
bool cDevice::Receiving(bool CheckAny) const
diff --git a/device.h b/device.h
index 33b4ad80..196ccfe9 100644
--- a/device.h
+++ b/device.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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
@@ -14,6 +14,7 @@
#include "eit.h"
#include "filter.h"
#include "pat.h"
+#include "sdt.h"
#include "sections.h"
#include "thread.h"
#include "tools.h"
@@ -131,7 +132,8 @@ public:
///< Returns the card index of this device (0 ... MAXDEVICES - 1).
int DeviceNumber(void) const;
///< 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
///< 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.
@@ -161,6 +163,8 @@ protected:
public:
virtual bool ProvidesSource(int Source) const;
///< 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;
///< Returns true if this device can provide the given channel.
///< In case the device has cReceivers attached to it or it is the primary
@@ -192,6 +196,10 @@ protected:
public:
static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; }
///< 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);
///< Returns true if the device is currently showing any programme to
///< the user, either through replaying or live.
@@ -232,6 +240,7 @@ private:
cSectionHandler *sectionHandler;
cEitFilter *eitFilter;
cPatFilter *patFilter;
+ cSdtFilter *sdtFilter;
protected:
void StartSectionHandler(void);
///< A derived device that provides section data must call
diff --git a/dvbdevice.c b/dvbdevice.c
index 76c3340b..15c6786d 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.c 1.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"
@@ -86,7 +86,7 @@ public:
virtual ~cDvbTuner();
bool IsTunedTo(const cChannel *Channel) const;
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)
@@ -114,19 +114,18 @@ cDvbTuner::~cDvbTuner()
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)
{
cMutexLock MutexLock(&mutex);
- bool CaChange = !(Channel->GetChannelID() == channel.GetChannelID());
if (Tune)
tunerStatus = tsSet;
- else if (tunerStatus == tsCam && CaChange)
+ else if (tunerStatus == tsCam)
tunerStatus = tsTuned;
useCa = UseCa;
- if (Channel->Ca() && CaChange)
+ if (Channel->Ca() && tunerStatus != tsCam)
startTime = time(NULL);
channel = *Channel;
newSet.Broadcast();
@@ -268,29 +267,27 @@ void cDvbTuner::Action(void)
continue;
}
}
- if (tunerStatus >= tsLocked) {
- if (ciHandler) {
- if (ciHandler->Process() && useCa) {
- if (tunerStatus != tsCam) {//XXX TODO update in case the CA descriptors have changed
- for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) {
- cCiCaPmt CaPmt(channel.Source(), channel.Frequency(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
- if (CaPmt.Valid()) {
- CaPmt.AddPid(channel.Vpid(), 2);
- CaPmt.AddPid(channel.Apid1(), 4);
- CaPmt.AddPid(channel.Apid2(), 4);
- CaPmt.AddPid(channel.Dpid1(), 0);
- if (ciHandler->SetCaPmt(CaPmt, Slot)) {
- tunerStatus = tsCam;
- startTime = 0;
- }
- }
+ }
+ if (ciHandler) {
+ if (ciHandler->Process() && useCa) {
+ if (tunerStatus == tsLocked) {
+ for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) {
+ cCiCaPmt CaPmt(channel.Source(), channel.Frequency(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
+ if (CaPmt.Valid()) {
+ CaPmt.AddPid(channel.Vpid(), 2);
+ CaPmt.AddPid(channel.Apid1(), 4);
+ CaPmt.AddPid(channel.Apid2(), 4);
+ CaPmt.AddPid(channel.Dpid1(), 0);
+ if (ciHandler->SetCaPmt(CaPmt, Slot)) {
+ tunerStatus = tsCam;
+ 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
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;
}
+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)
{
return new cDvbOsd(x, y);
@@ -661,13 +669,18 @@ bool cDvbDevice::ProvidesSource(int Source) const
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 result = false;
bool hasPriority = Priority < 0 || Priority > this->Priority();
bool needsDetachReceivers = false;
- if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel->Ca())) {
+ if ((Channel->Vpid() || Channel->Apid1()) && ProvidesSource(Channel->Source()) && ProvidesCa(Channel)) {
result = hasPriority;
if (Priority >= 0 && Receiving()) {
if (dvbTuner->IsTunedTo(Channel)) {
@@ -736,15 +749,14 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
if (TurnOffLivePIDs)
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:
if (TurnOnLivePIDs) {
aPid1 = Channel->Apid1();
aPid2 = Channel->Apid2();
- int pPid = Channel->Ppid() ? Channel->Ppid() : Channel->Vpid();
- if (!(AddPid(pPid, ptPcr) && AddPid(Channel->Apid1(), ptAudio) && AddPid(Channel->Vpid(), ptVideo))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
+ if (!(AddPid(Channel->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);
return false;
}
@@ -758,6 +770,11 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
return true;
}
+bool cDvbDevice::HasLock(void)
+{
+ return dvbTuner->Locked();
+}
+
void cDvbDevice::SetVolumeDevice(int Volume)
{
if (HasDecoder()) {
diff --git a/dvbdevice.h b/dvbdevice.h
index f6f6f484..f64e6dda 100644
--- a/dvbdevice.h
+++ b/dvbdevice.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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
@@ -44,6 +44,7 @@ protected:
public:
cDvbDevice(int n);
virtual ~cDvbDevice();
+ virtual int ProvidesCa(const cChannel *Channel) const;
virtual bool HasDecoder(void) const;
// OSD facilities
@@ -61,9 +62,12 @@ private:
void TurnOffLiveMode(void);
public:
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;
protected:
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
+public:
+ virtual bool HasLock(void);
// PID handle facilities
diff --git a/eit.c b/eit.c
index f1071826..45a4d800 100644
--- a/eit.c
+++ b/eit.c
@@ -8,7 +8,7 @@
* 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>.
*
- * $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"
@@ -29,12 +29,10 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
if (!CheckCRCAndParse())
return;
- //XXX TODO use complete channel ID
- cChannel *channel = Channels.GetByServiceID(Source, getServiceId());
+ tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId());
+ cChannel *channel = Channels.GetByChannelID(channelID, true);
if (!channel)
return; // only collect data for known channels
- tChannelID channelID = channel->GetChannelID();
- channelID.ClrRid();
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
// 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
- // 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())
continue;
}
diff --git a/eitscan.c b/eitscan.c
index a12bb44d..d4d1e8f3 100644
--- a/eitscan.c
+++ b/eitscan.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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"
@@ -12,6 +12,68 @@
#include "channels.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::cEITScanner(void)
@@ -20,24 +82,12 @@ cEITScanner::cEITScanner(void)
currentDevice = NULL;
currentChannel = 0;
memset(lastChannel, 0, sizeof(lastChannel));
- numTransponders = 0;
- transponders = NULL;
+ scanList = NULL;
}
cEITScanner::~cEITScanner()
{
- free(transponders);
-}
-
-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;
+ delete scanList;
}
void cEITScanner::Activity(void)
@@ -54,37 +104,51 @@ void cEITScanner::Process(void)
if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
time_t now = time(NULL);
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
- for (int i = 0; i < cDevice::NumDevices(); i++) {
- cDevice *Device = cDevice::GetDevice(i);
- if (Device && Device->CardIndex() < MAXDVBDEVICES) {
- if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
- if (!(Device->Receiving(true) || Device->Replaying())) {
- for (;;) {
- cChannel *Channel = Channels.GetByNumber(lastChannel[Device->DeviceNumber()] + 1, 1);
- if (Channel) {
- lastChannel[Device->DeviceNumber()] = Channel->Number();
- if (Channel->Sid() && Device->ProvidesChannel(Channel) && !TransponderScanned(Channel)) {
- if (Device == cDevice::PrimaryDevice() && !currentChannel) {
- currentChannel = Device->CurrentChannel();
+ if (Channels.Lock(false, 10)) {
+ if (!scanList)
+ scanList = new cScanList();
+ for (bool AnyDeviceSwitched = false; !AnyDeviceSwitched; ) {
+ cScanData *ScanData = NULL;
+ for (int i = 0; i < cDevice::NumDevices(); i++) {
+ cDevice *Device = cDevice::GetDevice(i);
+ if (Device) {
+ if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
+ if (!(Device->Receiving(true) || Device->Replaying())) {
+ if (!ScanData)
+ 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 {
- if (lastChannel[Device->DeviceNumber()])
- numTransponders = 0;
- lastChannel[Device->DeviceNumber()] = 0;
- break;
+ else
+ break;
}
}
- }
+ }
+ }
+ if (ScanData && !AnyDeviceSwitched) {
+ scanList->Del(ScanData);
+ ScanData = NULL;
+ }
+ if (!scanList->Count()) {
+ delete scanList;
+ scanList = NULL;
+ break;
}
}
- }
- lastScan = time(NULL);
+ Channels.Unlock();
+ lastScan = time(NULL);
+ }
}
}
}
diff --git a/eitscan.h b/eitscan.h
index 420f47d0..fff2dee8 100644
--- a/eitscan.h
+++ b/eitscan.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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
@@ -13,6 +13,8 @@
#include <time.h>
#include "config.h"
+class cScanList;
+
class cEITScanner {
private:
enum { ActivityTimeout = 60,
@@ -22,8 +24,7 @@ private:
cDevice *currentDevice;
int currentChannel;
int lastChannel[MAXDEVICES];
- int numTransponders, *transponders;
- bool TransponderScanned(cChannel *Channel);
+ cScanList *scanList;
public:
cEITScanner(void);
~cEITScanner();
diff --git a/epg.h b/epg.h
index 84667848..19332a59 100644
--- a/epg.h
+++ b/epg.h
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* 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
@@ -110,7 +110,7 @@ class cSchedules : public cList<cSchedule> {
friend class cSchedule;
friend class cSchedulesLock;
private:
- cRWlock rwlock;
+ cRwLock rwlock;
static cSchedules schedules;
static const char *epgDataFileName;
static time_t lastCleanup;
diff --git a/menu.c b/menu.c
index 16f2893a..5e628bbb 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 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"
@@ -581,7 +581,7 @@ void cMenuEditChannel::Setup(void)
Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 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));
/* XXX not yet used
Add(new cMenuEditIntItem( tr("Nid"), &data.nid, 0));
@@ -615,7 +615,6 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key)
if (channel) {
*channel = data;
isyslog("edited channel %d %s", channel->Number(), data.ToText());
- Timers.Save();
state = osBack;
}
else {
@@ -626,7 +625,7 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key)
isyslog("added channel %d %s", channel->Number(), data.ToText());
state = osUser1;
}
- Channels.Save();
+ Channels.SetModified();
}
else {
Interface->Error(tr("Channel settings are not unique!"));
@@ -682,6 +681,7 @@ protected:
virtual void Move(int From, int To);
public:
cMenuChannels(void);
+ ~cMenuChannels();
virtual eOSState ProcessKey(eKeys Key);
};
@@ -693,6 +693,12 @@ cMenuChannels::cMenuChannels(void)
Add(new cMenuChannelItem(channel), channel->Number() == cDevice::CurrentChannel());
}
SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark"));
+ Channels.IncBeingEdited();
+}
+
+cMenuChannels::~cMenuChannels()
+{
+ Channels.DecBeingEdited();
}
cChannel *cMenuChannels::GetChannel(int Index)
@@ -704,11 +710,10 @@ cChannel *cMenuChannels::GetChannel(int Index)
void cMenuChannels::Propagate(void)
{
Channels.ReNumber();
- Channels.Save();
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
ci->Set();
- Timers.Save(); // channel numbering has changed!
Display();
+ Channels.SetModified();
}
eOSState cMenuChannels::Switch(void)
@@ -1380,22 +1385,24 @@ void cMenuSchedule::PrepareSchedule(cChannel *Channel)
free(buffer);
if (schedules) {
const cSchedule *Schedule = schedules->GetSchedule(Channel->GetChannelID());
- int num = Schedule->NumEvents();
- const cEvent **pArray = MALLOC(const cEvent *, num);
- if (pArray) {
- time_t now = time(NULL);
- int numreal = 0;
- for (int a = 0; a < num; a++) {
- const cEvent *Event = Schedule->GetEventNumber(a);
- if (Event->StartTime() + Event->Duration() > now)
- pArray[numreal++] = Event;
- }
-
- qsort(pArray, numreal, sizeof(cEvent *), CompareEventTime);
-
- for (int a = 0; a < numreal; a++)
- Add(new cMenuScheduleItem(pArray[a]));
- free(pArray);
+ if (Schedule) {
+ int num = Schedule->NumEvents();
+ const cEvent **pArray = MALLOC(const cEvent *, num);
+ if (pArray) {
+ time_t now = time(NULL);
+ int numreal = 0;
+ for (int a = 0; a < num; a++) {
+ const cEvent *Event = Schedule->GetEventNumber(a);
+ if (Event->StartTime() + Event->Duration() > now)
+ pArray[numreal++] = Event;
+ }
+
+ qsort(pArray, numreal, sizeof(cEvent *), CompareEventTime);
+
+ for (int a = 0; a < numreal; a++)
+ 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)
{
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
diff --git a/menu.h b/menu.h
index ddab9863..041d6f7c 100644
--- a/menu.h
+++ b/menu.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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
@@ -143,6 +143,7 @@ public:
static const char *GetInstantId(const char *LastInstantId);
static cRecordControl *GetRecordControl(const char *FileName);
static void Process(time_t t);
+ static void ChannelDataModified(cChannel *Channel);
static bool Active(void);
static void Shutdown(void);
};
diff --git a/pat.c b/pat.c
index 07980147..3fa6848c 100644
--- a/pat.c
+++ b/pat.c
@@ -4,45 +4,39 @@
* See the main source file 'vdr.c' for copyright information and
* 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 <malloc.h>
+#include "channels.h"
#include "libsi/section.h"
#include "libsi/descriptor.h"
+#include "thread.h"
#define PMT_SCAN_TIMEOUT 10 // seconds
// --- cCaDescriptor ---------------------------------------------------------
class cCaDescriptor : public cListObject {
- friend class cCaDescriptors;
private:
- int source;
- int transponder;
- int serviceId;
int caSystem;
- int providerId;
- int caPid;
bool stream;
int length;
uchar *data;
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();
+ bool operator== (const cCaDescriptor &arg) const;
+ int CaSystem(void) { return caSystem; }
+ int Stream(void) { return stream; }
int Length(void) const { return length; }
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;
- providerId = ProviderId;
- caPid = CaPid;
stream = Stream;
length = Length + 6;
data = MALLOC(uchar, length);
@@ -54,15 +48,6 @@ cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaS
data[5] = CaPid & 0xFF;
if (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()
@@ -70,75 +55,121 @@ cCaDescriptor::~cCaDescriptor()
free(data);
}
+bool cCaDescriptor::operator== (const cCaDescriptor &arg) const
+{
+ return length == arg.length && memcmp(data, arg.data, length) == 0;
+}
+
// --- cCaDescriptors --------------------------------------------------------
-class cCaDescriptors : public cList<cCaDescriptor> {
+class cCaDescriptors : public cListObject {
private:
- cMutex mutex;
+ int source;
+ int transponder;
+ int serviceId;
+ int numCaIds;
+ int caIds[MAXCAIDS + 1];
+ cList<cCaDescriptor> caDescriptors;
+ void AddCaId(int CaId);
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);
+ 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; }
};
-void cCaDescriptors::NewCaDescriptor(int Source, int Transponder, int ServiceId, SI::CaDescriptor *d, bool Stream)
-{
- // The code for determining the ProviderID was taken from 'libdtv'
- // 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;
+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;
}
+}
- 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())
+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;
+ }
}
- Add(new cCaDescriptor(Source, Transponder, ServiceId, d->getCaType(), ProviderID, d->getCaPid(), Stream, Length, Data));
- //XXX update???
+ 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(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
+int cCaDescriptors::GetCaDescriptors(const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
{
if (!CaSystemIds || !*CaSystemIds)
return 0;
if (BufSize > 0 && Data) {
- cMutexLock MutexLock(&mutex);
int length = 0;
int IsStream = -1;
- for (cCaDescriptor *d = First(); d; d = Next(d)) {
- if (d->source == Source && d->transponder == Transponder && d->serviceId == ServiceId) {
- const unsigned short *caids = CaSystemIds;
- do {
- if (d->caSystem == *caids) {
- if (length + d->Length() <= BufSize) {
- if (IsStream >= 0 && IsStream != d->stream)
- dsyslog("CAM: different stream flag in CA descriptors");
- IsStream = d->stream;
- memcpy(Data + length, d->Data(), d->Length());
- length += d->Length();
- }
- else
- return -1;
+ for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) {
+ const unsigned short *caids = CaSystemIds;
+ do {
+ if (d->CaSystem() == *caids) {
+ if (length + d->Length() <= BufSize) {
+ if (IsStream >= 0 && IsStream != d->Stream())
+ dsyslog("CAM: different stream flag in CA descriptors");
+ IsStream = d->Stream();
+ memcpy(Data + length, d->Data(), d->Length());
+ length += d->Length();
}
- } while (*++caids);
- }
+ else
+ return -1;
+ }
+ } while (*++caids);
}
StreamFlag = IsStream == 1;
return length;
@@ -146,11 +177,52 @@ int cCaDescriptors::GetCaDescriptors(int Source, int Transponder, int ServiceId,
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)
{
- return CaDescriptors.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, StreamFlag);
+ return CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, StreamFlag);
}
// --- cPatFilter ------------------------------------------------------------
@@ -160,6 +232,7 @@ cPatFilter::cPatFilter(void)
pmtIndex = 0;
pmtPid = 0;
lastPmtScan = 0;
+ numPmtEntries = 0;
Set(0x00, 0x00); // PAT
}
@@ -169,6 +242,28 @@ void cPatFilter::SetStatus(bool On)
pmtIndex = 0;
pmtPid = 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)
@@ -206,21 +301,78 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
SI::PMT pmt(Data, false);
if (!pmt.CheckCRCAndParse())
return;
- SI::CaDescriptor *d;
- // Scan the common loop:
- for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)pmt.commonDescriptors.getNext(it, SI::CaDescriptorTag)); ) {
- CaDescriptors.NewCaDescriptor(Source(), Transponder(), pmt.getServiceId(), d, false);
- delete d;
- }
- // Scan the stream-specific loop:
- SI::PMT::Stream stream;
- for (SI::Loop::Iterator it; pmt.streamLoop.hasNext(it); ) {
- stream = pmt.streamLoop.getNext(it);
- for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)stream.streamDescriptors.getNext(it, SI::CaDescriptorTag)); ) {
- CaDescriptors.NewCaDescriptor(Source(), Transponder(), pmt.getServiceId(), d, true);
- delete d;
- }
- }
+ if (!PmtVersionChanged(pmtPid, pmt.getVersionNumber())) {
+ lastPmtScan = 0; // this triggers the next scan
+ return;
+ }
+ if (!Channels.Lock(true, 10)) {
+ numPmtEntries = 0; // to make sure we try again
+ return;
+ }
+ cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId());
+ if (Channel) {
+ SI::CaDescriptor *d;
+ cCaDescriptors *CaDescriptors = new cCaDescriptors(Channel->Source(), Channel->Transponder(), Channel->Sid());
+ // 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
+ Channels.Unlock();
}
}
diff --git a/pat.h b/pat.h
index df30c104..dd1a1fe8 100644
--- a/pat.h
+++ b/pat.h
@@ -4,25 +4,30 @@
* See the main source file 'vdr.c' for copyright information and
* 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
#define __PAT_H
#include "filter.h"
-#include "thread.h"
+
+#define MAXPMTENTRIES 64
class cPatFilter : public cFilter {
private:
time_t lastPmtScan;
int pmtIndex;
int pmtPid;
+ int pmtVersion[MAXPMTENTRIES];
+ int numPmtEntries;
+ bool PmtVersionChanged(int PmtPid, int Version);
protected:
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
public:
cPatFilter(void);
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);
diff --git a/sdt.c b/sdt.c
new file mode 100644
index 00000000..a4e91b80
--- /dev/null
+++ b/sdt.c
@@ -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);
+}
diff --git a/sdt.h b/sdt.h
new file mode 100644
index 00000000..8d75f3c7
--- /dev/null
+++ b/sdt.h
@@ -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
diff --git a/sections.c b/sections.c
index 4a2f6d5f..6b4d4907 100644
--- a/sections.c
+++ b/sections.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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"
@@ -108,23 +108,25 @@ void cSectionHandler::Detach(cFilter *Filter)
void cSectionHandler::SetSource(int Source, int Transponder)
{
+ Lock();
source = Source;
transponder = Transponder;
+ Unlock();
}
void cSectionHandler::SetStatus(bool On)
{
+ Lock();
if (on != On) {
- Lock();
statusCount++;
for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
fi->SetStatus(false);
if (On)
fi->SetStatus(true);
}
- Unlock();
on = On;
}
+ Unlock();
}
void cSectionHandler::Action(void)
@@ -144,6 +146,9 @@ void cSectionHandler::Action(void)
Unlock();
if (poll(pfd, NumFilters, 1000) != 0) {
+ bool DeviceHasLock = device->HasLock();
+ if (!DeviceHasLock)
+ usleep(100000);
for (int i = 0; i < NumFilters; i++) {
if (pfd[i].revents & POLLIN) {
cFilterHandle *fh = NULL;
@@ -158,6 +163,8 @@ void cSectionHandler::Action(void)
// Read section data:
unsigned char buf[4096]; // max. allowed size for any EIT section
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
int len = (((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF)) + 3;
if (len == r) {
diff --git a/svdrp.c b/svdrp.c
index 009f2f01..83847a0e 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* 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"
@@ -476,7 +476,7 @@ void cSVDRP::CmdDELC(const char *Option)
}
Channels.Del(channel);
Channels.ReNumber();
- Channels.Save();
+ Channels.SetModified();
isyslog("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)) {
*channel = ch;
Channels.ReNumber();
- Channels.Save();
+ Channels.SetModified();
isyslog("modifed channel %d %s", channel->Number(), channel->ToText());
- Timers.Save();
Reply(250, "%d %s", channel->Number(), channel->ToText());
}
else
@@ -886,7 +885,7 @@ void cSVDRP::CmdNEWC(const char *Option)
*channel = ch;
Channels.Add(channel);
Channels.ReNumber();
- Channels.Save();
+ Channels.SetModified();
isyslog("new channel %d %s", channel->Number(), channel->ToText());
Reply(250, "%d %s", channel->Number(), channel->ToText());
}
diff --git a/thread.c b/thread.c
index 31e14a2b..974362c9 100644
--- a/thread.c
+++ b/thread.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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"
@@ -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_rwlock_init(&rwlock, &attr);
}
-cRWlock::~cRWlock()
+cRwLock::~cRwLock()
{
pthread_rwlock_destroy(&rwlock);
}
-bool cRWlock::Lock(bool Write, int TimeoutMs)
+bool cRwLock::Lock(bool Write, int TimeoutMs)
{
int Result = 0;
struct timespec abstime;
@@ -108,7 +108,7 @@ bool cRWlock::Lock(bool Write, int TimeoutMs)
return Result == 0;
}
-void cRWlock::Unlock(void)
+void cRwLock::Unlock(void)
{
pthread_rwlock_unlock(&rwlock);
}
diff --git a/thread.h b/thread.h
index 124a930e..1804a5a6 100644
--- a/thread.h
+++ b/thread.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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
@@ -28,12 +28,12 @@ public:
//void Signal(void);
};
-class cRWlock {
+class cRwLock {
private:
pthread_rwlock_t rwlock;
public:
- cRWlock(bool PreferWriter = false);
- ~cRWlock();
+ cRwLock(bool PreferWriter = false);
+ ~cRwLock();
bool Lock(bool Write, int TimeoutMs = 0);
void Unlock(void);
};
diff --git a/timers.c b/timers.c
index 36e249c3..1db88a0f 100644
--- a/timers.c
+++ b/timers.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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"
@@ -216,8 +216,10 @@ bool cTimer::Parse(const char *s)
strn0cpy(file, filebuffer, MaxFileName);
strreplace(file, '|', ':');
strreplace(summary, '|', '\n');
- tChannelID cid = tChannelID::FromString(channelbuffer);
- channel = cid.Valid() ? Channels.GetByChannelID(cid, true) : Channels.GetByNumber(atoi(channelbuffer));
+ if (isnumber(channelbuffer))
+ channel = Channels.GetByNumber(atoi(channelbuffer));
+ else
+ channel = Channels.GetByChannelID(tChannelID::FromString(channelbuffer), true);
if (!channel) {
esyslog("ERROR: channel %s not defined", channelbuffer);
result = false;
diff --git a/vdr.5 b/vdr.5
index 67bdc37b..761c400d 100644
--- a/vdr.5
+++ b/vdr.5
@@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the
.\" 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"
.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
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,
and based on a possible previous '@...' parameter)
@@ -57,6 +57,13 @@ to right):
.B Name
The channel's name (if the name originally contains a ':' character
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
.B Frequency
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.
.TP
.B Conditional access
-An integer defining how this channel can be accessed:
+A hexadecimal integer defining how this channel can be accessed:
.TS
tab (@);
l l.
-\fB0\fR@Free To Air
-\fB1...4\fR@explicitly requires the DVB card with the given number
-\fB>=100\fR@requires a specific decryption method defined in \fIca.conf\fR
+\fB0000\fR@Free To Air
+\fB0001...000F\fR@explicitly requires the device with the given number
+\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
+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
.B SID
The Service ID of this channel.
.TP
.B NID
-The Network ID of this channel (for future use, currently always 0).
+The Network ID of this channel.
.TP
.B TID
-The Transport stream ID of this channel (for future use, currently always 0).
+The Transport stream ID of this channel.
.TP
.B RID
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,
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
-(12188, MHz) and \fBSID\fR (12003) as defined above. The parts that are currently
-\fB0\fR are reserved for future use (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).
+The components of this string are the \fBSource\fR (S19.2E), \fBNID\fR
+(1), \fBTID\fR (1089), \fBSID\fR (12003) and \fBRID\fR (0) as defined above.
+The last part can be omitted if it is \fB0\fR,
+so the above example could also be written as S19.2E-1-1089-12003).
.br
The \fBchannel\ ID\fR is used in the \fItimers.conf\fR and \fIepg.data\fR
files to properly identify the channels.
diff --git a/vdr.c b/vdr.c
index 4adb1868..fc12f005 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* 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>
@@ -511,6 +511,25 @@ int main(int argc, char *argv[])
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:
if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
if (!Menu)