Switch to unified view

a/src/avtransport.cxx b/src/avtransport.cxx
...
...
21
21
22
#include <functional>
22
#include <functional>
23
#include <iostream>
23
#include <iostream>
24
#include <map>
24
#include <map>
25
#include <utility>
25
#include <utility>
26
#include <regex>
26
27
27
#include "libupnpp/log.hxx"
28
#include "libupnpp/log.hxx"
28
#include "libupnpp/soaphelp.hxx"
29
#include "libupnpp/soaphelp.hxx"
29
#include "libupnpp/upnpavutils.hxx"
30
#include "libupnpp/upnpavutils.hxx"
30
31
31
#include "mpdcli.hxx"
32
#include "mpdcli.hxx"
32
#include "ohplaylist.hxx"
33
#include "ohplaylist.hxx"
33
#include "upmpd.hxx"
34
#include "upmpd.hxx"
34
#include "upmpdutils.hxx"
35
#include "upmpdutils.hxx"
35
#include "smallut.h"
36
#include "smallut.h"
37
#include "pathut.h"
38
#include "conftree.h"
39
#include "mediaserver/cdplugins/cdplugin.hxx"
36
40
37
// For testing upplay with a dumb renderer.
41
// For testing upplay with a dumb renderer.
38
// #define NO_SETNEXT
42
// #define NO_SETNEXT
39
43
40
using namespace std;
44
using namespace std;
41
using namespace std::placeholders;
45
using namespace std::placeholders;
42
46
43
static const string sIdTransport("urn:upnp-org:serviceId:AVTransport");
47
static const string sIdTransport("urn:upnp-org:serviceId:AVTransport");
44
static const string sTpTransport("urn:schemas-upnp-org:service:AVTransport:1");
48
static const string sTpTransport("urn:schemas-upnp-org:service:AVTransport:1");
49
50
// this is used for translating urls for the very special use of
51
// Kazoo/Lumin + ohcredentials. Actually, this should be configurable
52
// as there is no need for the media server, which is used to do the
53
// real data access to run on this host.
54
static string upnphost;
45
55
46
UpMpdAVTransport::UpMpdAVTransport(UpMpd *dev, bool noev)
56
UpMpdAVTransport::UpMpdAVTransport(UpMpd *dev, bool noev)
47
    : UpnpService(sTpTransport, sIdTransport, dev, noev), m_dev(dev), m_ohp(0)
57
    : UpnpService(sTpTransport, sIdTransport, dev, noev), m_dev(dev), m_ohp(0)
48
{
58
{
49
    m_dev->addActionMapping(this,"SetAVTransportURI", 
59
    m_dev->addActionMapping(this,"SetAVTransportURI", 
...
...
87
                                               this, _1, _2, 0));
97
                                               this, _1, _2, 0));
88
    m_dev->addActionMapping(this, "Previous", 
98
    m_dev->addActionMapping(this, "Previous", 
89
                            bind(&UpMpdAVTransport::seqcontrol, 
99
                            bind(&UpMpdAVTransport::seqcontrol, 
90
                                 this, _1, _2, 1));
100
                                 this, _1, _2, 1));
91
101
102
    unsigned short usport;
103
    m_dev->ipv4(&upnphost, &usport);
104
    
92
    // This would make our life easier, but it's incompatible if
105
    // This would make our life easier, but it's incompatible if
93
    // ohplaylist is also in use, so refrain.
106
    // ohplaylist is also in use, so refrain.
94
//    dev->m_mpdcli->consume(true);
107
//    dev->m_mpdcli->consume(true);
95
#ifdef NO_SETNEXT
108
#ifdef NO_SETNEXT
96
    // If no setnext, we'd like to fake stopping at each track but this does not work because mpd goes into PAUSED PLAY at the end of track, not STOP.
109
    // If no setnext, we'd like to fake stopping at each track but this does not work because mpd goes into PAUSED PLAY at the end of track, not STOP.
...
...
364
    m_tpstate = newtpstate;
377
    m_tpstate = newtpstate;
