Switch to side-by-side view

--- a/src/ohsndrcv.cxx
+++ b/src/ohsndrcv.cxx
@@ -25,17 +25,25 @@
 #include "mpdcli.hxx"
 #include "upmpdutils.hxx"
 #include "ohreceiver.hxx"
-#include "ohplaylist.hxx"
 
 using namespace std;
 using namespace std::placeholders;
 using namespace UPnPP;
 
+#ifndef deleteZ
+#define deleteZ(X) {delete (X); X = 0;}
+#endif
+
 class SenderReceiver::Internal {
 public:
+    // isender is the process we use for internal sources:
+    //   internal source -> local mpd -> fifo -> isender->Songcast
+    // ssender is an arbitrary script probably reading from an audio
+    // driver input and managing a sender. Our local source or mpd are
+    // uninvolved
     Internal(UpMpd *dv, const string& starterpath, int port)
-        : dev(dv), mpd(0), origmpd(0), sender(0), makesendercmd(starterpath),
-          mpdport(port) {
+        : dev(dv), mpd(0), origmpd(0), isender(0), ssender(0),
+          makeisendercmd(starterpath), mpdport(port) {
     }
     ~Internal() {
         clear();
@@ -44,25 +52,22 @@
         if (dev && origmpd) {
             dev->m_mpdcli = origmpd;
             origmpd = 0;
-            if (dev->m_ohrcv) {
-                dev->m_ohrcv->iStop();
-            }
-            if (dev->m_ohpl) {
-                dev->m_ohpl->refreshState();
-            }
-        }
-        delete mpd;
-        mpd = 0;
-        delete sender;
-        sender = 0;
+        }
+        if (dev && dev->m_ohrcv) {
+            dev->m_ohrcv->iStop();
+        }
+        deleteZ(mpd);
+        deleteZ(isender);
+        deleteZ(ssender);
     }
     UpMpd *dev;
     MPDCli *mpd;
     MPDCli *origmpd;
-    ExecCmd *sender;
-    string uri;
-    string meta;
-    string makesendercmd;
+    ExecCmd *isender;
+    ExecCmd *ssender;
+    string iuri;
+    string imeta;
+    string makeisendercmd;
     int mpdport;
 };
 
@@ -88,30 +93,52 @@
     return src->saveState(st, seekms) && dest->restoreState(st);
 }
 
