From 5b65773ec836a6086374657098bbcc55e74abd60 Mon Sep 17 00:00:00 2001
From: Klaus Schmidinger <vdr@tvdr.de>
Date: Sun, 12 Nov 2000 14:06:53 +0100
Subject: Using timer priority to interrupt lower priority timer recording

---
 HISTORY  |  8 +++++++-
 MANUAL   |  4 +++-
 config.c | 10 +++++-----
 config.h |  5 ++++-
 dvbapi.c | 30 ++++++++++++++++++++----------
 dvbapi.h | 25 +++++++++++++++++++------
 menu.c   | 19 ++++++++++++++++---
 menu.h   |  4 +++-
 8 files changed, 77 insertions(+), 28 deletions(-)

diff --git a/HISTORY b/HISTORY
index bf328597..6057a8ad 100644
--- a/HISTORY
+++ b/HISTORY
@@ -266,7 +266,7 @@ Video Disk Recorder Revision History
   are programmed via the "Schedules" menu) are now replaced by suitable
   substitutes.
 
-2000-11-11: Version 0.68
+2000-11-12: Version 0.68
 
 - Date and time in the title of an event info page are now always right adjusted.
 - The 'current channel' is now handled device specific (in case there is more
@@ -281,3 +281,9 @@ Video Disk Recorder Revision History
 - There can now be a configuration file named 'commands.conf' that defines
   commands that can be executed through the "Main" menu's "Commands" option
   (see FORMATS for details on how to define these commands).
+- The 'Priority' parameter of the timers is now also used to interrupt a low
+  priority timer recording if a higher priority timer wants to record.
+- A timer recording on a DVB card with a CAM module will now be interrupted
+  by a timer that needs to use this specific DVB card to record an encrypted
+  channel, if the timer currently occupying this DVB card doesn't need the
+  CAM module (and thus can continue recording on a different DVB card).
diff --git a/MANUAL b/MANUAL
index 3f0b1f7b..a72c580d 100644
--- a/MANUAL
+++ b/MANUAL
@@ -203,7 +203,9 @@ Video Disk Recorder User's Manual
              to free space for a new recording. If the disk is full and a new
              recording needs more space, an existing recording with the lowest
              Priority (and which has exceeded its guaranteed Lifetime) will be
-             removed.
+             removed. If all available DVB cards are currently occupied, a
+             timer with a higher priority will interrupt the timer with the
+             lowest priority in order to start recording.
   Lifetime:  The number of days (0..99) a recording made through this timer is
              guaranteed to remain on disk before it is automatically removed
              to free up space for a new recording. Note that setting this
diff --git a/config.c b/config.c
index d4f8b383..f7344169 100644
--- a/config.c
+++ b/config.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: config.c 1.32 2000/11/11 15:41:07 kls Exp $
+ * $Id: config.c 1.33 2000/11/12 12:22:40 kls Exp $
  */
 
 #include "config.h"
@@ -294,8 +294,8 @@ cTimer::cTimer(bool Instant)
   if (stop >= 2400)
      stop -= 2400;
 //TODO VPS???
-  priority = 99;
-  lifetime = 99;
+  priority = DEFAULTPRIORITY;
+  lifetime = DEFAULTLIFETIME;
   *file = 0;
   summary = NULL;
   if (Instant && ch)
@@ -319,8 +319,8 @@ cTimer::cTimer(const cEventInfo *EventInfo)
   stop = time->tm_hour * 100 + time->tm_min;
   if (stop >= 2400)
      stop -= 2400;
-  priority = 99;
-  lifetime = 99;
+  priority = DEFAULTPRIORITY;
+  lifetime = DEFAULTLIFETIME;
   *file = 0;
   const char *Title = EventInfo->GetTitle();
   if (!isempty(Title))
diff --git a/config.h b/config.h
index c6f6ba99..dd6b5f88 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: config.h 1.32 2000/11/11 14:39:40 kls Exp $
+ * $Id: config.h 1.33 2000/11/12 12:22:24 kls Exp $
  */
 
 #ifndef __CONFIG_H
@@ -95,6 +95,9 @@ public:
   bool Switch(cDvbApi *DvbApi = NULL);
   };
 
