Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[vdr] [PATCH] Possible fix for EPG scan ("video data stream broken")



Hi,

while debugging I noticed that when starting a recording while EPG 
scan is active the following piece of code in method 
cDvbDevice::SetChannelDevice prevents starting transfer mode (at 
least on a single card system):

   if (EITScanner.Active()) {
      StartTransferMode = false;
      TurnOnLivePIDs = false;
      }

I think this causes the recording thread not receiving data for some 
time (20sec ScanTimeout for EITScanner + some time for several 
Channel switches incl. displaying "Channel not available"). This 
amount of time can quite reach the timeout of 30sec in the recording 
thread.

As workaround I inserted a call of EITScanner.Activity()  in 
cRecordControls::Start in before SwitchChannel is called.

In method  cEITScanner::Activity I rearranged the assignments for 
currentChannel and lastActivity. So EITScanner::Active immediatly 
returns false.

Furthermore I made a small optimization at the beginning 
cEITScanner::Process for single card setups. This prevents building 
and deleting the scanlist every 20 secs when EPGScanTimeout is not 
reached.

I will have to test this patch over night but up to then comments a 
welcome. This patch contains also the cDvbTuner patch (timeout now 
300ms) and some debugging messages.

Stefan



diff -Nru vdr-1.3.12/dvbdevice.c vdr-1.3.12-patched/dvbdevice.c
--- vdr-1.3.12/dvbdevice.c	2004-06-19 11:33:42.000000000 +0200
+++ vdr-1.3.12-patched/dvbdevice.c	2004-07-31 16:42:13.705232395 +0200
@@ -35,7 +35,6 @@
 
 #define DO_REC_AND_PLAY_ON_PRIMARY_DEVICE 1
 #define DO_MULTIPLE_RECORDINGS 1
-//#define WAIT_FOR_LOCK_AFTER_TUNING 1
 
 #define DEV_VIDEO         "/dev/video"
 #define DEV_DVB_ADAPTER   "/dev/dvb/adapter"
@@ -80,6 +79,7 @@
   eTunerStatus tunerStatus;
   cMutex mutex;
   cCondVar newSet;
+  cCondVar evLocked;
   bool SetFrontend(void);
   virtual void Action(void);
 public:
@@ -132,6 +132,8 @@
      startTime = time(NULL);
   channel = *Channel;
   newSet.Broadcast();
+  if (tunerStatus < tsLocked)
+    evLocked.TimedWait(mutex, 6000);
 }
 
 static unsigned int FrequencyToHz(unsigned int f)
@@ -241,6 +243,15 @@
          esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
          return false;
     }
+  
+  /* discard stale events */
+  dvb_frontend_event event;
+  while (1)
+  {
+    if (ioctl(fd_frontend, FE_GET_EVENT, &event) == -1)
+      break;
+  }
+  
   if (ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend) < 0) {
      esyslog("ERROR: frontend %d: %m", cardIndex);
      return false;
@@ -248,6 +259,7 @@
   return true;
 }
 
+
 void cDvbTuner::Action(void)
 {
   active = true;
@@ -256,19 +268,28 @@
         if (tunerStatus == tsSet)
            tunerStatus = SetFrontend() ? tsTuned : tsIdle;
         if (tunerStatus == tsTuned) {
-           fe_status_t status = fe_status_t(0);
-           CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status));
-           if (status & FE_HAS_LOCK)
-              tunerStatus = tsLocked;
+           pollfd pfd;
+           pfd.fd = fd_frontend;
+           pfd.events = POLLIN | POLLPRI;
+           int rc = poll(&pfd, 1, 5000);
+           if (rc == 0)
+              isyslog("WARNING: frontend %d poll timed out!", cardIndex + 1);
+           else if (rc == -1)
+              esyslog("ERROR: frontend %d poll failed - errno %d!", cardIndex + 1, errno);
            }
         if (tunerStatus != tsIdle) {
            dvb_frontend_event event;
-           if (ioctl(fd_frontend, FE_GET_EVENT, &event) == 0) {
+           while (ioctl(fd_frontend, FE_GET_EVENT, &event) == 0) {
               if (event.status & FE_REINIT) {
                  tunerStatus = tsSet;
-                 esyslog("ERROR: frontend %d was reinitialized - re-tuning", cardIndex);
+                 esyslog("ERROR: frontend %d was reinitialized - re-tuning", cardIndex + 1);
                  continue;
                  }
+              if ((tunerStatus == tsTuned) && (event.status & FE_HAS_LOCK)) {
+                 usleep(300*1000);
+                 tunerStatus = tsLocked;
+                 evLocked.Broadcast();
+                 }
               }
            }
         if (ciHandler) {
@@ -293,7 +314,8 @@
               tunerStatus = tsLocked;
            }
         // in the beginning we loop more often to let the CAM connection start up fast
-        newSet.TimedWait(mutex, (ciHandler && (time(NULL) - startTime < 20)) ? 100 : 1000);
+        if (tunerStatus != tsTuned)
+           newSet.TimedWait(mutex, (ciHandler && (time(NULL) - startTime < 20)) ? 100 : 1000);
         }
 }
 
