mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Fixed VPS recording in case there is more than one timer in the VPS margin
This commit is contained in:
		
							
								
								
									
										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<74> kan<61>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(); | ||||
|            } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user