-bool SenderReceiver::start(bool useradio, int seekms)
-{
-    LOGDEB("SenderReceiver::start. seekms " << seekms << endl);
-    
-    if (!m->dev || !m->dev->m_ohpl) {
-        LOGERR("SenderReceiver::start: no dev or ohpl??\n");
+// If script is empty, we are using an internal source and aux mpd +
+// script. Which we reuse across start/stop/start.
+// If script is non-empty, it's an external source, and we restart it
+// each time.
+bool SenderReceiver::start(const string& script, int seekms)
+{
+    LOGDEB("SenderReceiver::start. script [" << script <<
+           "] seekms " << seekms << endl);
+    
+    if (!m->dev || !m->dev->m_mpdcli || !m->dev->m_ohrcv) {
+        LOGERR("SenderReceiver::start: no dev or absent service??\n");
         return false;
     }
     
     // Stop MPD Play (normally already done)
     m->dev->m_mpdcli->stop();
 
-    if (!m->sender) {
-        // First time: Start fifo MPD and Sender
-        m->sender = new ExecCmd();
+    // sndcmd will non empty if we actually started a script instead
+    // of reusing an old one (then need to read the initial data).
+    ExecCmd *sndcmd = 0;
+    if (script.empty() && !m->isender) {
+        // Internal source, first time: Start fifo MPD and Sender
+        m->isender = sndcmd = new ExecCmd();
         vector<string> args;
         args.push_back("-p");
         args.push_back(SoapHelp::i2s(m->mpdport));
         args.push_back("-f");
         args.push_back(m->dev->m_friendlyname);
-        m->sender->startExec(m->makesendercmd, args, false, true);
-
+        m->isender->startExec(m->makeisendercmd, args, false, true);
+    } else if (!script.empty()) {
+        // External source. ssender should already be zero, we delete
+        // it just in case
+        deleteZ(m->ssender);
+        m->ssender = sndcmd = new ExecCmd();
+        vector<string> args;
+        args.push_back("-f");
+        args.push_back(m->dev->m_friendlyname);
+        m->ssender->startExec(script, args, false, true);
+    }
+
+    string meta, uri;
+    if (sndcmd) {
+        // Just started internal or external sender script, need to read the
+        // details
         string output;
-        if (m->sender->getline(output) <= 0) {
+        if (sndcmd->getline(output) <= 0) {
             LOGERR("SenderReceiver::start: makesender command failed\n");
             m->clear();
             return false;
@@ -119,6 +146,7 @@
         LOGDEB("SenderReceiver::start got [" << output << "] from script\n");
 
         // Output is like [Ok mpdport URI base64-encoded-uri METADATA b64-meta]
+        // mpdport is bogus, but present, for ext scripts
         vector<string> toks;
         stringToTokens(output, toks);
         if (toks.size() != 6 || toks[0].compare("Ok")) {
@@ -127,10 +155,20 @@
             m->clear();
             return false;
         }
-        m->uri = base64_decode(toks[3]);
-        m->meta = base64_decode(toks[5]);
-
-        // Connect to the new MPD
+        uri = base64_decode(toks[3]);
+        meta = base64_decode(toks[5]);
+        if (script.empty()) {
+            m->iuri = uri;
+            m->imeta = meta;
+        }
+    } else {
+        // Reusing internal source
+        uri = m->iuri;
+        meta = m->imeta;
+    }
+    
+    if (sndcmd && script.empty()) {
+        // Just started the internal source script, connect to the new MPD
         m->mpd = new MPDCli("localhost", m->mpdport);
         if (!m->mpd || !m->mpd->ok()) {
             LOGERR("SenderReceiver::start: can't connect to new MPD\n");
@@ -140,16 +178,20 @@
     }
     
     // Start our receiver
-    if (!m->dev->m_ohrcv->iSetSender(m->uri, m->meta) ||
+    if (!m->dev->m_ohrcv->iSetSender(uri, meta) ||
         !m->dev->m_ohrcv->iPlay()) {
         m->clear();
         return false;
     }
 
-    // Copy mpd state 
-    copyMpd(m->dev->m_mpdcli, m->mpd, seekms);
-    m->origmpd = m->dev->m_mpdcli;
-    m->dev->m_mpdcli = m->mpd;
+    if (script.empty()) {
+        // Internal source: copy mpd state
+        copyMpd(m->dev->m_mpdcli, m->mpd, seekms);
+        m->origmpd = m->dev->m_mpdcli;
+        m->dev->m_mpdcli = m->mpd;
+    } else {
+        m->origmpd = 0;
+    }
 
     return true;
 }
@@ -157,18 +199,21 @@
 bool SenderReceiver::stop()
 {
     LOGDEB("SenderReceiver::stop()\n");
-    // Do we want to transfer the playlist back ? Probably we do.
-    if (!m->dev || !m->origmpd || !m->mpd || !m->dev->m_ohpl ||
-        !m->dev->m_ohrcv) {
-        LOGERR("SenderReceiver::stop: bad state: dev/origmpd/mpd null\n");
-        return false;
-    }
-    copyMpd(m->mpd, m->origmpd, -1);
-    m->mpd->stop();
-    m->dev->m_mpdcli = m->origmpd;
-    m->origmpd = 0;
+    if (!m->dev || !m->dev->m_ohrcv) {
+        LOGERR("SenderReceiver::stop: bad state: dev/rcv null\n");
+        return false;
+    }
     m->dev->m_ohrcv->iStop();
-    m->dev->m_ohpl->refreshState();
-
+
+    if (m->origmpd && m->mpd) {
+        // Do we want to transfer the playlist back ? Probably we do.
+        copyMpd(m->mpd, m->origmpd, -1);
+        m->mpd->stop();
+        m->dev->m_mpdcli = m->origmpd;
+        m->origmpd = 0;
+    }
+
+    // We don't reuse external source processes
+    deleteZ(m->ssender);
     return true;
 }