[mythtv] [PATCH] External TV programs in MythTV (tvtime)

John Hurliman jhurliman at focustheater.com
Wed Aug 6 22:15:26 EDT 2003


This adds support for an EXECTV command in the xml menu files. MythTV 
will lock the first locally available tuner and return the device 
name(s) for it. After the command has finished the tuner will be 
unlocked and Myth has access to it again.

Usage:

<action>EXECTV command %s %s %s</action>

All of the %s are optional; the first one returns the videodevice (ex. 
/dev/video0), the second is the dsp device (ex. /dev/dsp) and the third 
is the vbi device (ex. /dev/vbi0). A command might be:

xawtv -f -device %s -dspdev %s -vbidev %s

or

tvtime m -D %s

Any recordings that are attempted when all tuners are locked will be 
suppressed.

jph
-------------- next part --------------
Index: libs/libmyth/themedmenu.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmyth/themedmenu.cpp,v
retrieving revision 1.49
diff -u -r1.49 themedmenu.cpp
--- libs/libmyth/themedmenu.cpp	11 Jul 2003 20:28:10 -0000	1.49
+++ libs/libmyth/themedmenu.cpp	7 Aug 2003 04:02:15 -0000
@@ -19,6 +19,7 @@
 #include "mythcontext.h"
 #include "util.h"
 #include "mythplugin.h"
+#include "dialogbox.h"
 
 ThemedMenu::ThemedMenu(const char *cdir, const char *menufile, 
                        MythMainWindow *parent, const char *name)
@@ -1692,6 +1693,41 @@
     {
         QString rest = action.right(action.length() - 5);
         system(rest);
+    }
+    else if (action.left(7) == "EXECTV ")
+    {
+        QString rest = action.right(action.length() - 7).stripWhiteSpace();
+        QStringList strlist = QString("LOCK_TUNER");
+        gContext->SendReceiveStringList(strlist);
+        int cardid = strlist[0].toInt();
+
+        if (cardid >= 0)
+        {
+            cout << "themedmenu.o: Locked device id " << cardid << endl;
+
+            rest = rest.sprintf(rest, (const char*)strlist[1], (const char*)strlist[2], (const char*)strlist[3]);
+            cout << "themedmenu.o: rest == " << rest << endl;
+
+            system(rest);
+
+            strlist = QString("FREE_TUNER %1").arg(cardid);
+            gContext->SendReceiveStringList(strlist);
+            QString ret = strlist[0];
+            cout << "themedmenu.o: Unlocking tuner: " << ret << endl;
+        }
+        else
+        {
+            if (cardid == -2)
+                cerr << "themedmenu.o: Tuner already locked" << endl;
+            
+            DialogBox *error_dialog = new DialogBox(gContext->GetMainWindow(),
+                     "\n\nAll tuners are currently in use. If you want to watch "
+                     "TV, you can cancel one of the in-progress recordings from "
+                     "the delete menu");
+            error_dialog->AddButton("OK");
+            error_dialog->exec();
+            delete error_dialog;
+        }
     }
     else if (action.left(5) == "MENU ")
     {
Index: programs/mythbackend/encoderlink.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/programs/mythbackend/encoderlink.cpp,v
retrieving revision 1.22
diff -u -r1.22 encoderlink.cpp
--- programs/mythbackend/encoderlink.cpp	26 Jul 2003 16:49:17 -0000	1.22
+++ programs/mythbackend/encoderlink.cpp	7 Aug 2003 04:02:15 -0000
@@ -20,6 +20,7 @@
     hostname = lhostname;
     tv = NULL;
     local = false;
+    locked = false;
     m_capturecardnum = capturecardnum;
 
     endRecordingTime = QDateTime::currentDateTime().addDays(-2);
@@ -32,6 +33,7 @@
     sock = NULL;
     tv = ltv;
     local = true;
+    locked = false;
     m_capturecardnum = capturecardnum;
 
     recordfileprefix = gContext->GetSetting("RecordFilePrefix");
@@ -197,6 +199,25 @@
     {
         freeSpace = 0;
     }
+}
+
+int EncoderLink::LockTuner()
+{
+    if (locked)
+        return -2;
+
+    locked = true;  
+    return m_capturecardnum;
+}
+
+void EncoderLink::FreeTuner()
+{
+    locked = false;
+}
+
+bool EncoderLink::isTunerLocked()
+{
+    return locked;
 }
 
 bool EncoderLink::isLowOnFreeSpace()
Index: programs/mythbackend/encoderlink.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/programs/mythbackend/encoderlink.h,v
retrieving revision 1.21
diff -u -r1.21 encoderlink.h
--- programs/mythbackend/encoderlink.h	18 Jul 2003 21:23:26 -0000	1.21
+++ programs/mythbackend/encoderlink.h	7 Aug 2003 04:02:16 -0000
@@ -30,6 +30,10 @@
     bool isConnected();
     int getCardId() { return m_capturecardnum; }
 