+#define DEFAULTPRIORITY 99
+#define DEFAULTLIFETIME 99
+
 class cTimer : public cListObject {
 private:
   time_t startTime, stopTime;
diff --git a/dvbapi.c b/dvbapi.c
index 0737d304..886348d7 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbapi.c 1.36 2000/11/05 18:30:58 kls Exp $
+ * $Id: dvbapi.c 1.37 2000/11/12 12:59:50 kls Exp $
  */
 
 #include "dvbapi.h"
@@ -1091,6 +1091,8 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName)
   pidRecord = pidReplay = 0;
   fromRecord = toRecord = -1;
   fromReplay = toReplay = -1;
+  ca = 0;
+  priority = -1;
   videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK);
   if (videoDev >= 0) {
      siProcessor = new cSIProcessor(VbiFileName);
@@ -1161,22 +1163,25 @@ bool cDvbApi::SetPrimaryDvbApi(int n)
   return false;
 }
 
-cDvbApi *cDvbApi::GetDvbApi(int Ca)
+cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority)
 {
   cDvbApi *d = NULL;
-  Ca--;
+  int index = Ca - 1;
   for (int i = MAXDVBAPI; --i >= 0; ) {
-      if (dvbApi[i] && !dvbApi[i]->Recording()) {
-         if (i == Ca)
-            return dvbApi[i];
-         if (Ca < 0) {
+      if (dvbApi[i]) {
+         if (i == index) { // means we need exactly _this_ device
             d = dvbApi[i];
-            if (d != PrimaryDvbApi)
+            break;
+            }
+         else if (Ca == 0) { // means any device would be acceptable
+            if (!d || !dvbApi[i]->Recording() || (d->Recording() && d->Priority() > dvbApi[i]->Priority()))
+               d = dvbApi[i];
+            if (d && d != PrimaryDvbApi && !d->Recording()) // avoids the PrimaryDvbApi if possible
                break;
             }
          }
       }
-  return d;
+  return (d && (!d->Recording() || d->Priority() < Priority || (!d->Ca() && Ca))) ? d : NULL;
 }
 
 int cDvbApi::Index(void)
@@ -1746,7 +1751,7 @@ bool cDvbApi::Replaying(void)
   return pidReplay;
 }
 
-bool cDvbApi::StartRecord(const char *FileName)
+bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority)
 {
   if (Recording()) {
      esyslog(LOG_ERR, "ERROR: StartRecord() called while recording - ignored!");
@@ -1843,6 +1848,9 @@ bool cDvbApi::StartRecord(const char *FileName)
 
      fromRecord = fromRecordPipe[0];
      toRecord = toRecordPipe[1];
+
+     ca = Ca;
+     priority = Priority;
      return true;
      }
   return false;
@@ -1857,6 +1865,8 @@ void cDvbApi::StopRecord(void)
      toRecord = fromRecord = -1;
      KillProcess(pidRecord);
      pidRecord = 0;
+     ca = 0;
+     priority = -1;
      SetReplayMode(VID_PLAY_RESET); //XXX
      }
 }
diff --git a/dvbapi.h b/dvbapi.h
index aa8dbcf3..7e237379 100644
--- a/dvbapi.h
+++ b/dvbapi.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbapi.h 1.22 2000/11/05 13:39:31 kls Exp $
+ * $Id: dvbapi.h 1.23 2000/11/12 12:52:41 kls Exp $
  */
 
 #ifndef __DVBAPI_H
@@ -59,11 +59,15 @@ public:
   static bool SetPrimaryDvbApi(int n);
          // Sets the primary DVB device to 'n' (which must be in the range
          // 1...NumDvbApis) and returns true if this was possible.
-  static cDvbApi *GetDvbApi(int Ca = 0);
+  static cDvbApi *GetDvbApi(int Ca, int Priority);
          // Selects a free DVB device, starting with the highest device number
          // (but avoiding, if possible, the PrimaryDvbApi).
-         // If Ca is not 0, the device with the given number will be returned
-         // if it is not currently recording.
+         // If Ca is not 0, the device with the given number will be returned.
+         // If all DVB devices are currently recording, the one recording the
+         // lowest priority timer (if any) that is lower than the given Priority
+         // will be returned.
+         // The caller must check whether the returned DVB device is actually
+         // recording and stop recording if necessary.
   int Index(void);
          // Returns the index of this DvbApi.
   static bool Init(void);
