Switch to unified view

a/upmpd/upmpd.cxx b/upmpd/upmpd.cxx
...
...
39
static const string dfltFriendlyName("UpMpd");
39
static const string dfltFriendlyName("UpMpd");
40
40
41
// The UPnP MPD frontend device with its 2 services
41
// The UPnP MPD frontend device with its 2 services
42
class UpMpd : public UpnpDevice {
42
class UpMpd : public UpnpDevice {
43
public:
43
public:
44
  enum Options {
45
      upmpdNone,
46
      upmpdOwnQueue, // The MPD belongs to us, we shall clear it as we like
47
  };
44
    UpMpd(const string& deviceid, const unordered_map<string, string>& xmlfiles,
48
    UpMpd(const string& deviceid, const unordered_map<string, string>& xmlfiles,
45
        MPDCli *mpdcli);
49
        MPDCli *mpdcli, Options opts = upmpdNone);
46
50
47
    // RenderingControl
51
    // RenderingControl
48
    int setMute(const SoapArgs& sc, SoapData& data);
52
    int setMute(const SoapArgs& sc, SoapData& data);
49
    int getMute(const SoapArgs& sc, SoapData& data);
53
    int getMute(const SoapArgs& sc, SoapData& data);
50
    int setVolume(const SoapArgs& sc, SoapData& data, bool isDb);
54
    int setVolume(const SoapArgs& sc, SoapData& data, bool isDb);
...
...
94
98
95
    // Desired volume target. We may delay executing small volume
99
    // Desired volume target. We may delay executing small volume
96
    // changes to avoid saturating with small requests.
100
    // changes to avoid saturating with small requests.
97
    int m_desiredvolume;
101
    int m_desiredvolume;
98
102
103
  int m_options;
99
};
104
};
100
105
101
static const string serviceIdRender("urn:upnp-org:serviceId:RenderingControl");
106
static const string serviceIdRender("urn:upnp-org:serviceId:RenderingControl");
102
static const string serviceIdTransport("urn:upnp-org:serviceId:AVTransport");
107
static const string serviceIdTransport("urn:upnp-org:serviceId:AVTransport");
103
108
104
UpMpd::UpMpd(const string& deviceid, 
109
UpMpd::UpMpd(const string& deviceid, 
105
             const unordered_map<string, string>& xmlfiles,
110
             const unordered_map<string, string>& xmlfiles,
106
           MPDCli *mpdcli)
111
           MPDCli *mpdcli, Options opts)
107
    : UpnpDevice(deviceid, xmlfiles), m_mpdcli(mpdcli), m_desiredvolume(-1)
112
    : UpnpDevice(deviceid, xmlfiles), m_mpdcli(mpdcli), m_desiredvolume(-1),
113
    m_options(opts)
