--- a
+++ b/src/ohsndrcv.cxx
@@ -0,0 +1,167 @@
+/* Copyright (C) 2015 J.F.Dockes
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ohsndrcv.hxx"
+
+#include "libupnpp/log.hxx"
+#include "libupnpp/base64.hxx"
+
+#include "execmd.h"
+#include "upmpd.hxx"
+#include "mpdcli.hxx"
+#include "upmpdutils.hxx"
+#include "ohreceiver.hxx"
+#include "ohplaylist.hxx"
+
+using namespace std;
+using namespace std::placeholders;
+using namespace UPnPP;
+
+static const string makesendercmd("scmakesender.py");
+static int mpdport = 6700;
+
+class SenderReceiver::Internal {
+public:
+ Internal(UpMpd *dv)
+ : dev(dv), mpd(0), origmpd(0), cmd(0) {
+ }
+ ~Internal() {
+ clear();
+ }
+ void clear() {
+ if (dev && origmpd) {
+ dev->m_mpdcli = origmpd;
+ origmpd = 0;
+ if (dev->m_ohpl) {
+ dev->m_ohpl->resetQVers();
+ }
+ if (dev->m_ohrcv) {
+ dev->m_ohrcv->iStop();
+ }
+ }
+ delete mpd;
+ delete cmd;
+ }
+ UpMpd *dev;
+ MPDCli *mpd;
+ MPDCli *origmpd;
+ ExecCmd *cmd;
+};
+
+
+SenderReceiver::SenderReceiver(UpMpd *dev)
+{
+ m = new Internal(dev);
+}
+
+SenderReceiver::~SenderReceiver()
+{
+ if (m)
+ delete m;
+}
+
+bool SenderReceiver::start(int seekms)
+{
+ LOGDEB("SenderReceiver::start. seekms " << seekms << endl);
+
+ if (!m->dev || !m->dev->m_ohpl) {
+ LOGERR("SenderReceiver::start: no ohpl\n");
+ return false;
+ }
+
+ // Playing state. Playing is stopped at this point (source switch), so
+ // we get the elapsedms (would be 0) as input param.
+ MpdStatus mpds = m->dev->getMpdStatusNoUpdate();
+
+ // Retrieve the current playlist from the normal MPD
+ vector<UpSong> playlist;
+ if (!m->dev->m_mpdcli || !m->dev->m_mpdcli->getQueueData(playlist)) {
+ LOGERR("SenderReceiver::start: can't retrieve current playlist\n");
+ return false;
+ }
+
+ // Stop MPD Play (normally already done)
+ m->dev->m_mpdcli->stop();
+
+ // Start fifo MPD and Sender
+ m->cmd = new ExecCmd();
+ vector<string> args;
+ args.push_back("-p");
+ args.push_back(SoapHelp::i2s(mpdport));
+ m->cmd->startExec(makesendercmd, args, false, true);
+
+ string output;
+ if (!m->cmd->getline(output)) {
+ LOGERR("SenderReceiver::start: makesender command failed\n");
+ m->clear();
+ return false;
+ }
+ LOGDEB("SenderReceiver::start got [" << output << "] from script\n");
+
+ // Output is like [Ok mpdport URI base64-encoded-uri METADATA b64-meta]
+ vector<string> toks;
+ stringToTokens(output, toks);
+ if (toks.size() != 6 || toks[0].compare("Ok")) {
+ LOGERR("SenderReceiver::start: bad output from script: " << output
+ << endl);
+ m->clear();
+ return false;
+ }
+ string uri = base64_decode(toks[3]);
+ string meta = base64_decode(toks[5]);
+
+ // Connect to the new MPD, and copy the playlist
+ m->mpd = new MPDCli("localhost", mpdport);
+ if (!m->mpd || !m->mpd->ok()) {
+ LOGERR("SenderReceiver::start: can't connect to new MPD\n");
+ m->clear();
+ return false;
+ }
+ for (unsigned int i = 0; i < playlist.size(); i++) {
+ if (m->mpd->insert(playlist[i].uri, i, playlist[i]) < 0) {
+ LOGERR("SenderReceiver::start: mpd->insert failed\n");
+ m->clear();
+ return false;
+ }
+ }
+
+ // Start our receiver
+ if (!m->dev->m_ohrcv->iSetSender(uri, meta) ||
+ !m->dev->m_ohrcv->iPlay()) {
+ m->clear();
+ return false;
+ }
+
+ // Replace the original mpd and play
+ m->origmpd = m->dev->m_mpdcli;
+ m->dev->m_mpdcli = m->mpd;
+ LOGDEB("SenderReceiver::starting new mpd. songelapsedms: " <<
+ mpds.songelapsedms << endl);
+ m->mpd->setVolume(mpds.volume);
+ m->mpd->play(mpds.songpos);
+ m->mpd->seek(seekms/1000);
+ m->mpd->setVolume(mpds.volume);
+ return true;
+}
+
+bool SenderReceiver::stop()
+{
+ LOGDEB("SenderReceiver::stop()\n");
+ // Do we want to transfer the playlist back ? Probably we do.
+ m->clear();
+ return true;
+}