+    int LockTuner();
+    void FreeTuner();
+    bool isTunerLocked();
+    
     void cacheFreeSpace();
     bool isLowOnFreeSpace();
     int getFreeSpace() { return freeSpace; }
@@ -109,6 +113,7 @@
     TVRec *tv;
 
     bool local;
+    bool locked;
 
     QDateTime endRecordingTime;
     QDateTime startRecordingTime;
Index: programs/mythbackend/mainserver.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/programs/mythbackend/mainserver.cpp,v
retrieving revision 1.70
diff -u -r1.70 mainserver.cpp
--- programs/mythbackend/mainserver.cpp	2 Aug 2003 17:23:21 -0000	1.70
+++ programs/mythbackend/mainserver.cpp	7 Aug 2003 04:02:18 -0000
@@ -286,6 +286,18 @@
     {
         HandleFillProgramInfo(listline, pbs);
     }
+    else if (command == "LOCK_TUNER")
+    {
+        HandleLockTuner(pbs);
+    }
+    else if (command == "FREE_TUNER")
+    {
+        if (tokens.size() != 2)
+            cerr << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
+                 << " Bad FREE_TUNER query" << endl;
+        else
+            HandleFreeTuner(tokens[1].toInt(), pbs);
+    }
     else if (command == "BACKEND_MESSAGE")
     {
         QString message = listline[1];
@@ -1042,6 +1054,99 @@
     delete pginfo;
 }
 
