[mythtv] [PATCH] Beginning radio pvr support

Dan Sheridan djs52 at postman.org.uk
Sat Jan 10 13:22:02 EST 2004


This is a very hacky first attempt (which doesn't work!) at radio
support within mythtv. I am aiming to support radio as another input:
channels can be selected and recorded as if they were TV channels. I
have tuning and input selection sorted out, using an extra column in
the cardinput table to indicate a radio input (though the device name
should probably be in the capturecard table).

My problems are:

o  Notifying the various threads that the current stream is
   audio-only. At the moment I have a call to a function in
   ChannelBase, but this feels messy.

o  NuppelVideoRecorder, when setting up, can select a channel. I think
   for symmetry that it should use the Channel class instead of
   calling the ioctl itself -- is there any reason why it doesn't at
   the moment?

o  I need to stop the video thread while allowing the audio thread to
   continue. You can see my failed attempt below. Any ideas on how I 
   should be going about this? 

When backend support is complete, I'd like to modify the frontend to
simply keep all of the OSDs switch on, with a black bacground, when a
stream without video is played. 

       Dan.

-- 
Dan Sheridan -- Research Student -- LFCS, Division of Informatics
 University of Edinburgh, King's Buildings, Mayfield Road EH9 3JZ


Index: mythtv/libs/libmythtv/NuppelVideoRecorder.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/NuppelVideoRecorder.cpp,v
retrieving revision 1.152
diff -u -r1.152 NuppelVideoRecorder.cpp
--- mythtv/libs/libmythtv/NuppelVideoRecorder.cpp	7 Jan 2004 06:14:04 -0000	1.152
+++ mythtv/libs/libmythtv/NuppelVideoRecorder.cpp	10 Jan 2004 18:11:05 -0000
@@ -366,6 +366,7 @@
 
 void NuppelVideoRecorder::Unpause(void)
 {
+    isradio = channelObj->GetCurrentInputRadio();
     pausewritethread = false;
     paused = false;
 }
@@ -1027,6 +1028,13 @@
                gettimeofday(&stm, &tzone);
            continue;
         }
+        if (isradio)
+        {
+           usleep(500);
+           if (cleartimeonpause)
+               gettimeofday(&stm, &tzone);
+           continue;
+        }
 
         frame = 0;
         mm.frame = 0;
@@ -2433,7 +2441,7 @@
         } action = ACTION_NONE;
         int firsttimecode = -1;
 
-        if (videobuffer[act_video_encode]->freeToEncode)
+        if (!isradio && videobuffer[act_video_encode]->freeToEncode)
         {
             action = ACTION_VIDEO;
             firsttimecode = videobuffer[act_video_encode]->timecode;
Index: mythtv/libs/libmythtv/NuppelVideoRecorder.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/NuppelVideoRecorder.h,v
retrieving revision 1.66
diff -u -r1.66 NuppelVideoRecorder.h
--- mythtv/libs/libmythtv/NuppelVideoRecorder.h	7 Jan 2004 06:14:04 -0000	1.66
+++ mythtv/libs/libmythtv/NuppelVideoRecorder.h	10 Jan 2004 18:11:05 -0000
@@ -262,6 +262,8 @@
     ChannelBase *channelObj;
 
     bool setorigaudio;
+
+    bool isradio;
 };
 
 #endif
Index: mythtv/libs/libmythtv/channel.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/channel.cpp,v
retrieving revision 1.60
diff -u -r1.60 channel.cpp
--- mythtv/libs/libmythtv/channel.cpp	9 Jan 2004 21:02:12 -0000	1.60
+++ mythtv/libs/libmythtv/channel.cpp	10 Jan 2004 18:11:05 -0000
@@ -22,6 +22,7 @@
 {
     device = videodevice;
     isopen = false;
+    isradio = false;
     videofd = -1;
     curList = 0;
     defaultFreqTable = 1;
@@ -117,11 +118,26 @@
             inputChannel[vin.index] = "";
             inputTuneTo[vin.index] = "";
             externalChanger[vin.index] = "";
+            inputRadio[vin.index] = "";
             vin.index++;
 
             capchannels = vin.index;
         }
 
+	// if there is a radio on this card
+	{
+	    QString msg = QString("Probed: %1 - Radio").arg(device);
+            VERBOSE(VB_CHANNEL, msg);
+            channelnames[vin.index] = "Radio";
+            inputChannel[vin.index] = "";
+            inputTuneTo[vin.index] = "";
+            externalChanger[vin.index] = "";
+            inputRadio[vin.index] = ""; // Will be filled in later
+            vin.index++;
+
+            capchannels = vin.index;
+	}
+
         if (fmt == "NTSC")
             videomode = V4L2_STD_NTSC;
         else if (fmt == "ATSC")
@@ -140,7 +156,7 @@
             videomode = V4L2_STD_NTSC_M_JP;
 
         pParent->RetrieveInputChannels(inputChannel, inputTuneTo, 
-                                       externalChanger);
+                                       externalChanger, inputRadio);
         return;
     }
  
