From bfce2b3dba4f4f7f4e6b009b34b2467d3eef6542 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 9 Apr 2006 09:12:47 +0200 Subject: [PATCH] Fixed VPS recording in case there is more than one timer in the VPS margin --- HISTORY | 9 ++++++- device.c | 7 +++++- device.h | 5 +++- dvbdevice.c | 7 +++++- dvbdevice.h | 3 ++- i18n.c | 24 ++++++++++++++++++- timers.c | 26 +++++++++++--------- timers.h | 4 ++-- vdr.c | 68 +++++++++++++++++++++++++++++++++++++++++++---------- 9 files changed, 121 insertions(+), 32 deletions(-) diff --git a/HISTORY b/HISTORY index 1d8edf5b..1045b404 100644 --- a/HISTORY +++ b/HISTORY @@ -4456,7 +4456,7 @@ Video Disk Recorder Revision History EPG event has been explicitly set to SI::RunningStatusNotRunning. - The check for timers to be deleted is now done only every 30 seconds. -2006-04-01: Version 1.3.46 +2006-04-09: Version 1.3.46 - Fixed handling broken PMT records (thanks to Marcel Wiesweg for pointing out how to detect these). @@ -4471,3 +4471,10 @@ Video Disk Recorder Revision History - VPS timers now record only events that have exactly the given start time. This fix also implements recording several subsequent events that have the same VPS time (like a sports event with intermittent news breaks). +- When checking for timers that have entered the "VPS margin", any free devices are + now used to switch to the needed transponder. This improves cases where more than + one VPS timer is about to start. +- Fixed handling the VPS margin in case the event's duration is shorter than the + margin. +- Fixed handling VPS timers in case the primary device needs to switch to the + timer's transponder. diff --git a/device.c b/device.c index dfb95f4c..6b4cc8ae 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.125 2006/03/26 09:42:48 kls Exp $ + * $Id: device.c 1.126 2006/04/02 13:08:08 kls Exp $ */ #include "device.h" @@ -547,6 +547,11 @@ bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Needs return false; } +bool cDevice::IsTunedToTransponder(const cChannel *Channel) +{ + return false; +} + bool cDevice::MaySwitchTransponder(void) { return !Receiving(true) && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid); diff --git a/device.h b/device.h index 16fa370b..23663e84 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.73 2006/03/26 09:42:40 kls Exp $ + * $Id: device.h 1.74 2006/04/02 13:08:13 kls Exp $ */ #ifndef __DEVICE_H @@ -217,6 +217,9 @@ public: ///< function itself actually returns true. ///< The default implementation always returns false, so a derived cDevice ///< class that can provide channels must implement this function. + virtual bool IsTunedToTransponder(const cChannel *Channel); + ///< Returns true if this device is currently tuned to the given Channel's + ///< transponder. virtual bool MaySwitchTransponder(void); ///< Returns true if it is ok to switch the transponder on this device, ///< without disturbing any other activities. diff --git a/dvbdevice.c b/dvbdevice.c index af9b4a84..db6a4476 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.155 2006/03/26 09:42:54 kls Exp $ + * $Id: dvbdevice.c 1.156 2006/04/01 14:19:43 kls Exp $ */ #include "dvbdevice.h" @@ -801,6 +801,11 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne return result; } +bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel) +{ + return dvbTuner->IsTunedTo(Channel); +} + bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) { bool DoTune = !dvbTuner->IsTunedTo(Channel); diff --git a/dvbdevice.h b/dvbdevice.h index ac84a946..6f2078ab 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.38 2006/02/04 10:21:51 kls Exp $ + * $Id: dvbdevice.h 1.39 2006/04/01 14:18:59 kls Exp $ */ #ifndef __DVBDEVICE_H @@ -62,6 +62,7 @@ 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; + virtual bool IsTunedToTransponder(const cChannel *Channel); protected: virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); public: diff --git a/i18n.c b/i18n.c index 63977cec..06c58ecd 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.253 2006/03/31 12:58:26 kls Exp $ + * $Id: i18n.c 1.254 2006/04/08 13:52:28 kls Exp $ * * Translations provided by: * @@ -2246,6 +2246,28 @@ const tI18nPhrase Phrases[] = { "*** Ugyldig kanal! ***", "*** Neplatný kanál ***", }, + { "Upcoming VPS recording!", + "VPS-Aufnahme beginnt in Kürze!", + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + }, { "No free DVB device to record!", "Keine freie DVB-Karte zum Aufnehmen!", "Ni proste DVB naprave za snemanje!", diff --git a/timers.c b/timers.c index 6439c0ea..f620735f 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.56 2006/04/01 13:27:14 kls Exp $ + * $Id: timers.c 1.57 2006/04/09 09:10:08 kls Exp $ */ #include "timers.h" @@ -330,7 +330,7 @@ char *cTimer::SetFile(const char *File) return file; } -bool cTimer::Matches(time_t t, bool Directly) const +bool cTimer::Matches(time_t t, bool Directly, int Margin) const { startTime = stopTime = 0; if (t == 0) @@ -370,7 +370,7 @@ bool cTimer::Matches(time_t t, bool Directly) const stopTime = event->EndTime(); return event->IsRunning(true); } - return startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers + return startTime <= t + Margin && t < stopTime; // must stop *before* stopTime to allow adjacent timers } return false; } @@ -450,19 +450,24 @@ void cTimer::SetEventFromSchedule(const cSchedules *Schedules) if (Schedule && Schedule->Events()->First()) { time_t now = time(NULL); if (!lastSetEvent || Schedule->Modified() >= lastSetEvent) { + lastSetEvent = now; const cEvent *Event = NULL; if (HasFlags(tfVps) && Schedule->Events()->First()->Vps()) { + if (event && Recording()) + return; // let the recording end first // VPS timers only match if their start time exactly matches the event's VPS time: for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) { - if (e->RunningStatus() == SI::RunningStatusNotRunning) - continue; // skip events that have already stopped - int overlap = 0; - Matches(e, &overlap); - if (overlap > FULLMATCH) { - Event = e; - break; // take the first matching event + if (e->StartTime() && e->RunningStatus() != SI::RunningStatusNotRunning) { // skip outdated events + int overlap = 0; + Matches(e, &overlap); + if (overlap > FULLMATCH) { + Event = e; + break; // take the first matching event + } } } + if (!Event && event && (now <= event->EndTime() || Matches(0, true))) + return; // stay with the old event until the timer has completely expired } else { // Normal timers match the event they have the most overlap with: @@ -487,7 +492,6 @@ void cTimer::SetEventFromSchedule(const cSchedules *Schedules) } } SetEvent(Event); - lastSetEvent = now; } } } diff --git a/timers.h b/timers.h index 8b86cc3a..8abc5238 100644 --- a/timers.h +++ b/timers.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: timers.h 1.27 2006/03/26 14:38:46 kls Exp $ + * $Id: timers.h 1.28 2006/04/08 12:41:44 kls Exp $ */ #ifndef __TIMERS_H @@ -73,7 +73,7 @@ public: static time_t IncDay(time_t t, int Days); static time_t SetTime(time_t t, int SecondsFromMidnight); char *SetFile(const char *File); - bool Matches(time_t t = 0, bool Directly = false) const; + bool Matches(time_t t = 0, bool Directly = false, int Margin = 0) const; int Matches(const cEvent *Event, int *Overlap = NULL) const; bool Expired(void) const; time_t StartTime(void) const; diff --git a/vdr.c b/vdr.c index 2589e2e4..904f637a 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.252 2006/04/01 12:55:33 kls Exp $ + * $Id: vdr.c 1.253 2006/04/09 09:10:41 kls Exp $ */ #include @@ -72,6 +72,8 @@ #define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready #define MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed #define SHUTDOWNRETRY 300 // seconds before trying again to shut down +#define VPSCHECKDELTA 10 // seconds between checks for timers that have entered the VPS margin +#define VPSDEVICETIMEOUT 8 // seconds before a device used for VPS may be reused #define EXIT(v) { ExitCode = (v); goto Exit; } @@ -751,21 +753,61 @@ int main(int argc, char *argv[]) LastTimerChannel = Timer->Channel()->Number(); } // Make sure VPS timers "see" their channel early enough: - TimerInVpsMargin = false; - for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer)) { - if (Timer->HasFlags(tfActive | tfVps) && !Timer->Recording() && !Timer->Pending() && Timer->Matches(Now + Setup.VpsMargin, true)) { - if (!Timer->InVpsMargin()) { + static time_t LastVpsCheck = 0; + if (Now - LastVpsCheck > VPSCHECKDELTA) { // don't do this too often + TimerInVpsMargin = false; + static time_t DeviceUsed[MAXDEVICES] = { 0 }; + for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer)) { + if (Timer->HasFlags(tfActive | tfVps) && !Timer->Recording() && Timer->Matches(Now, true, Setup.VpsMargin)) { Timer->SetInVpsMargin(true); - //XXX if not primary device has TP??? - LastTimerChannel = Timer->Channel()->Number(); - cRecordControls::Start(Timer); // will only switch the device + // Find a device that provides the required transponder: + cDevice *Device = NULL; + for (int i = 0; i < cDevice::NumDevices(); i++) { + cDevice *d = cDevice::GetDevice(i); + if (d && d->ProvidesTransponder(Timer->Channel())) { + if (d->IsTunedToTransponder(Timer->Channel())) { + // if any device is tuned to the transponder, we're done + Device = d; + break; + } + else if (Now - DeviceUsed[d->DeviceNumber()] > VPSDEVICETIMEOUT) { + // only check other devices if they have been left alone for a while + if (d->MaySwitchTransponder()) + // this one can be switched without disturbing anything else + Device = d; + else if (!Device && !d->Receiving() && d->ProvidesTransponderExclusively(Timer->Channel())) + // use this one only if no other with less impact can be found + Device = d; + } + } + } + if (!Device) { + cDevice *d = cDevice::ActualDevice(); + if (!d->Receiving() && d->ProvidesTransponder(Timer->Channel()) && Now - DeviceUsed[d->DeviceNumber()] > VPSDEVICETIMEOUT) + Device = d; // use the actual device as a last resort + } + // Switch the device to the transponder: + if (Device) { + if (Device == cDevice::ActualDevice() && !Device->IsPrimaryDevice()) + cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode + if (!Device->IsTunedToTransponder(Timer->Channel())) { + dsyslog("switching device %d to channel %d", Device->DeviceNumber() + 1, Timer->Channel()->Number()); + Device->SwitchChannel(Timer->Channel(), false); + DeviceUsed[Device->DeviceNumber()] = Now; + } + if (cDevice::PrimaryDevice()->HasDecoder() && !cDevice::PrimaryDevice()->HasProgramme()) { + // the previous SwitchChannel() has switched away the current live channel + Channels.SwitchTo(Timer->Channel()->Number()); // avoids toggling between old channel and black screen + Skins.Message(mtInfo, tr("Upcoming VPS recording!")); + } + } + TimerInVpsMargin = true; } + else + Timer->SetInVpsMargin(false); } - else - Timer->SetInVpsMargin(false); - if (Timer->InVpsMargin()) - TimerInVpsMargin = true; - } + LastVpsCheck = time(NULL); + } // Delete expired timers: Timers.DeleteExpired(); }