@@ -158,14 +162,23 @@ private:
   pid_t pidRecord, pidReplay;
   int fromRecord, toRecord;
   int fromReplay, toReplay;
+  int ca;
+  int priority;
   void SetReplayMode(int Mode);
+protected:
+  int  Ca(void) { return ca; }
+       // Returns the ca of the current recording session (0..MAXDVBAPI).
+  int  Priority(void) { return priority; }
+       // Returns the priority of the current recording session (0..99),
+       // or -1 if no recording is currently active.
 public:
   bool Recording(void);
        // Returns true if we are currently recording.
   bool Replaying(void);
        // Returns true if we are currently replaying.
-  bool StartRecord(const char *FileName);
-       // Starts recording the current channel into the given file.
+  bool StartRecord(const char *FileName, int Ca, int Priority);
+       // Starts recording the current channel into the given file, with
+       // the given ca and priority.
        // In order to be able to record longer movies,
        // a numerical suffix will be appended to the file name. The inital
        // value of that suffix will be larger than any existing file under
diff --git a/menu.c b/menu.c
index c9959a4f..92e715e2 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: menu.c 1.46 2000/11/11 15:22:56 kls Exp $
+ * $Id: menu.c 1.47 2000/11/12 13:03:35 kls Exp $
  */
 
 #include "menu.h"
@@ -1817,7 +1817,7 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer)
   timer->SetRecording(true);
   Channels.SwitchTo(timer->channel, dvbApi);
   cRecording Recording(timer);
-  if (dvbApi->StartRecord(Recording.FileName()))
+  if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority))
      Recording.WriteSummary();
   Interface->DisplayRecording(dvbApi->Index(), true);
 }
@@ -1863,8 +1863,9 @@ bool cRecordControls::Start(cTimer *Timer)
   cChannel *channel = Channels.GetByNumber(ch);
 
   if (channel) {
-     cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca);
+     cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca, Timer ? Timer->priority : DEFAULTPRIORITY);
      if (dvbApi) {
+        Stop(dvbApi);
         for (int i = 0; i < MAXDVBAPI; i++) {
             if (!RecordControls[i]) {
                RecordControls[i] = new cRecordControl(dvbApi, Timer);
@@ -1891,6 +1892,18 @@ void cRecordControls::Stop(const char *InstantId)
       }
 }
 
+void cRecordControls::Stop(cDvbApi *DvbApi)
+{
+  for (int i = 0; i < MAXDVBAPI; i++) {
+      if (RecordControls[i]) {
+         if (RecordControls[i]->Uses(DvbApi)) {
+            isyslog(LOG_INFO, "stopping recording on DVB device %d due to higher priority", DvbApi->Index() + 1);
+            RecordControls[i]->Stop();
+            }
+         }
+      }
+}
+
 const char *cRecordControls::GetInstantId(const char *LastInstantId)
 {
   for (int i = 0; i < MAXDVBAPI; i++) {
diff --git a/menu.h b/menu.h
index d979069e..8153f5d7 100644
--- a/menu.h
+++ b/menu.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: menu.h 1.13 2000/11/01 14:03:09 kls Exp $
+ * $Id: menu.h 1.14 2000/11/12 12:33:00 kls Exp $
  */
 
 #ifndef _MENU_H
@@ -59,6 +59,7 @@ public:
   cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL);
   virtual ~cRecordControl();
   bool Process(void);
+  bool Uses(cDvbApi *DvbApi) { return DvbApi == dvbApi; }
   void Stop(bool KeepInstant = false);
   bool IsInstant(void) { return instantId; }
   const char *InstantId(void) { return instantId; }
@@ -70,6 +71,7 @@ private:
 public:
   static bool Start(cTimer *Timer = NULL);
   static void Stop(const char *InstantId);
+  static void Stop(cDvbApi *DvbApi);
   static const char *GetInstantId(const char *LastInstantId);
   static void Process(void);
   };
-- 
cgit v1.2.3