[mythtv] DVB channel flipping hang

Mark Weaver mark-clist at npsl.co.uk
Thu Aug 25 00:34:12 UTC 2005


> Is it a reasonable solution just to do the ioctl and enter a select() 
> loop at that point, with a timeout?  I can see that the fd is used 
> elsewhere (via GetFd()) but only FE_SET_FRONTEND appears to use 
> FE_GET_EVENT according to the API docs, so it would seem ok.  I have no 
> idea what the actual code flow is so I could be missing something.
> 
> I'll probably give it a go and see what happens, it doesn't seem like 
> too much work!
> 
This does seem to help, I've done 10 minutes of channel flipping with no 
issues.  The attached patch is what I used, would be good if someone 
else could give it a whirl.

Thanks,

Mark
-------------- next part --------------
Index: dvbchannel.cpp
===================================================================
--- dvbchannel.cpp	(revision 7121)
+++ dvbchannel.cpp	(working copy)
@@ -666,11 +666,8 @@
         prev_tuning.params.u.qpsk.symbol_rate != tuning.params.u.qpsk.symbol_rate ||
         prev_tuning.params.u.qpsk.fec_inner   != tuning.params.u.qpsk.fec_inner)
     {
-        if (ioctl(fd_frontend, FE_SET_FRONTEND, &tuning.params) < 0)
-        {
-            ERRNO("Setting Frontend failed.");
-            return false;
-        }
+        if (!SetFrontEnd(tuning))
+	    return false;
 
         prev_tuning.params.frequency = tuning.params.frequency;
         prev_tuning.params.inversion = tuning.params.inversion;
@@ -691,11 +688,9 @@
         prev_tuning.params.frequency != tuning.params.frequency ||
         prev_tuning.params.u.vsb.modulation != tuning.params.u.vsb.modulation)
     {
-        if (ioctl(fd_frontend, FE_SET_FRONTEND, &tuning.params) < 0)
-        {
-            ERRNO("Setting Frontend failed.");
-            return false;
-        }
+        if (!SetFrontEnd(tuning))
+	    return false;
+
         prev_tuning.params.frequency = tuning.params.frequency;
         prev_tuning.params.u.vsb.modulation  = tuning.params.u.vsb.modulation;
         havetuned = true;
@@ -717,11 +712,8 @@
         prev_tuning.params.u.qam.fec_inner   != tuning.params.u.qam.fec_inner   ||
         prev_tuning.params.u.qam.modulation  != tuning.params.u.qam.modulation)
     {
-        if (ioctl(fd_frontend, FE_SET_FRONTEND, &tuning.params) < 0)
-        {
-            ERRNO("Setting Frontend failed.");
-            return false;
-        }
+        if (!SetFrontEnd(tuning))
+	    return false;
 
         prev_tuning.params.frequency = tuning.params.frequency;
         prev_tuning.params.inversion = tuning.params.inversion;
@@ -747,11 +739,8 @@
         prev_tuning.params.u.ofdm.guard_interval != tuning.params.u.ofdm.guard_interval ||
         prev_tuning.params.u.ofdm.hierarchy_information != tuning.params.u.ofdm.hierarchy_information)
     {
-        if (ioctl(fd_frontend, FE_SET_FRONTEND, &tuning.params) < 0)
-        {
-            ERRNO("Setting Frontend failed.");
-            return false;
-        }
+        if (!SetFrontEnd(tuning))
+	    return false;
 
         prev_tuning.params.frequency = tuning.params.frequency;
         prev_tuning.params.inversion = tuning.params.inversion;
@@ -811,6 +800,74 @@
     return query.value(0).toInt();
 }
 
+/** \fn DVBChannel::SetFrontEnd(DVBTuning &tuning)
+ *  \brief Set the frontend tuning parameters
+ */
+bool DVBChannel::SetFrontEnd(DVBTuning &tuning)
+{
+    if (ioctl(fd_frontend, FE_SET_FRONTEND, &tuning.params) < 0)
+    {
+	ERRNO("Setting Frontend failed.");
+	return false;
+    }
+
+    struct pollfd pfd[1];
+    pfd[0].fd = fd_frontend;
+    pfd[0].events = POLLPRI | POLLIN;
+
+    struct dvb_frontend_event event;
+    event.status = (fe_status_t)0;
+
+    int timeouts = 0;
+    while ( timeouts < 10 &&
+	    (event.status & FE_TIMEDOUT) == 0 && 
+	    (event.status & FE_HAS_LOCK) == 0 )
+    {
+	int status = poll(pfd, 1, 1000);
+	if (status < 0)
+	{
+	    ERRNO("poll failed.");
+	    return false;
+	}
+	else if (status == 0)
+	{
+	    ++timeouts;
+	}
+	else
+	{
+	    status = ioctl(fd_frontend, FE_GET_EVENT, &event);
+	    if (status < 0)
+	    {
+		if (errno == EOVERFLOW)
+		{
+		    CHANNEL("Overflow polling frontend events, continuing");
+		}
+		else
+	        {
+		    ERRNO("FE_GET_EVENT failed");
+		    return false;
+		}
+	    }
+	}
+    }
+
+    if (event.status & FE_HAS_LOCK)
+    {
+	CHANNEL("FE_HAS_LOCK after setting Frontend");
+	return true;
+    }
+
+    if (event.status & FE_TIMEDOUT)
+    {
+	CHANNEL("FE_TIMEDOUT setting frontend parameters");
+    }
+    else
+    {
+	CHANNEL("FE_SET_FRONTEND did not respond after 10s");
+    }
+    return false;
+}
+
 void DVBChannel::SaveCachedPids(const pid_cache_t &pid_cache) const
 {
     int chanid = GetChanID();
Index: dvbchannel.h
===================================================================
--- dvbchannel.h	(revision 7121)
+++ dvbchannel.h	(working copy)
@@ -85,6 +85,7 @@
     int  GetChanID(void) const;
     bool GetTransportOptions(int mplexid);
     bool GetChannelOptions(const QString &channum);
+    bool SetFrontEnd(DVBTuning &tuning);
 
     void CheckOptions();
     bool CheckModulation(fe_modulation_t modulation) const;


More information about the mythtv-dev mailing list