From 6439a8e169167e116efd9630564b5629efcd657b Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 18 Nov 2000 13:57:32 +0100 Subject: [PATCH] All cards write EIT info into the same data structure; free cards scan for EIT info --- HISTORY | 14 +++++++++++++- MANUAL | 6 ++++++ README | 11 ++++++----- config.c | 12 ++++++++---- config.h | 5 +++-- dvbapi.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- dvbapi.h | 21 +++++++++++++++++++-- eit.c | 37 ++++++++++++++++++++++++------------ eit.h | 7 +++++-- i18n.c | 5 ++++- menu.c | 3 ++- thread.c | 8 +++----- thread.h | 14 ++++++++++++-- vdr.c | 10 ++++++++-- 14 files changed, 169 insertions(+), 41 deletions(-) diff --git a/HISTORY b/HISTORY index f1d5bad6..1d2d1cb5 100644 --- a/HISTORY +++ b/HISTORY @@ -266,7 +266,7 @@ Video Disk Recorder Revision History are programmed via the "Schedules" menu) are now replaced by suitable substitutes. -2000-11-12: Version 0.68 +2000-11-18: Version 0.68 - Date and time in the title of an event info page are now always right adjusted. - The 'current channel' is now handled device specific (in case there is more @@ -289,3 +289,15 @@ Video Disk Recorder Revision History CAM module (and thus can continue recording on a different DVB card). - The "Yellow" button in the "What's on now/next?" menus now displays the schedule of the current channel from that menu. +- All DVB cards in a multi-card system now write their EIT information into the + same data structure. +- If there is more than one DVB card in the system, the non-primary cards are + now used to periodically scan through the channels in order to keep the + EPG info up-to-date. Scanning kicks in after 60 seconds of user inactivity + (timeout in order to keep user interactions instantaneously) and each channel + that has the 'pnr' parameter defined in 'channels.conf' is switched to for + 20 seconds. If there is only one DVB card in the system, that card will start + scanning after 5 hours (configurable through the "Setup" menu) of user inactivity + and will switch back to the channel it originally displayed at the first sign of + user activity. Any scanning will only occur if that particular card is not + currently recording or replaying. diff --git a/MANUAL b/MANUAL index 4de0af22..490b689d 100644 --- a/MANUAL +++ b/MANUAL @@ -272,10 +272,16 @@ Video Disk Recorder User's Manual 1 = system time wil be set Note that this works only if VDR is running under a user id that has permisson to set the system time. + MarginStart = 2 Defines how many minutes before the official start time MarginStop = 10 of a broadcast VDR shall start recording, and how long after the official end time it shall stop recording. + EPGScanTimeout = 5 The time (in hours) of user inactivity after which the + DVB card in a single card system starts scanning channels + to keep the EPG up-to-date. + A value of '0' turns off scanning on a single card system. + * Executing system commands The "Main" menu option "Commands" allows you to execute any system commands diff --git a/README b/README index cfc10a76..b1e071ee 100644 --- a/README +++ b/README @@ -1,9 +1,8 @@ -On Screen Menu for the Video Disk Recorder ------------------------------------------- +Video Disk Recorder ('VDR') +--------------------------- -These files contain the source code of an on screen -menu for a video disk recorder based on the DVB driver -of the LinuxTV project (http://linuxtv.org). +These files contain the source code of the "Video Disk Recorder", +which is based on the DVB driver of the LinuxTV project (http://linuxtv.org). For details about the "Video Disk Recorder" project please refer to http://www.cadsoft.de/people/kls/vdr. @@ -13,6 +12,8 @@ Web pages, which can be used within this program. Please see the INSTALL file for details on how to install this program on your computer. +The MANUAL file describes how to operate the VDR. + The author can be contacted at kls@cadsoft.de. Yet another "set-top-box"? diff --git a/config.c b/config.c index f7344169..8964e5a0 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.33 2000/11/12 12:22:40 kls Exp $ + * $Id: config.c 1.34 2000/11/18 13:26:36 kls Exp $ */ #include "config.h" @@ -257,12 +257,14 @@ bool cChannel::Save(FILE *f) return fprintf(f, ToText()) > 0; } -bool cChannel::Switch(cDvbApi *DvbApi) +bool cChannel::Switch(cDvbApi *DvbApi, bool Log) { if (!DvbApi) DvbApi = cDvbApi::PrimaryDvbApi; if (!DvbApi->Recording() && !groupSep) { - isyslog(LOG_INFO, "switching to channel %d", number); + if (Log) { + isyslog(LOG_INFO, "switching to channel %d", number); + } for (int i = 3; i--;) { if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) return true; @@ -720,6 +722,7 @@ cSetup::cSetup(void) SetSystemTime = 0; MarginStart = 2; MarginStop = 10; + EPGScanTimeout = 5; } bool cSetup::Parse(char *s) @@ -738,6 +741,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); + else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); else return false; return true; @@ -788,7 +792,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); fprintf(f, "SetSystemTime = %d\n", SetSystemTime); fprintf(f, "MarginStart = %d\n", MarginStart); - fprintf(f, "MarginStop = %d\n", MarginStop); + fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout); fclose(f); isyslog(LOG_INFO, "saved setup to %s", FileName); return true; diff --git a/config.h b/config.h index dd6b5f88..db3f1edc 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.33 2000/11/12 12:22:24 kls Exp $ + * $Id: config.h 1.34 2000/11/18 13:25:53 kls Exp $ */ #ifndef __CONFIG_H @@ -92,7 +92,7 @@ public: const char *ToText(void); bool Parse(const char *s); bool Save(FILE *f); - bool Switch(cDvbApi *DvbApi = NULL); + bool Switch(cDvbApi *DvbApi = NULL, bool Log = true); }; #define DEFAULTPRIORITY 99 @@ -257,6 +257,7 @@ public: int LnbFrequHi; int SetSystemTime; int MarginStart, MarginStop; + int EPGScanTimeout; cSetup(void); bool Load(const char *FileName); bool Save(const char *FileName = NULL); diff --git a/dvbapi.c b/dvbapi.c index 886348d7..dda8ae98 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.37 2000/11/12 12:59:50 kls Exp $ + * $Id: dvbapi.c 1.38 2000/11/18 13:46:46 kls Exp $ */ #include "dvbapi.h" @@ -1143,6 +1143,7 @@ cDvbApi::~cDvbApi() Stop(); StopRecord(); OvlO(false); //Overlay off! + //XXX the following call sometimes causes a segfault - driver problem? close(videoDev); } #if defined(DEBUG_OSD) || defined(REMOTE_KBD) @@ -1727,7 +1728,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, front.AFC = 1; ioctl(videoDev, VIDIOCSFRONTEND, &front); if (front.sync & 0x1F == 0x1F) { - if (siProcessor) + if (this == PrimaryDvbApi && siProcessor) siProcessor->SetCurrentServiceID(Pnr); currentChannel = ChannelNumber; return true; @@ -2107,3 +2108,55 @@ bool cDvbApi::GetIndex(int *Current, int *Total) return false; } +// --- cEITScanner ----------------------------------------------------------- + +cEITScanner::cEITScanner(void) +{ + lastScan = lastActivity = time(NULL); + currentChannel = 0; + lastChannel = 1; +} + +void cEITScanner::Activity(void) +{ + if (currentChannel) { + Channels.SwitchTo(currentChannel); + currentChannel = 0; + } + lastActivity = time(NULL); +} + +void cEITScanner::Process(void) +{ + if (Channels.MaxNumber() > 1) { + time_t now = time(NULL); + if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) { + for (int i = 0; i < cDvbApi::NumDvbApis; i++) { + cDvbApi *DvbApi = cDvbApi::GetDvbApi(i, 0); + if (DvbApi) { + if (DvbApi != cDvbApi::PrimaryDvbApi || (cDvbApi::NumDvbApis == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) { + if (!(DvbApi->Recording() || DvbApi->Replaying())) { + int oldCh = lastChannel; + int ch = oldCh + 1; + while (ch != oldCh) { + if (ch > Channels.MaxNumber()) + ch = 1; + cChannel *Channel = Channels.GetByNumber(ch); + if (Channel && Channel->pnr) { + if (DvbApi == cDvbApi::PrimaryDvbApi && !currentChannel) + currentChannel = DvbApi->Channel(); + Channel->Switch(DvbApi, false); + lastChannel = ch; + break; + } + ch++; + } + } + } + } + } + lastScan = time(NULL); + } + } +} + diff --git a/dvbapi.h b/dvbapi.h index 7e237379..1f5e1a7d 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.23 2000/11/12 12:52:41 kls Exp $ + * $Id: dvbapi.h 1.24 2000/11/18 13:46:10 kls Exp $ */ #ifndef __DVBAPI_H @@ -45,7 +45,6 @@ public: class cDvbApi { private: int videoDev; - cSIProcessor *siProcessor; cDvbApi(const char *VideoFileName, const char *VbiFileName); public: ~cDvbApi(); @@ -79,6 +78,9 @@ public: // EIT facilities +private: + cSIProcessor *siProcessor; +public: const cSchedules *Schedules(cThreadLock *ThreadLock) const; // Caller must provide a cThreadLock which has to survive the entire // time the returned cSchedules is accessed. Once the cSchedules is no @@ -147,6 +149,7 @@ private: public: bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr); static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } + int Channel(void) { return currentChannel; } // Record/Replay facilities @@ -212,4 +215,18 @@ public: bool GetIndex(int *Current, int *Total = NULL); }; +class cEITScanner { +private: + enum { ActivityTimeout = 60, + ScanTimeout = 20 + }; + time_t lastScan, lastActivity; + int currentChannel, lastChannel; +public: + cEITScanner(void); + bool Active(void) { return currentChannel; } + void Activity(void); + void Process(void); + }; + #endif //__DVBAPI_H diff --git a/eit.c b/eit.c index edc3d7b8..79855282 100644 --- a/eit.c +++ b/eit.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.8 2000/11/02 19:19:06 kls Exp $ + * $Id: eit.c 1.9 2000/11/18 13:42:28 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -1056,15 +1056,20 @@ bool cEIT::WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, #define MAX_FILTERS 20 +int cSIProcessor::numSIProcessors = 0; +cSchedules *cSIProcessor::schedules = NULL; +cMutex cSIProcessor::schedulesMutex; + /** */ cSIProcessor::cSIProcessor(const char *FileName) { + masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master' useTStime = false; filters = NULL; - schedules = NULL; if ((fsvbi = open(FileName, O_RDONLY)) >= 0) { - schedules = new cSchedules; + if (!numSIProcessors++) // the first one creates it + schedules = new cSchedules; filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER)); } else @@ -1078,7 +1083,8 @@ cSIProcessor::~cSIProcessor() Stop(); ShutDownFilters(); delete filters; - delete schedules; + if (!--numSIProcessors) // the last one deletes it + delete schedules; close(fsvbi); } } @@ -1093,7 +1099,7 @@ void cSIProcessor::Action() return; } - dsyslog(LOG_INFO, "EIT processing thread started (pid=%d)", getpid()); + dsyslog(LOG_INFO, "EIT processing thread started (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : ""); unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) unsigned int seclen; @@ -1103,15 +1109,20 @@ void cSIProcessor::Action() while(true) { - time_t now = time(NULL); - struct tm *ptm = localtime(&now); - if (now - lastCleanup > 3600 && ptm->tm_hour == 5) + if (masterSIProcessor) { - LOCK_THREAD; + time_t now = time(NULL); + struct tm *ptm = localtime(&now); + if (now - lastCleanup > 3600 && ptm->tm_hour == 5) + { + LOCK_THREAD; - isyslog(LOG_INFO, "Now cleaning up things"); - schedules->Cleanup(); - lastCleanup = now; + schedulesMutex.Lock(); + isyslog(LOG_INFO, "cleaning up schedules data"); + schedules->Cleanup(); + schedulesMutex.Unlock(); + lastCleanup = now; + } } /* wait data become ready from the bitfilter */ @@ -1150,8 +1161,10 @@ void cSIProcessor::Action() { LOCK_THREAD; + schedulesMutex.Lock(); cEIT ceit(buf, seclen, schedules); ceit.ProcessEIT(); + schedulesMutex.Unlock(); } else dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); diff --git a/eit.h b/eit.h index fec498ba..d5c4ebdc 100644 --- a/eit.h +++ b/eit.h @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.2 2000/10/29 10:21:56 kls Exp $ + * $Id: eit.h 1.3 2000/11/17 16:14:27 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -120,7 +120,10 @@ typedef struct sip_filter { class cSIProcessor : public cThread { private: - cSchedules *schedules; + static int numSIProcessors; + static cSchedules *schedules; + static cMutex schedulesMutex; + bool masterSIProcessor; bool useTStime; SIP_FILTER *filters; int fsvbi; diff --git a/i18n.c b/i18n.c index 94009cb1..94002302 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.2 2000/11/11 16:20:47 kls Exp $ + * $Id: i18n.c 1.3 2000/11/18 13:28:19 kls Exp $ */ /* @@ -250,6 +250,9 @@ const tPhrase Phrases[] = { { "MarginStop", "Zeitpuffer bei Ende", }, + { "EPGScanTimeout", + "Zeit bis EPG Scan", + }, // The days of the week: { "MTWTFSS", "MDMDFSS", diff --git a/menu.c b/menu.c index 08350ea3..3d4b241e 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.48 2000/11/12 16:46:19 kls Exp $ + * $Id: menu.c 1.49 2000/11/18 13:42:52 kls Exp $ */ #include "menu.h" @@ -1527,6 +1527,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditBoolItem(tr("SetSystemTime"), &data.SetSystemTime)); Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart)); Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop)); + Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout)); } eOSState cMenuSetup::ProcessKey(eKeys Key) diff --git a/thread.c b/thread.c index b124581f..67b5ab96 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.3 2000/10/28 15:26:02 kls Exp $ + * $Id: thread.c 1.4 2000/11/14 18:38:25 kls Exp $ */ #include "thread.h" @@ -24,7 +24,6 @@ cThread::cThread(void) signal(SIGIO, SignalHandler); signalHandlerInstalled = true; } - pthread_mutex_init(&mutex, NULL); running = false; parentPid = lockingPid = 0; locked = 0; @@ -32,7 +31,6 @@ cThread::cThread(void) cThread::~cThread() { - pthread_mutex_destroy(&mutex); } void cThread::SignalHandler(int signum) @@ -64,7 +62,7 @@ void cThread::Stop(void) bool cThread::Lock(void) { if (!lockingPid || lockingPid != getpid()) { - pthread_mutex_lock(&mutex); + Mutex.Lock(); lockingPid = getpid(); } locked++; @@ -75,7 +73,7 @@ void cThread::Unlock(void) { if (!--locked) { lockingPid = 0; - pthread_mutex_unlock(&mutex); + Mutex.Unlock(); } } diff --git a/thread.h b/thread.h index b47f6d71..c85c51e2 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.2 2000/10/28 15:08:09 kls Exp $ + * $Id: thread.h 1.3 2000/11/14 18:38:11 kls Exp $ */ #ifndef __THREAD_H @@ -13,11 +13,21 @@ #include #include +class cMutex { +private: + pthread_mutex_t mutex; +public: + cMutex(void) { pthread_mutex_init(&mutex, NULL); } + ~cMutex() { pthread_mutex_destroy(&mutex); } + void Lock(void) { pthread_mutex_lock(&mutex); } + void Unlock(void) { pthread_mutex_unlock(&mutex); } + }; + class cThread { friend class cThreadLock; private: pthread_t thread; - pthread_mutex_t mutex; + cMutex Mutex; pid_t parentPid, lockingPid; int locked; bool running; diff --git a/vdr.c b/vdr.c index 060a9d00..8a842003 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.45 2000/11/11 14:40:11 kls Exp $ + * $Id: vdr.c 1.46 2000/11/18 13:46:56 kls Exp $ */ #include @@ -181,6 +181,8 @@ int main(int argc, char *argv[]) Channels.SwitchTo(1); + cEITScanner EITScanner; + // User interface: Interface = new cInterface(SVDRPport); @@ -205,7 +207,7 @@ int main(int argc, char *argv[]) while (!Interrupted) { // Channel display: - if (cDvbApi::CurrentChannel() != LastChannel) { + if (!EITScanner.Active() && cDvbApi::CurrentChannel() != LastChannel) { if (!Menu) Menu = new cDisplayChannel(cDvbApi::CurrentChannel(), LastChannel > 0); PreviousChannel = LastChannel; @@ -224,6 +226,8 @@ int main(int argc, char *argv[]) // User Input: cOsdBase **Interact = Menu ? &Menu : (cOsdBase **)&ReplayControl; eKeys key = Interface->GetKey(!*Interact || !(*Interact)->NeedsFastResponse()); + if (NORMALKEY(key) != kNone) + EITScanner.Activity(); if (*Interact) { switch ((*Interact)->ProcessKey(key)) { case osMenu: DELETENULL(Menu); @@ -302,6 +306,8 @@ int main(int argc, char *argv[]) default: break; } } + if (!Menu) + EITScanner.Process(); } isyslog(LOG_INFO, "caught signal %d", Interrupted); delete Menu;