@@ -709,6 +731,8 @@
 
 bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 {
+  dsyslog("SetChannelDevice: Channel %s, LiveView %s", Channel->Name(), LiveView ? "true" : "false");
+  
   bool IsEncrypted = Channel->Ca() > CACONFBASE && !ciHandler; // only LL-firmware can do non-live CA channels
 
   bool DoTune = !dvbTuner->IsTunedTo(Channel);
@@ -738,6 +762,7 @@
 
   // XXX 1.3: use the same mechanism as below (!EITScanner.UsesDevice(this))
   if (EITScanner.Active()) {
+     dsyslog("EITScanner is active");
      StartTransferMode = false;
      TurnOnLivePIDs = false;
      }
@@ -748,13 +773,12 @@
      TurnOffLiveMode();
 
   dvbTuner->Set(Channel, DoTune, !EITScanner.UsesDevice(this)); //XXX 1.3: this is an ugly hack - find a cleaner solution//XXX
-
-#ifdef WAIT_FOR_LOCK_AFTER_TUNING
-  //XXX TODO preliminary fix for the "Unknown picture type" error
-  time_t t0 = time(NULL);
-  while (!dvbTuner->Locked() && time(NULL) - t0 < 5)
-        usleep(100);
-#endif
+  
+  if (!dvbTuner->Locked()) {
+     esyslog("ERROR: failed to tune to channel %d \"%s\"", Channel->Number(), Channel->Name());
+     return false;
+     }
+  
   // PID settings:
 
   if (TurnOnLivePIDs) {
diff -Nru vdr-1.3.12/eitscan.c vdr-1.3.12-patched/eitscan.c
--- vdr-1.3.12/eitscan.c	2004-04-16 15:33:34.000000000 +0200
+++ vdr-1.3.12-patched/eitscan.c	2004-07-31 16:41:03.044258645 +0200
@@ -114,20 +114,26 @@
 
 void cEITScanner::Activity(void)
 {
+  dsyslog("cEITScanner::Activity called");
+  lastActivity = time(NULL);
   if (currentChannel) {
-     Channels.SwitchTo(currentChannel);
+     int Channel = currentChannel;
      currentChannel = 0;
+     Channels.SwitchTo(Channel);
      }
-  lastActivity = time(NULL);
 }
 
 void cEITScanner::Process(void)
 {
+  time_t now = time(NULL);
+  if (!scanList && lastActivity && cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity < Setup.EPGScanTimeout * 3600)
+     return;
   if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
-     time_t now = time(NULL);
      if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
+        dsyslog("cEITScanner::Process: start processing");
         if (Channels.Lock(false, 10)) {
            if (!scanList) {
+              dsyslog("cEITScanner::Process: create new scanlist");
               scanList = new cScanList;
               scanList->AddTransponders(&Channels);
               if (transponderList) {
@@ -136,6 +142,7 @@
                  transponderList = NULL;
                  }
               }
+           dsyslog("cEITScanner::Process: scanlist contains %d entries", scanList->Count());
            for (bool AnyDeviceSwitched = false; !AnyDeviceSwitched; ) {
                cScanData *ScanData = NULL;
                for (int i = 0; i < cDevice::NumDevices(); i++) {
@@ -171,6 +178,7 @@
                   ScanData = NULL;
                   }
                if (!scanList->Count()) {
+                  dsyslog("cEITScanner::Process: scanlist is now empty");
                   delete scanList;
                   scanList = NULL;
                   if (lastActivity == 0) // this was a triggered scan
diff -Nru vdr-1.3.12/menu.c vdr-1.3.12-patched/menu.c
--- vdr-1.3.12/menu.c	2004-06-13 22:26:51.000000000 +0200
+++ vdr-1.3.12-patched/menu.c	2004-07-31 15:46:25.110509999 +0200
@@ -2861,6 +2861,7 @@
            if (device == cTransferControl::ReceiverDevice())
               cControl::Shutdown(); // in case this device was used for Transfer Mode
            }
+        EITScanner.Activity();
         dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number());
         if (!device->SwitchChannel(channel, false)) {
            cThread::EmergencyExit(true);

Home | Main Index | Thread Index