+void MainServer::HandleLockTuner(PlaybackSock *pbs)
+{
+    QSocket *pbssock = pbs->getSocket();
+    QString pbshost = pbs->getHostname();
+
+    QStringList strlist;
+    int retval;
+    
+    EncoderLink *encoder = NULL;
+    
+    QMap<int, EncoderLink *>::Iterator iter = encoderList->begin();
+    for (; iter != encoderList->end(); ++iter)
+    {
+        EncoderLink *elink = iter.data();
+
+        if (gContext->GetHostName() == pbshost && elink->isConnected() && !elink->IsBusy())
+        {
+            encoder = elink;
+            break;
+        }
+    }
+    
+    if (encoder)
+    {
+        retval = encoder->LockTuner();
+
+        if (retval != -1)
+        {
+            QString querystr = QString("SELECT videodevice,audiodevice,vbidevice FROM "
+                                       "capturecard WHERE cardid = %1;")
+                                       .arg(retval);
+
+            QSqlQuery query = m_db->exec(querystr);
+
+            if (query.isActive() && query.numRowsAffected())
+            {
+                // Success
+                query.next();
+                strlist << QString::number(retval) << query.value(0).toString() << query.value(1).toString() << query.value(2).toString();
+
+                dblock.lock();
+                ScheduledRecording::signalChange(m_db);
+                dblock.unlock();
+
+                SendResponse(pbssock, strlist);
+                return;
+            }
+            else
+            {
+                cerr << "mainserver.o: Failed querying the db for a videodevice" << endl;
+            }
+        }
+        else
+        {
+            // Tuner already locked
+            strlist << "-2" << "" << "" << "";
+            SendResponse(pbssock, strlist);
+            return;
+        }
+    }
+
+    strlist << "-1" << "" << "" << "";
+    SendResponse(pbssock, strlist);
+}
+
+void MainServer::HandleFreeTuner(int cardid, PlaybackSock *pbs)
+{
+    QSocket *pbssock = pbs->getSocket();
+    QStringList strlist;
+    EncoderLink *encoder = NULL;
+    
+    QMap<int, EncoderLink *>::Iterator iter = encoderList->find(cardid);
+    if (iter == encoderList->end())
+    {
+        cerr << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
+        << " Unknown encoder " << cardid << endl;
+        strlist << "FAILED";
+    }
+    else
+    {
+        encoder = iter.data();
+        encoder->FreeTuner();
+        
+        dblock.lock();
+        ScheduledRecording::signalChange(m_db);
+        dblock.unlock();
+        
+        strlist << "OK";
+    }
+    
+    SendResponse(pbssock, strlist);
+}
+
 void MainServer::HandleGetFreeRecorder(PlaybackSock *pbs)
 {
     QSocket *pbssock = pbs->getSocket();
@@ -1063,13 +1168,13 @@
         else
             enchost = elink->getHostname();
 
-        if (enchost == pbshost && elink->isConnected() && !elink->IsBusy())
+        if (enchost == pbshost && elink->isConnected() && !elink->IsBusy() && !elink->isTunerLocked())
         {
             encoder = elink;
             retval = iter.key();
             break;
         }
-        if (retval == -1 && elink->isConnected() && !elink->IsBusy())
+        if (retval == -1 && elink->isConnected() && !elink->IsBusy() && !elink->isTunerLocked())
         {
             encoder = elink;
             retval = iter.key();
Index: programs/mythbackend/mainserver.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/programs/mythbackend/mainserver.h,v
retrieving revision 1.29
diff -u -r1.29 mainserver.h
--- programs/mythbackend/mainserver.h	2 Aug 2003 17:23:22 -0000	1.29
+++ programs/mythbackend/mainserver.h	7 Aug 2003 04:02:18 -0000
@@ -71,6 +71,8 @@
     void HandleQueueTranscode(QStringList &slist, PlaybackSock *pbs);
     void HandleRemoteEncoder(QStringList &slist, QStringList &commands,
                              PlaybackSock *pbs);
+    void HandleLockTuner(PlaybackSock *pbs);
+    void HandleFreeTuner(int cardid, PlaybackSock *pbs);
 
     void SendResponse(QSocket *pbs, QStringList &commands);
 
Index: programs/mythbackend/scheduler.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/programs/mythbackend/scheduler.cpp,v
retrieving revision 1.38
diff -u -r1.38 scheduler.cpp
--- programs/mythbackend/scheduler.cpp	18 Jul 2003 21:23:26 -0000	1.38
+++ programs/mythbackend/scheduler.cpp	7 Aug 2003 04:02:19 -0000
@@ -915,6 +915,8 @@
                     continue;
                 if (enc->isLowOnFreeSpace())
                     continue;
+                if (enc->isTunerLocked())
+                    continue;
                 placed = true;
                 break;
             }
@@ -1006,6 +1008,9 @@
                     if (((*m_tvList)[second->cardid])->isLowOnFreeSpace())
                         continue;
 
+                    if (((*m_tvList)[second->cardid])->isTunerLocked())
+                        continue;
+
                     if (!Conflict(first, second))
                     {
                         bool allclear = true;
@@ -1058,6 +1063,9 @@
                     if (((*m_tvList)[first->cardid])->isLowOnFreeSpace())
                         continue;
 
+                    if (((*m_tvList)[first->cardid])->isTunerLocked())
+                        continue;    
+
                     if (!Conflict(first, second))
                     {
                         bool allclear = true;
@@ -1150,7 +1158,7 @@
             FillRecordLists();
             lastupdate = curtime;
             VERBOSE("Found changes in the todo list.");
-
+            
             // Determine if the user wants us to start recording early
             // and by how many seconds
             prerollseconds = gContext->GetNumSetting("RecordPreRoll");
@@ -1188,6 +1196,24 @@
                                       .arg(nextRecording->cardid)
                                       .arg(nextRecording->sourceid)
                                       .arg(nexttv->getFreeSpace());
+
+                VERBOSE(msg);
+
+                RemoveRecording(nextRecording);
+                nextRecording = NULL;
+                recIter = recordingList.begin();
+                continue;
+            }
+
+            if (recording && nexttv->isTunerLocked())
+            {
+                QString msg = QString("SUPPRESSED recording \"%1\" on channel: "
+                                      "%2 on cardid: %3, sourceid %4. Tuner "
+                                      "is locked by an external application.")
+                                      .arg(nextRecording->title)
+                                      .arg(nextRecording->chanid)
+                                      .arg(nextRecording->cardid)
+                                      .arg(nextRecording->sourceid);
 
                 VERBOSE(msg);
 
Index: programs/mythfrontend/main.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/programs/mythfrontend/main.cpp,v
retrieving revision 1.96
diff -u -r1.96 main.cpp
--- programs/mythfrontend/main.cpp	19 Jul 2003 20:10:41 -0000	1.96
+++ programs/mythfrontend/main.cpp	7 Aug 2003 04:02:20 -0000
@@ -125,6 +125,13 @@
     return 0;
 }
 
+int startExternal(void)
+{
+    
+
+    return 0;
+}
+
 void startTV(void)
 {
     QSqlDatabase *db = QSqlDatabase::database();
@@ -225,6 +232,8 @@
         startManaged();
     else if (sel == "tv_set_rankings")
         startProgramRankings();
+    else if (sel == "tv_external")
+        startExternal();
     else if (sel == "tv_progfind")
         RunProgramFind();
     else if (sel == "settings appearance") 
Index: programs/mythfrontend/tvmenu.xml
===================================================================
RCS file: /var/lib/mythcvs/mythtv/programs/mythfrontend/tvmenu.xml,v
retrieving revision 1.14
diff -u -r1.14 tvmenu.xml
--- programs/mythfrontend/tvmenu.xml	12 Jul 2003 02:20:39 -0000	1.14
+++ programs/mythfrontend/tvmenu.xml	7 Aug 2003 04:02:20 -0000
@@ -58,4 +58,10 @@
       <action>TV_DELETE</action>
    </button> 
 
+<!--   <button>
+      <type>TV_PLAYBACK</type>
+      <text>Passthrough Mode</text>
+      <action>EXECTV xawtv -f -device %s -dspdev %s -vbidev %s</action>
+   </button> -->
+
 </mythmenu>


More information about the mythtv-dev mailing list