@@ -189,8 +205,20 @@
         inputChannel[i] = "";
         inputTuneTo[i] = "";
         externalChanger[i] = "";
+        inputRadio[i] = "";
     }
 
+    // if there is a radio on this card
+    {
+        QString msg = QString("Probed: %1 - Radio").arg(device);
+        VERBOSE(VB_CHANNEL, msg);
+        channelnames[capchannels] = "Radio";
+        inputChannel[capchannels] = "";
+        inputTuneTo[capchannels] = "";
+        externalChanger[capchannels] = "";
+        inputRadio[capchannels] = ""; // Will be filled in later
+        capchannels++;
+    }
     struct video_channel vc;
     memset(&vc, 0, sizeof(vc));
     ioctl(videofd, VIDIOCGCHAN, &vc);
@@ -199,7 +227,7 @@
 
     videomode = mode;
 
-    pParent->RetrieveInputChannels(inputChannel, inputTuneTo, externalChanger);
+    pParent->RetrieveInputChannels(inputChannel, inputTuneTo, externalChanger, inputRadio);
 }
 
 int Channel::SetDefaultFreqTable(const QString &name)
@@ -254,6 +282,11 @@
     return -1;
 }
 
+bool Channel::GetCurrentInputRadio(void)
+{
+  return isradio;
+}
+
 bool Channel::ChannelUp(void)
 {
     if (ChannelBase::ChannelUp())
@@ -369,6 +402,7 @@
     // Tune
     if (externalChanger[currentcapchannel].isEmpty())
     {
+        cerr << "Requesting " << freqid << "\n";
         if (!TuneTo(freqid, finetune))
             return false;
     }
@@ -392,18 +426,29 @@
 
 bool Channel::TuneTo(const QString &channum, int finetune)
 {
-    int i = GetCurrentChannelNum(channum);
-    if (i == -1)
-        return false;
-
-    int frequency = curList[i].freq * 16 / 1000 + finetune;
+    int frequency;
+    if (isradio)
+    {
+        frequency = channum.toInt() * 16;
+	cerr << "Tuning to " << frequency << "\n";
+    }
+    else
+    {
+	int i = GetCurrentChannelNum(channum);
+	if (i == -1)
+	    return false;
+        frequency = curList[i].freq * 16 / 1000 + finetune;
+    }
 
     if (usingv4l2)
     {
         struct v4l2_frequency vf;
         memset(&vf, 0, sizeof(vf));
         vf.frequency = frequency;
-        vf.type = V4L2_TUNER_ANALOG_TV;
+	if (isradio)
+	    vf.type = V4L2_TUNER_RADIO;
+        else
+            vf.type = V4L2_TUNER_ANALOG_TV;
 
         if (ioctl(videofd, VIDIOC_S_FREQUENCY, &vf) < 0)
         {
@@ -424,23 +469,53 @@
 
 void Channel::SwitchToInput(int newcapchannel, bool setstarting)
 {
-    if (usingv4l2)
+    if (!inputRadio[newcapchannel].isEmpty())
     {
-        if (ioctl(videofd, VIDIOC_S_INPUT, &newcapchannel) < 0)
-            perror("VIDIOC_S_INPUT");
-   
-        if (ioctl(videofd, VIDIOC_S_STD, &videomode) < 0)
-            perror("VIDIOC_S_STD");
+        close(videofd);
+        videofd = open(inputRadio[newcapchannel].ascii(), O_RDWR);
+        if (videofd > 0)
+            isradio = true;
+        else
+        {
+            cerr << "Channel::SwitchToInput(): Can't open: " << inputRadio[newcapchannel] << endl;
+            perror(inputRadio[newcapchannel].ascii());
+            return;
+        }
+    } else 
+    if (isradio)
+    {
+        close(videofd);
+	videofd = open(device.ascii(), O_RDWR);
+        if (videofd > 0)
+            isradio = false;
+        else
+        {
+             cerr << "Channel::SwitchToInput(): Can't open: " << device << endl;
+             perror(device.ascii());
+             return;
+        }
     }
-    else
+
+    if (!isradio)
     {
-        struct video_channel set;
-        memset(&set, 0, sizeof(set));
-        ioctl(videofd, VIDIOCGCHAN, &set);
-        set.channel = newcapchannel;
-        set.norm = videomode;
-        if (ioctl(videofd, VIDIOCSCHAN, &set) < 0)
-           perror("VIDIOCSCHAN");
+        if (usingv4l2)
+        {
+            if (ioctl(videofd, VIDIOC_S_INPUT, &newcapchannel) < 0)
+                perror("VIDIOC_S_INPUT");
+   
+            if (ioctl(videofd, VIDIOC_S_STD, &videomode) < 0)
+                perror("VIDIOC_S_STD");
+        }
+        else
+        {
+            struct video_channel set;
+            memset(&set, 0, sizeof(set));
+            ioctl(videofd, VIDIOCGCHAN, &set);
+            set.channel = newcapchannel;
+            set.norm = videomode;
+            if (ioctl(videofd, VIDIOCSCHAN, &set) < 0)
+               perror("VIDIOCSCHAN");
+        }
     }
 
     currentcapchannel = newcapchannel;
@@ -476,6 +551,9 @@
     QString field_name = name;
     int field = pParent->GetChannelValue(field_name, this, curchannelname);
 
+    if (isradio)
+        return;
+
     if (usingv4l2)
     {
         struct v4l2_control ctrl;
Index: mythtv/libs/libmythtv/channel.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/channel.h,v
retrieving revision 1.26
diff -u -r1.26 channel.h
--- mythtv/libs/libmythtv/channel.h	9 Jan 2004 21:02:12 -0000	1.26
+++ mythtv/libs/libmythtv/channel.h	10 Jan 2004 18:11:05 -0000
@@ -41,8 +41,9 @@
     void SetHue();
 
     void SwitchToInput(int newcapchannel, bool setstarting);
-
+    
     void SetFd(int fd); 
+    bool GetCurrentInputRadio(void);
 
   private:
     int GetCurrentChannelNum(const QString &channame);
@@ -53,6 +54,7 @@
 
     QString device;
     bool isopen;  
+    bool isradio;  
     int videofd;
 
     struct CHANLIST *curList;  
Index: mythtv/libs/libmythtv/channelbase.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/channelbase.cpp,v
retrieving revision 1.6
diff -u -r1.6 channelbase.cpp
--- mythtv/libs/libmythtv/channelbase.cpp	12 Sep 2003 16:49:53 -0000	1.6
+++ mythtv/libs/libmythtv/channelbase.cpp	10 Jan 2004 18:11:05 -0000
@@ -70,6 +70,11 @@
     return currentcapchannel;
 }
 
+bool ChannelBase::GetCurrentInputRadio(void)
+{
+  return false;
+}
+
 void ChannelBase::ToggleInputs(void)
 {
     int newcapchannel = currentcapchannel;
Index: mythtv/libs/libmythtv/channelbase.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/channelbase.h,v
retrieving revision 1.3
diff -u -r1.3 channelbase.h
--- mythtv/libs/libmythtv/channelbase.h	7 Aug 2003 17:37:41 -0000	1.3
+++ mythtv/libs/libmythtv/channelbase.h	10 Jan 2004 18:11:05 -0000
@@ -55,6 +55,7 @@
     virtual QString GetCurrentInput(void);
 
     virtual int GetCurrentInputNum(void);
+    virtual bool GetCurrentInputRadio(void);
 
     virtual void SetFd(int fd) { (void)fd; }
 
@@ -69,6 +70,7 @@
     map<int, QString> inputChannel;
     map<int, QString> inputTuneTo;
     map<int, QString> externalChanger;
+    map<int, QString> inputRadio;
     // returns index of channame (channel.channum) in curList
 
     QString channelorder;
Index: mythtv/libs/libmythtv/tv_rec.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/tv_rec.cpp,v
retrieving revision 1.126
diff -u -r1.126 tv_rec.cpp
--- mythtv/libs/libmythtv/tv_rec.cpp	9 Jan 2004 21:02:13 -0000	1.126
+++ mythtv/libs/libmythtv/tv_rec.cpp	10 Jan 2004 18:11:06 -0000
@@ -2072,14 +2072,16 @@
 
 void TVRec::RetrieveInputChannels(map<int, QString> &inputChannel,
                                   map<int, QString> &inputTuneTo,
-                                  map<int, QString> &externalChanger)
+                                  map<int, QString> &externalChanger,
+                                  map<int, QString> &inputRadio)
 {
     pthread_mutex_lock(&db_lock);
     MythContext::KickDatabase(db_conn);
 
     QString query = QString("SELECT inputname, trim(externalcommand), "
                             "if(tunechan='', 'Undefined', tunechan), "
-                            "if(startchan, startchan, '') "
+                            "if(startchan, startchan, ''), "
+                            "radiodevice "
                             "FROM capturecard, cardinput "
                             "WHERE capturecard.cardid = %1 "
                             "AND capturecard.cardid = cardinput.cardid;")
@@ -2104,6 +2106,7 @@
             externalChanger[cap] = result.value(1).toString();
             inputTuneTo[cap] = result.value(2).toString();
             inputChannel[cap] = result.value(3).toString();
+            inputRadio[cap] = result.value(4).toString();
         }
     }
 
Index: mythtv/libs/libmythtv/tv_rec.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/tv_rec.h,v
retrieving revision 1.47
diff -u -r1.47 tv_rec.h
--- mythtv/libs/libmythtv/tv_rec.h	30 Dec 2003 07:05:23 -0000	1.47
+++ mythtv/libs/libmythtv/tv_rec.h	10 Jan 2004 18:11:06 -0000
@@ -75,7 +75,8 @@
 
     void RetrieveInputChannels(map<int, QString> &inputChannel,
                                map<int, QString> &inputTuneTo,
-                               map<int, QString> &externalChanger);
+                               map<int, QString> &externalChanger,
+                               map<int, QString> &inputRadio);
     void StoreInputChannels(map<int, QString> &inputChannel);
 
     bool IsBusy(void);



More information about the mythtv-dev mailing list