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.
|
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.
|
||||||
|
7
device.c
7
device.c
@ -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);
|
||||||
|
5
device.h
5
device.h
@ -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.
|
||||||
|
@ -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);
|
||||||
|
@ -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
24
i18n.c
@ -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!",
|
||||||
|
26
timers.c
26
timers.c
@ -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,19 +450,24 @@ 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) {
|
Event = e;
|
||||||
Event = e;
|
break; // take the first matching event
|
||||||
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 {
|
else {
|
||||||
// Normal timers match the event they have the most overlap with:
|
// Normal timers match the event they have the most overlap with:
|
||||||
@ -487,7 +492,6 @@ void cTimer::SetEventFromSchedule(const cSchedules *Schedules)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetEvent(Event);
|
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
|
* 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;
|
||||||
|
68
vdr.c
68
vdr.c
@ -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,21 +753,61 @@ 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:
|
||||||
TimerInVpsMargin = false;
|
static time_t LastVpsCheck = 0;
|
||||||
for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer)) {
|
if (Now - LastVpsCheck > VPSCHECKDELTA) { // don't do this too often
|
||||||
if (Timer->HasFlags(tfActive | tfVps) && !Timer->Recording() && !Timer->Pending() && Timer->Matches(Now + Setup.VpsMargin, true)) {
|
TimerInVpsMargin = false;
|
||||||
if (!Timer->InVpsMargin()) {
|
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);
|
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
|
||||||
|
Timer->SetInVpsMargin(false);
|
||||||
}
|
}
|
||||||
else
|
LastVpsCheck = time(NULL);
|
||||||
Timer->SetInVpsMargin(false);
|
}
|
||||||
if (Timer->InVpsMargin())
|
|
||||||
TimerInVpsMargin = true;
|
|
||||||
}
|
|
||||||
// Delete expired timers:
|
// Delete expired timers:
|
||||||
Timers.DeleteExpired();
|
Timers.DeleteExpired();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user