Switch to side-by-side view

--- a
+++ b/src/ohradio.cpp
@@ -0,0 +1,347 @@
+/* Copyright (C) 2013 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.
+ */
+
+/////////////// libupnpp OhRadio trial driver
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+
+#include <string>
+#include <iostream>
+#include <vector>
+#include <algorithm>
+
+#include "libupnpp/upnpplib.hxx"
+#include "libupnpp/log.hxx"
+#include "libupnpp/upnpputils.hxx"
+#include "libupnpp/control/cdirectory.hxx"
+#include "libupnpp/control/discovery.hxx"
+#include "libupnpp/control/mediarenderer.hxx"
+#include "libupnpp/control/ohradio.hxx"
+#include "libupnpp/control/ohinfo.hxx"
+
+using namespace std;
+using namespace UPnPClient;
+using namespace UPnPP;
+
+UPnPDeviceDirectory *superdir;
+
+int channelid;
+
+class MReporter : public UPnPClient::VarEventReporter {
+public:
+    void changed(const char *nm, int value) {
+        if (!strcmp(nm, "TransportState")) {
+            string tpstate;
+            switch(value) {
+            case OHPlaylist::TPS_Unknown: tpstate = "Unknown"; break;
+            case OHPlaylist::TPS_Buffering: tpstate = "Buffering"; break;
+            case OHPlaylist::TPS_Paused: tpstate = "Paused"; break;
+            case OHPlaylist::TPS_Playing: tpstate = "Playing"; break;
+            case OHPlaylist::TPS_Stopped: tpstate = "Stopped"; break;
+            }
+            cout << "Changed: " << nm << " : " << tpstate << endl;
+        } else if (!strcmp(nm, "Id")) {
+            cout << "Changed: " << nm << " : " << value << endl;
+            channelid = value;
+        } else {
+            cout << "Changed: " << nm << " : " << value << endl;
+        }
+    }
+    void changed(const char *nm, const char *value)  {
+        cout << "Changed: " << nm << " : " << value << endl;
+    }
+
+    void changed(const char *nm, UPnPDirObject meta) {
+        cout << "Changed: " << nm << " : " << meta.dump() << endl;
+    }
+
+    void changed(const char * nm, std::vector<int> ids) {
+        cout << "Changed: " << nm << " : ";
+        for (unsigned int i = 0; i < ids.size(); i++) {
+            cout << SoapHelp::i2s(ids[i]) << " ";
+        }
+        cout << endl;
+    }
+};
+
+MRDH getRenderer(const string& friendlyName)
+{
+    if (superdir == 0) {
+        superdir = UPnPDeviceDirectory::getTheDir();
+    }
+
+    UPnPDeviceDesc ddesc;
+    if (superdir->getDevByFName(friendlyName, ddesc)) {
+        return MRDH(new MediaRenderer(ddesc));
+    }
+    cerr << "getDevByFname failed" << endl;
+    return MRDH();
+}
+
+void rdMonitor(OHRDH hdl, OHIFH hdlif)
+{
+    MReporter reporter;
+    hdl->installReporter(&reporter);
+    hdlif->installReporter(&reporter);
+    while (true) {
+        static int prevchan;
+        sleep(2);
+        string uri;
+        UPnPDirObject dirent;
+        if (0&& prevchan != channelid) {
+            cerr << "New ChannelId: " << channelid << endl;
+            prevchan = channelid;
+#if 0
+            if (hdl->channel(&uri, &dirent) == 0) {
+                cout << "Channel: uri " << uri << "\nMetadata " <<
+                    dirent.dump() << endl;
+            }
+#endif
+            int ret;
+            if ((ret = hdlif->metatext(&dirent)) == 0) {
+                cout << "Metatext: " << dirent.dump() << endl;
+            } else {
+                cerr << "Metatext: failed: " << ret << endl;
+            }
+            
+        }
+    }
+}
+
+void rdIdArray(OHRDH hdl)
+{
+    vector<int> ids;
+    int token = 0;
+    int ret;
+    if ((ret = hdl->idArray(&ids, &token)) != 0) {
+        cerr << "idArray failed: " << ret << endl;
+        return;
+    }
+
+    cout << "token: " << token << ". " << ids.size() << " ids: ";
+    for (unsigned int i = 0; i < ids.size(); i++) {
+        cout << SoapHelp::i2s(ids[i]) << " ";
+    }
+    cout << endl;
+}
+
+string rdReadList(OHRDH hdl, int id = -1)
+{
+    vector<int> ids;
+    int token = 0;
+    int ret;
+    if ((ret = hdl->idArray(&ids, &token)) != 0) {
+        cerr << "idArray failed: " << ret << endl;
+        return string();
+    }
+    vector<OHPlaylist::TrackListEntry> ents;
+    if ((ret = hdl->readList(ids, &ents)) != 0) {
+        cerr << "readList failed: " << ret << endl;
+        return string();
+    }
+
+    for (unsigned int i = 0; i < ents.size(); i++) {
+        if (id == -1) {
+            cout << "Id: " << SoapHelp::i2s(ents[i].id) <<
+                " url " << ents[i].url << 
+                "\nmetadata: " << ents[i].dirent.dump() << "\n";
+        } else {
+            if (ents[i].id == id) {
+                return ents[i].url;
+            }
+        }
+    }
+    cout << endl;
+    return string();
+}
+
+// Could not get this to work. Gets UPNP_E_BAD_RESPONSE on sendAction??
+void rdRead(OHRDH hdl, int id)
+{
+    UPnPDirObject dirent;
+    int ret;
+    if ((ret = hdl->read(id, &dirent)) != 0) {
+        cerr << "read failed: " << ret << endl;
+        return;
+    }
+    cout << "read: metadata: " << dirent.dump() << endl;
+}
+
+void rdSetId(OHRDH hdl, int id)
+{
+    int ret;
+    string url = rdReadList(hdl, id);
+    if (url.empty()) {
+        cerr << "Id " << id << " not found\n";
+        return;
+    }
+    if ((ret = hdl->setId(id, url)) != 0) {
+        cerr << "setId failed: " << ret << endl;
+        return;
+    }
+    cout << "setId ok\n";
+}
+
+static char *thisprog;
+static char usage [] =
+" -a <renderer>: run idArray\n"
+" -M <renderer>: monitor OHRadio\n"
+" -p <renderer>: pause radio\n"
+" -P <renderer>: play radio\n"
+" -r <renderer> id: run read\n"
+" -R <renderer>: run ReadList\n"
+" -s <renderer> id: run setId\n"
+" -S <renderer>: stop\n"
+" \n"
+;
+
+static void
+Usage(void)
+{
+    fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
+    exit(1);
+}
+static int	   op_flags;
+#define OPT_M    0x1
+#define OPT_a    0x2
+#define OPT_r    0x4
+#define OPT_R    0x8
+#define OPT_s    0x10
+#define OPT_P    0x20
+#define OPT_p    0x40
+#define OPT_S    0x80
+
+static struct option long_options[] = {
+    {0, 0, 0, 0}
+};
+
+int main(int argc, char *argv[])
+{
+    string fname;
+    string arg;
+
+    thisprog = argv[0];
+
+    int ret;
+    int option_index = 0;
+    while ((ret = getopt_long(argc, argv, "aMPpRrSs", 
+                              long_options, &option_index)) != -1) {
+        switch (ret) {
+        case 'a': if (op_flags) Usage(); op_flags |= OPT_a; break;
+        case 'M': if (op_flags) Usage(); op_flags |= OPT_M; break;
+        case 'P': if (op_flags) Usage(); op_flags |= OPT_P; break;
+        case 'p': if (op_flags) Usage(); op_flags |= OPT_p; break;
+        case 'R': if (op_flags) Usage(); op_flags |= OPT_R; break;
+        case 'r': if (op_flags) Usage(); op_flags |= OPT_r; break;
+        case 's': if (op_flags) Usage(); op_flags |= OPT_s; break;
+        case 'S': if (op_flags) Usage(); op_flags |= OPT_S; break;
+        default:
+            Usage();
+        }
+    }
+
+    if (op_flags & (OPT_M|OPT_a|OPT_R|OPT_p|OPT_P|OPT_S)) {
+            if (optind != argc - 1) 
+                Usage();
+            fname = argv[optind++];
+    }
+    if (op_flags & (OPT_r|OPT_s)) {
+        if (optind != argc - 2) 
+                Usage();
+            fname = argv[optind++];
+            arg = argv[optind++];
+    }
+            
+    if (Logger::getTheLog("/tmp/ohradio.log") == 0) {
+        cerr << "Can't initialize log" << endl;
+        return 1;
+    }
+    Logger::getTheLog("")->setLogLevel(Logger::LLDEB1);
+
+    LibUPnP *mylib = LibUPnP::getLibUPnP();
+    if (!mylib) {
+        cerr << "Can't get LibUPnP" << endl;
+        return 1;
+    }
+
+    if (!mylib->ok()) {
+        cerr << "Lib init failed: " <<
+            mylib->errAsString("main", mylib->getInitError()) << endl;
+        return 1;
+    }
+    mylib->setLogFileName("/tmp/libupnp.log", LibUPnP::LogLevelDebug);
+
+    MRDH rdr = getRenderer(fname);
+    if (!rdr) {
+        cerr << "Can't connect torenderer\n";
+        return 1;
+    }
+    OHRDH hdl = rdr->ohrd();
+    if (!hdl) {
+        cerr << "Device has no OHRadio service" << endl;
+        return 1;
+    }
+    OHIFH hdlif = rdr->ohif();
+    if (!hdlif) {
+        cerr << "Device has no OHInfo service" << endl;
+        return 1;
+    }
+    
+    if ((op_flags & OPT_M)) {
+        rdMonitor(hdl, hdlif);
+    } else if ((op_flags & OPT_a)) {
+        rdIdArray(hdl);
+    } else if ((op_flags & OPT_R)) {
+        rdReadList(hdl);
+    } else if ((op_flags & OPT_p)) {
+        int ret = hdl->pause();
+        if (ret) {
+            cerr << "Pause: " << SoapHelp::i2s(ret);
+            return 1;
+        } else {
+            cout << "Pause Ok\n";
+        }
+    } else if ((op_flags & OPT_P)) {
+        int ret = hdl->play();
+        if (ret) {
+            cerr << "Play: " << SoapHelp::i2s(ret);
+            return 1;
+        } else {
+            cout << "Play Ok\n";
+        }
+    } else if ((op_flags & OPT_S)) {
+        int ret = hdl->stop();
+        if (ret) {
+            cerr << "Stop: " << SoapHelp::i2s(ret);
+            return 1;
+        } else {
+            cout << "Stop Ok\n";
+        }
+    } else if ((op_flags & OPT_r)) {
+        rdRead(hdl, atoi(arg.c_str()));
+    } else if ((op_flags & OPT_s)) {
+        rdSetId(hdl, atoi(arg.c_str()));
+    } else {
+        Usage();
+    }
+
+    return 0;
+}