1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Fixed VPS recording in case there is more than one timer in the VPS margin

This commit is contained in:
Klaus Schmidinger 2006-04-09 09:12:47 +02:00
parent 24b3579d14
commit bfce2b3dba
9 changed files with 121 additions and 32 deletions

View File

@ -4456,7 +4456,7 @@ Video Disk Recorder Revision History
EPG event has been explicitly set to SI::RunningStatusNotRunning. EPG event has been explicitly set to SI::RunningStatusNotRunning.
- The check for timers to be deleted is now done only every 30 seconds. - 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 - Fixed handling broken PMT records (thanks to Marcel Wiesweg for pointing out how
to detect these). 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. - VPS timers now record only events that have exactly the given start time.
This fix also implements recording several subsequent events that have the This fix also implements recording several subsequent events that have the
same VPS time (like a sports event with intermittent news breaks). 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.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: device.c 1.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" #include "device.h"
@ -547,6 +547,11 @@ bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Needs
return false; return false;
} }
bool cDevice::IsTunedToTransponder(const cChannel *Channel)
{
return false;
}
bool cDevice::MaySwitchTransponder(void) bool cDevice::MaySwitchTransponder(void)
{ {
return !Receiving(true) && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid); return !Receiving(true) && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: device.h 1.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 #ifndef __DEVICE_H
@ -217,6 +217,9 @@ public:
///< function itself actually returns true. ///< function itself actually returns true.
///< The default implementation always returns false, so a derived cDevice ///< The default implementation always returns false, so a derived cDevice
///< class that can provide channels must implement this function. ///< 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); virtual bool MaySwitchTransponder(void);
///< Returns true if it is ok to switch the transponder on this device, ///< Returns true if it is ok to switch the transponder on this device,
///< without disturbing any other activities. ///< without disturbing any other activities.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbdevice.c 1.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" #include "dvbdevice.h"
@ -801,6 +801,11 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
return result; return result;
} }
bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel)
{
return dvbTuner->IsTunedTo(Channel);
}
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
{ {
bool DoTune = !dvbTuner->IsTunedTo(Channel); bool DoTune = !dvbTuner->IsTunedTo(Channel);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbdevice.h 1.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 #ifndef __DVBDEVICE_H
@ -62,6 +62,7 @@ public:
virtual bool ProvidesSource(int Source) const; virtual bool ProvidesSource(int Source) const;
virtual bool ProvidesTransponder(const cChannel *Channel) const; virtual bool ProvidesTransponder(const cChannel *Channel) const;
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const; virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
virtual bool IsTunedToTransponder(const cChannel *Channel);
protected: protected:
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
public: public:

24
i18n.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: 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: * Translations provided by:
* *
@ -2246,6 +2246,28 @@ const tI18nPhrase Phrases[] = {
"*** Ugyldig kanal! ***", "*** Ugyldig kanal! ***",
"*** Neplatný kanál ***", "*** 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!", { "No free DVB device to record!",
"Keine freie DVB-Karte zum Aufnehmen!", "Keine freie DVB-Karte zum Aufnehmen!",
"Ni proste DVB naprave za snemanje!", "Ni proste DVB naprave za snemanje!",

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: timers.c 1.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" #include "timers.h"
@ -330,7 +330,7 @@ char *cTimer::SetFile(const char *File)
return 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; startTime = stopTime = 0;
if (t == 0) if (t == 0)
@ -370,7 +370,7 @@ bool cTimer::Matches(time_t t, bool Directly) const
stopTime = event->EndTime(); stopTime = event->EndTime();
return event->IsRunning(true); 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; return false;
} }
@ -450,12 +450,14 @@ void cTimer::SetEventFromSchedule(const cSchedules *Schedules)
if (Schedule && Schedule->Events()->First()) { if (Schedule && Schedule->Events()->First()) {
time_t now = time(NULL); time_t now = time(NULL);
if (!lastSetEvent || Schedule->Modified() >= lastSetEvent) { if (!lastSetEvent || Schedule->Modified() >= lastSetEvent) {
lastSetEvent = now;
const cEvent *Event = NULL; const cEvent *Event = NULL;
if (HasFlags(tfVps) && Schedule->Events()->First()->Vps()) { 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: // 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)) { for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) {
if (e->RunningStatus() == SI::RunningStatusNotRunning) if (e->StartTime() && e->RunningStatus() != SI::RunningStatusNotRunning) { // skip outdated events
continue; // skip events that have already stopped
int overlap = 0; int overlap = 0;
Matches(e, &overlap); Matches(e, &overlap);
if (overlap > FULLMATCH) { if (overlap > FULLMATCH) {
@ -464,6 +466,9 @@ void cTimer::SetEventFromSchedule(const cSchedules *Schedules)
} }
} }
} }
if (!Event && event && (now <= event->EndTime() || Matches(0, true)))
return; // stay with the old event until the timer has completely expired
}
else { else {
// Normal timers match the event they have the most overlap with: // Normal timers match the event they have the most overlap with:
int Overlap = 0; int Overlap = 0;
@ -487,7 +492,6 @@ void cTimer::SetEventFromSchedule(const cSchedules *Schedules)
} }
} }
SetEvent(Event); SetEvent(Event);
lastSetEvent = now;
} }
} }
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: timers.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 #ifndef __TIMERS_H
@ -73,7 +73,7 @@ public:
static time_t IncDay(time_t t, int Days); static time_t IncDay(time_t t, int Days);
static time_t SetTime(time_t t, int SecondsFromMidnight); static time_t SetTime(time_t t, int SecondsFromMidnight);
char *SetFile(const char *File); 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; int Matches(const cEvent *Event, int *Overlap = NULL) const;
bool Expired(void) const; bool Expired(void) const;
time_t StartTime(void) const; time_t StartTime(void) const;

58
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/vdr * The project's page is at http://www.cadsoft.de/vdr
* *
* $Id: vdr.c 1.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> #include <getopt.h>
@ -72,6 +72,8 @@
#define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready #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 MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
#define SHUTDOWNRETRY 300 // seconds before trying again to shut down #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; } #define EXIT(v) { ExitCode = (v); goto Exit; }
@ -751,20 +753,60 @@ int main(int argc, char *argv[])
LastTimerChannel = Timer->Channel()->Number(); LastTimerChannel = Timer->Channel()->Number();
} }
// Make sure VPS timers "see" their channel early enough: // Make sure VPS timers "see" their channel early enough:
static time_t LastVpsCheck = 0;
if (Now - LastVpsCheck > VPSCHECKDELTA) { // don't do this too often
TimerInVpsMargin = false; TimerInVpsMargin = false;
static time_t DeviceUsed[MAXDEVICES] = { 0 };
for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer)) { 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->HasFlags(tfActive | tfVps) && !Timer->Recording() && Timer->Matches(Now, true, Setup.VpsMargin)) {
if (!Timer->InVpsMargin()) {
Timer->SetInVpsMargin(true); Timer->SetInVpsMargin(true);
//XXX if not primary device has TP??? // Find a device that provides the required transponder:
LastTimerChannel = Timer->Channel()->Number(); cDevice *Device = NULL;
cRecordControls::Start(Timer); // will only switch the device 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 else
Timer->SetInVpsMargin(false); Timer->SetInVpsMargin(false);
if (Timer->InVpsMargin()) }
TimerInVpsMargin = true; LastVpsCheck = time(NULL);
} }
// Delete expired timers: // Delete expired timers:
Timers.DeleteExpired(); Timers.DeleteExpired();