365
    LOGDEB1("UpMpdAVTransport::getEventDataTransport: " << chgdata << endl);
378
    LOGDEB1("UpMpdAVTransport::getEventDataTransport: " << chgdata << endl);
366
    return true;
379
    return true;
367
}
380
}
368
381
382
// Hack for working with OHCredentials. The CP aware of this
383
// (Kazoo/Lumin mostly) will send URIs like qobuz:// tidal:// and
384
// expect the renderer to know what to do with them. We transform them
385
// so that they point to our media server gateway (which should be
386
// running of course for this to work).
387
static bool maybeMorphSpecialUri(string& uri)
388
{
389
    if (uri.find("http://") == 0 || uri.find("https://") == 0) {
390
        return true;
391
    }
392
393
    static string sport;
394
    if (sport.empty()) {
395
        std::unique_lock<std::mutex>(g_configlock);
396
        int port = CDPluginServices::default_microhttpport();
397
        if (!g_config->get("plgmicrohttpport", sport)) {
398
            sport = SoapHelp::i2s(port);
399
        }
400
    }
401
402
    // http://wiki.openhome.org/wiki/Av:Developer:Eriskay:StreamingServices
403
    // Tidal and qobuz tracks added by Kazoo / Lumin: 
404
    //   tidal://track?version=1&trackId=[tidal_track_id]
405
    //   qobuz://track?version=2&trackId=[qobuz_track_id]
406
    
407
    string se =
408
        "(tidal|qobuz)://track\\?version=([[:digit:]]+)&trackId=([[:digit:]]+)";
409
    std::regex e(se);
410
    std::smatch mr;
411
    bool found = std::regex_match(uri, mr, e);
412
    if (found) {
413
        string pathprefix = CDPluginServices::getpathprefix(mr[1]);
414
415
        // The microhttpd code actually only cares about getting a
416
        // trackId parameter. Make it look what the plugins normally
417
        // generate anyway:
418
        string path = path_cat(pathprefix,
419
                               "track?version=1&trackId=" + mr[3].str());
420
        uri = string("http://") + upnphost + ":" + sport + path;
421
    }
422
    return found;
423
}
424
369
// http://192.168.4.4:8200/MediaItems/246.mp3
425
// http://192.168.4.4:8200/MediaItems/246.mp3
370
int UpMpdAVTransport::setAVTransportURI(const SoapIncoming& sc,
426
int UpMpdAVTransport::setAVTransportURI(const SoapIncoming& sc,
371
                                        SoapOutgoing& data, bool setnext)
427
                                        SoapOutgoing& data, bool setnext)
372
{
428
{
373
#ifdef NO_SETNEXT
429
#ifdef NO_SETNEXT
...
...
381
    string uri;
437
    string uri;
382
    bool found = setnext? sc.get("NextURI", &uri) : sc.get("CurrentURI", &uri);
438
    bool found = setnext? sc.get("NextURI", &uri) : sc.get("CurrentURI", &uri);
383
    if (!found) {
439
    if (!found) {
384
        return UPNP_E_INVALID_PARAM;
440
        return UPNP_E_INVALID_PARAM;
385
    }
441
    }
442
    if (!maybeMorphSpecialUri(uri)) {
443
        LOGERR("Set(Next)AVTransportURI: bad uri: " << uri << endl);
444
        return UPNP_E_INVALID_PARAM;
445
    }
446
386
    string metadata;
447
    string metadata;
387
    found = setnext ? sc.get("NextURIMetaData", &metadata) :
448
    found = setnext ? sc.get("NextURIMetaData", &metadata) :
388
        sc.get("CurrentURIMetaData", &metadata);
449
        sc.get("CurrentURIMetaData", &metadata);
389
    LOGDEB("Set(next)AVTransportURI: next " << setnext <<  " uri " << uri <<
450
    LOGDEB("Set(next)AVTransportURI: next " << setnext <<  " uri " << uri <<
390
           " metadata[" << metadata << "]" << endl);
451
           " metadata[" << metadata << "]" << endl);