108
{
114
{
109
    addServiceType(serviceIdRender,
115
    addServiceType(serviceIdRender,
110
                   "urn:schemas-upnp-org:service:RenderingControl:1");
116
                   "urn:schemas-upnp-org:service:RenderingControl:1");
111
    {   auto bound = bind(&UpMpd::setMute, this, _1, _2);
117
    {   auto bound = bind(&UpMpd::setMute, this, _1, _2);
112
        addActionMapping("SetMute", bound);
118
        addActionMapping("SetMute", bound);
...
...
627
    it = setnext? sc.args.find("NextURIMetaData") : 
633
    it = setnext? sc.args.find("NextURIMetaData") : 
628
        sc.args.find("CurrentURIMetaData");
634
        sc.args.find("CurrentURIMetaData");
629
    if (it != sc.args.end())
635
    if (it != sc.args.end())
630
        metadata = it->second;
636
        metadata = it->second;
631
637
638
  if ((m_options & upmpdOwnQueue) && !setnext) {
639
      // If we own the queue, just clear it before setting the
640
      // track.  Else it's difficult to impossible to prevent it
641
      // from growing if upmpdcli restarts. If the option is not set, the
642
      // user prefers to live with the issue.
643
      m_mpdcli->clearQueue();
644
  }
645
632
    const struct MpdStatus &mpds = m_mpdcli->getStatus();
646
    const struct MpdStatus &mpds = m_mpdcli->getStatus();
633
    bool is_song = (mpds.state == MpdStatus::MPDS_PLAY) || 
647
    bool is_song = (mpds.state == MpdStatus::MPDS_PLAY) || 
634
        (mpds.state == MpdStatus::MPDS_PAUSE);
648
        (mpds.state == MpdStatus::MPDS_PAUSE);
635
    int curpos = mpds.songpos;
649
    int curpos = mpds.songpos;
636
    LOGDEB("UpMpd::set" << (setnext?"Next":"") << 
650
    LOGDEB("UpMpd::set" << (setnext?"Next":"") << 
637
           "AVTransportURI: curpos: " <<
651
           "AVTransportURI: curpos: " <<
638
           curpos << " is_song " << is_song << " qlen " << mpds.qlen << endl);
652
           curpos << " is_song " << is_song << " qlen " << mpds.qlen << endl);
639
653
640
    // curpos == -1 means that the playlist was cleared or we just started. A
654
    // curpos == -1 means that the playlist was cleared or we just started. A
641
    // play will use position 0, so it's actually equivalent to curpos == 0
655
    // play will use position 0, so it's actually equivalent to curpos == 0
642
    if (curpos == -1)
656
    if (curpos == -1) {
643
        curpos = 0;
657
        curpos = 0;
658
  }
644
659
645
    if (mpds.qlen == 0 && setnext) {
660
    if (mpds.qlen == 0 && setnext) {
646
        LOGDEB("setNextAVTRansportURI invoked but empty queue!" << endl);
661
        LOGDEB("setNextAVTRansportURI invoked but empty queue!" << endl);
647
        return UPNP_E_INVALID_PARAM;
662
        return UPNP_E_INVALID_PARAM;
648
    }
663
    }
...
...
972
#define OPT_d     0x8
987
#define OPT_d     0x8
973
#define OPT_D     0x10
988
#define OPT_D     0x10
974
#define OPT_c     0x20
989
#define OPT_c     0x20
975
#define OPT_l     0x40
990
#define OPT_l     0x40
976
#define OPT_f     0x80
991
#define OPT_f     0x80
992
#define OPT_q     0x100
993
977
static const char usage[] = 
994
static const char usage[] = 
978
"-c configfile \t configuration file to use\n"
995
"-c configfile \t configuration file to use\n"
979
"-h host    \t specify host MPD is running on\n"
996
"-h host    \t specify host MPD is running on\n"
980
"-p port     \t specify MPD port\n"
997
"-p port     \t specify MPD port\n"
981
"-d logfilename\t debug messages to\n"
998
"-d logfilename\t debug messages to\n"
982
"-l loglevel\t  log level (0-6)\n"
999
"-l loglevel\t  log level (0-6)\n"
983
"-D          \t run as a daemon\n"
1000
"-D          \t run as a daemon\n"
984
"-f friendlyname\t define device displayed name\n"
1001
"-f friendlyname\t define device displayed name\n"
1002
"-q 0|1      \t if set, we own the mpd queue, else avoid clearing it whenever we feel like it"
985
"  \n\n"
1003
"  \n\n"
986
            ;
1004
            ;
987
static void
1005
static void
988
Usage(void)
1006
Usage(void)
989
{
1007
{
...
...
1003
//  string upnplogfilename("/tmp/upmpd_libupnp.log");
1021
//  string upnplogfilename("/tmp/upmpd_libupnp.log");
1004
    string logfilename;
1022
    string logfilename;
1005
    int loglevel(upnppdebug::Logger::LLINF);
1023
    int loglevel(upnppdebug::Logger::LLINF);
1006
    string configfile;
1024
    string configfile;
1007
    string friendlyname(dfltFriendlyName);
1025
    string friendlyname(dfltFriendlyName);
1026
  bool ownqueue = true;
1008
1027
1009
    const char *cp;
1028
    const char *cp;
1010
    if ((cp = getenv("UPMPD_HOST")))
1029
    if ((cp = getenv("UPMPD_HOST")))
1011
        mpdhost = cp;
1030
        mpdhost = cp;
1012
    if ((cp = getenv("UPMPD_PORT")))
1031
    if ((cp = getenv("UPMPD_PORT")))
...
...
1035
                mpdhost = *(++argv); argc--; goto b1;
1054
                mpdhost = *(++argv); argc--; goto b1;
1036
            case 'l':   op_flags |= OPT_l; if (argc < 2)  Usage();
1055
            case 'l':   op_flags |= OPT_l; if (argc < 2)  Usage();
1037
                loglevel = atoi(*(++argv)); argc--; goto b1;
1056
                loglevel = atoi(*(++argv)); argc--; goto b1;
1038
            case 'p':   op_flags |= OPT_p; if (argc < 2)  Usage();
1057
            case 'p':   op_flags |= OPT_p; if (argc < 2)  Usage();
1039
                mpdport = atoi(*(++argv)); argc--; goto b1;
1058
                mpdport = atoi(*(++argv)); argc--; goto b1;
1059
          case 'q':   op_flags |= OPT_q; if (argc < 2)  Usage();
1060
              ownqueue = atoi(*(++argv)) != 0; argc--; goto b1;
1040
            default: Usage();   break;
1061
            default: Usage();   break;
1041
            }
1062
            }
1042
    b1: argc--; argv++;
1063
    b1: argc--; argv++;
1043
    }
1064
    }
1044
1065
...
...
1061
        if (!(op_flags & OPT_h))
1082
        if (!(op_flags & OPT_h))
1062
            config.get("mpdhost", mpdhost);
1083
            config.get("mpdhost", mpdhost);
1063
        if (!(op_flags & OPT_p) && config.get("mpdport", value)) {
1084
        if (!(op_flags & OPT_p) && config.get("mpdport", value)) {
1064
            mpdport = atoi(value.c_str());
1085
            mpdport = atoi(value.c_str());
1065
        }
1086
        }
1087
      if (!(op_flags & OPT_q) && config.get("ownqueue", value)) {
1088
          ownqueue = atoi(value.c_str()) != 0;
1089
      }
1066
    }
1090
    }
