From b2fb654bb333162473d0d0a3a9171b43cff7f990 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Tue, 13 Apr 2021 13:54:00 +0200 Subject: [PATCH] To avoid problems with very short events, non-VPS pattern timers now spawn timers for all matching events that would start while the first one is still recording --- HISTORY | 2 ++ MANUAL | 6 +++--- timers.c | 49 ++++++++++++++++++++++++++++--------------------- timers.h | 4 ++-- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/HISTORY b/HISTORY index 6667d23e..78b081a8 100644 --- a/HISTORY +++ b/HISTORY @@ -9652,3 +9652,5 @@ Video Disk Recorder Revision History was "remote"). - Now adjusting spawned timers before setting events to timers. - Fixed dropping outdated events. +- To avoid problems with very short events, non-VPS pattern timers now spawn timers for all + matching events that would start while the first one is still recording. diff --git a/MANUAL b/MANUAL index 640a9094..4553b78b 100644 --- a/MANUAL +++ b/MANUAL @@ -540,9 +540,9 @@ The following rules apply to pattern timers: with the given start/stop time. Overlapping events are recorded in full, even if they extend outside the given start/stop interval. - In order to actually record an event, a pattern timer "spawns" a separate timer - that does the recording. At most two timers are spawned from a pattern timer at - any given time, one for the next upcoming matching event, and one for - the event immediately following that one, in case it also matches. + that does the recording. If there are matching events that would start while + the first spawned timer is still recording (due to the start/stop margins), timers + for those events are also spawned. - Spawned timers are marked with the flag tfSpawned. - Spawned timers take the Priority, Lifetime and VPS settings from the pattern timer. - The special pattern "*" matches every event. So a timer with diff --git a/timers.c b/timers.c index ab4938a8..c1e5bf99 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 5.11 2021/04/10 11:32:50 kls Exp $ + * $Id: timers.c 5.12 2021/04/13 13:54:00 kls Exp $ */ #include "timers.h" @@ -708,7 +708,7 @@ void cTimer::SetId(int Id) id = Id; } -void cTimer::SpawnPatternTimer(const cEvent *Event, cTimers *Timers) +cTimer *cTimer::SpawnPatternTimer(const cEvent *Event, cTimers *Timers) { cString FileName = MakePatternFileName(Pattern(), Event->Title(), Event->ShortText(), File()); isyslog("spawning timer %s for event %s", *ToDescr(), *Event->ToDescr()); @@ -718,6 +718,7 @@ void cTimer::SpawnPatternTimer(const cEvent *Event, cTimers *Timers) t->SetFlags(tfAvoid); Timers->Add(t); HandleRemoteTimerModifications(t); + return t; } bool cTimer::SpawnPatternTimers(const cSchedules *Schedules, cTimers *Timers) @@ -727,30 +728,36 @@ bool cTimer::SpawnPatternTimers(const cSchedules *Schedules, cTimers *Timers) if (Schedule && Schedule->Events()->First()) { if (Schedule->Modified(scheduleStateSpawn)) { time_t Now = time(NULL); + // Find the first event that matches this pattern timer and either already has a spawned + // timer, or has not yet ended: for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) { if (Matches(e) != tmNone) { - bool CheckThis = false; - bool CheckNext = false; - if (Timers->GetTimerForEvent(e, tfSpawned)) // a matching event that already has a spawned timer - CheckNext = true; - else if (e->EndTime() > Now) { // only look at events that have not yet ended - CheckThis = true; - CheckNext = true; - } - if (CheckThis) { - SpawnPatternTimer(e, Timers); + const cTimer *Timer = Timers->GetTimerForEvent(e, tfSpawned); // a matching event that already has a spawned timer + if (!Timer && e->EndTime() > Now) { // only look at events that have not yet ended + Timer = SpawnPatternTimer(e, Timers); TimersSpawned = true; } - if (CheckNext) { - // We also check the event immediately following this one: - e = Schedule->Events()->Next(e); - if (e && !Timers->GetTimerForEvent(e, tfSpawned) && Matches(e) != tmNone) { - SpawnPatternTimer(e, Timers); - TimersSpawned = true; - } - } - if (CheckThis || CheckNext) + if (Timer) { + // Check all following matching events that would start while the first timer + // is still recording: + bool UseVps = Timer->HasFlags(tfVps); + time_t Limit = Timer->StopTime() + EXPIRELATENCY; + if (!UseVps) + Limit += Setup.MarginStart * 60; + for (e = Schedule->Events()->Next(e); e; e = Schedule->Events()->Next(e)) { + if (e->StartTime() <= Limit) { + if (!Timers->GetTimerForEvent(e, tfSpawned) && Matches(e) != tmNone) { + SpawnPatternTimer(e, Timers); + TimersSpawned = true; + } + if (UseVps) + break; // with VPS we only need to check the event immediately following the first one + } + else + break; // no need to check events that are too far in the future + } break; + } } } } diff --git a/timers.h b/timers.h index 18c8362d..fea94aec 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 5.5 2021/04/10 10:09:50 kls Exp $ + * $Id: timers.h 5.6 2021/04/13 13:54:00 kls Exp $ */ #ifndef __TIMERS_H @@ -99,7 +99,7 @@ public: time_t StartTime(void) const; time_t StopTime(void) const; void SetId(int Id); - void SpawnPatternTimer(const cEvent *Event, cTimers *Timers); + cTimer *SpawnPatternTimer(const cEvent *Event, cTimers *Timers); bool SpawnPatternTimers(const cSchedules *Schedules, cTimers *Timers); bool AdjustSpawnedTimer(void); void TriggerRespawn(void);