summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2006-04-09 09:12:47 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2006-04-09 09:12:47 +0200
commitbfce2b3dba4f4f7f4e6b009b34b2467d3eef6542 (patch)
treef525c931f3f71ff5c4755785ffc94115bb06e9f5
parent24b3579d149a45fa3b09cc22aa09a6ac053bd392 (diff)
downloadvdr-bfce2b3dba4f4f7f4e6b009b34b2467d3eef6542.tar.gz
vdr-bfce2b3dba4f4f7f4e6b009b34b2467d3eef6542.tar.bz2
Fixed VPS recording in case there is more than one timer in the VPS margin
-rw-r--r--HISTORY9
-rw-r--r--device.c7
-rw-r--r--device.h5
-rw-r--r--dvbdevice.c7
-rw-r--r--dvbdevice.h3
-rw-r--r--i18n.c24
-rw-r--r--timers.c26
-rw-r--r--timers.h4
-rw-r--r--vdr.c68
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 <getopt.h>
@@ -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();
}