1067
1091
1068
    if (upnppdebug::Logger::getTheLog(logfilename) == 0) {
1092
    if (upnppdebug::Logger::getTheLog(logfilename) == 0) {
1069
        cerr << "Can't initialize log" << endl;
1093
        cerr << "Can't initialize log" << endl;
1070
        return 1;
1094
        return 1;
...
...
1133
    xmlfiles["description.xml"] = description;
1157
    xmlfiles["description.xml"] = description;
1134
    xmlfiles["RenderingControl.xml"] = rdc_scdp;
1158
    xmlfiles["RenderingControl.xml"] = rdc_scdp;
1135
    xmlfiles["AVTransport.xml"] = avt_scdp;
1159
    xmlfiles["AVTransport.xml"] = avt_scdp;
1136
1160
1137
    // Initialize the UPnP device object.
1161
    // Initialize the UPnP device object.
1138
    UpMpd device(string("uuid:") + UUID, xmlfiles, &mpdcli);
1162
    UpMpd device(string("uuid:") + UUID, xmlfiles, &mpdcli,
1163
               ownqueue?UpMpd::upmpdOwnQueue:UpMpd::upmpdNone);
1139
1164
1140
    LOGDEB("Entering event loop" << endl);
1165
    LOGDEB("Entering event loop" << endl);
1141
1166
1142
    // And forever generate state change events.
1167
    // And forever generate state change events.
1143
    device.eventloop();
1168
    device.eventloop();