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:
parent
24b3579d14
commit
bfce2b3dba
9
HISTORY
9
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.
|
||||
|
7
device.c
7
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);
|
||||
|
5
device.h
5
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.
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
24
i18n.c
24
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!",
|
||||
|
26
timers.c
26
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
timers.h
4
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;
|
||||
|
68
vdr.c
68
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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user