|
a/upmpd/upmpd.cxx |
|
b/upmpd/upmpd.cxx |
|
... |
|
... |
36 |
#include "mpdcli.hxx"
|
36 |
#include "mpdcli.hxx"
|
37 |
#include "upmpdutils.hxx"
|
37 |
#include "upmpdutils.hxx"
|
38 |
|
38 |
|
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 3 services
|
42 |
class UpMpd : public UpnpDevice {
|
42 |
class UpMpd : public UpnpDevice {
|
43 |
public:
|
43 |
public:
|
44 |
enum Options {
|
44 |
enum Options {
|
45 |
upmpdNone,
|
45 |
upmpdNone,
|
46 |
upmpdOwnQueue, // The MPD belongs to us, we shall clear it as we like
|
46 |
upmpdOwnQueue, // The MPD belongs to us, we shall clear it as we like
|
|
... |
|
... |
74 |
int seqcontrol(const SoapArgs& sc, SoapData& data, int what);
|
74 |
int seqcontrol(const SoapArgs& sc, SoapData& data, int what);
|
75 |
virtual bool getEventDataTransport(bool all,
|
75 |
virtual bool getEventDataTransport(bool all,
|
76 |
std::vector<std::string>& names,
|
76 |
std::vector<std::string>& names,
|
77 |
std::vector<std::string>& values);
|
77 |
std::vector<std::string>& values);
|
78 |
|
78 |
|
|
|
79 |
// Connection Manager
|
|
|
80 |
int getCurrentConnectionIDs(const SoapArgs& sc, SoapData& data);
|
|
|
81 |
int getCurrentConnectionInfo(const SoapArgs& sc, SoapData& data);
|
|
|
82 |
int getProtocolInfo(const SoapArgs& sc, SoapData& data);
|
|
|
83 |
virtual bool getEventDataCM(bool all, std::vector<std::string>& names,
|
|
|
84 |
std::vector<std::string>& values);
|
|
|
85 |
|
79 |
// Re-implemented from the base class and shared by both services
|
86 |
// Re-implemented from the base class and shared by all services
|
80 |
virtual bool getEventData(bool all, const string& serviceid,
|
87 |
virtual bool getEventData(bool all, const string& serviceid,
|
81 |
std::vector<std::string>& names,
|
88 |
std::vector<std::string>& names,
|
82 |
std::vector<std::string>& values);
|
89 |
std::vector<std::string>& values);
|
83 |
|
90 |
|
84 |
private:
|
91 |
private:
|
85 |
MPDCli *m_mpdcli;
|
92 |
MPDCli *m_mpdcli;
|
|
|
93 |
|
|
|
94 |
string m_curMetadata;
|
|
|
95 |
string m_nextMetadata;
|
86 |
|
96 |
|
87 |
// State variable storage
|
97 |
// State variable storage
|
88 |
unordered_map<string, string> m_rdstate;
|
98 |
unordered_map<string, string> m_rdstate;
|
89 |
unordered_map<string, string> m_tpstate;
|
99 |
unordered_map<string, string> m_tpstate;
|
90 |
|
100 |
|
|
... |
|
... |
103 |
int m_options;
|
113 |
int m_options;
|
104 |
};
|
114 |
};
|
105 |
|
115 |
|
106 |
static const string serviceIdRender("urn:upnp-org:serviceId:RenderingControl");
|
116 |
static const string serviceIdRender("urn:upnp-org:serviceId:RenderingControl");
|
107 |
static const string serviceIdTransport("urn:upnp-org:serviceId:AVTransport");
|
117 |
static const string serviceIdTransport("urn:upnp-org:serviceId:AVTransport");
|
|
|
118 |
static const string serviceIdCM("urn:upnp-org:serviceId:ConnectionManager");
|
108 |
|
119 |
|
109 |
UpMpd::UpMpd(const string& deviceid,
|
120 |
UpMpd::UpMpd(const string& deviceid,
|
110 |
const unordered_map<string, string>& xmlfiles,
|
121 |
const unordered_map<string, string>& xmlfiles,
|
111 |
MPDCli *mpdcli, Options opts)
|
122 |
MPDCli *mpdcli, Options opts)
|
112 |
: UpnpDevice(deviceid, xmlfiles), m_mpdcli(mpdcli), m_desiredvolume(-1),
|
123 |
: UpnpDevice(deviceid, xmlfiles), m_mpdcli(mpdcli), m_desiredvolume(-1),
|
|
... |
|
... |
187 |
{ auto bound = bind(&UpMpd::seqcontrol, this, _1, _2, 0);
|
198 |
{ auto bound = bind(&UpMpd::seqcontrol, this, _1, _2, 0);
|
188 |
addActionMapping("Next", bound);
|
199 |
addActionMapping("Next", bound);
|
189 |
}
|
200 |
}
|
190 |
{ auto bound = bind(&UpMpd::seqcontrol, this, _1, _2, 1);
|
201 |
{ auto bound = bind(&UpMpd::seqcontrol, this, _1, _2, 1);
|
191 |
addActionMapping("Previous", bound);
|
202 |
addActionMapping("Previous", bound);
|
|
|
203 |
}
|
|
|
204 |
|
|
|
205 |
addServiceType(serviceIdCM,
|
|
|
206 |
"urn:schemas-upnp-org:service:ConnectionManager:1");
|
|
|
207 |
{ auto bound = bind(&UpMpd::getCurrentConnectionIDs, this, _1, _2);
|
|
|
208 |
addActionMapping("GetCurrentConnectionIDs", bound);
|
|
|
209 |
}
|
|
|
210 |
{ auto bound = bind(&UpMpd::getCurrentConnectionInfo, this, _1, _2);
|
|
|
211 |
addActionMapping("GetCurrentConnectionInfo", bound);
|
|
|
212 |
}
|
|
|
213 |
{ auto bound = bind(&UpMpd::getProtocolInfo, this, _1, _2);
|
|
|
214 |
addActionMapping("GetProtocolInfo", bound);
|
192 |
}
|
215 |
}
|
193 |
}
|
216 |
}
|
194 |
|
217 |
|
195 |
// This is called by the polling loop at regular intervals, or when
|
218 |
// This is called by the polling loop at regular intervals, or when
|
196 |
// triggered, to retrieve changed state variables for each of the
|
219 |
// triggered, to retrieve changed state variables for each of the
|
|
... |
|
... |
207 |
{
|
230 |
{
|
208 |
if (!serviceid.compare(serviceIdRender)) {
|
231 |
if (!serviceid.compare(serviceIdRender)) {
|
209 |
return getEventDataRendering(all, names, values);
|
232 |
return getEventDataRendering(all, names, values);
|
210 |
} else if (!serviceid.compare(serviceIdTransport)) {
|
233 |
} else if (!serviceid.compare(serviceIdTransport)) {
|
211 |
return getEventDataTransport(all, names, values);
|
234 |
return getEventDataTransport(all, names, values);
|
|
|
235 |
} else if (!serviceid.compare(serviceIdCM)) {
|
|
|
236 |
return getEventDataCM(all, names, values);
|
212 |
} else {
|
237 |
} else {
|
213 |
LOGERR("UpMpd::getEventData: servid? [" << serviceid << "]" << endl);
|
238 |
LOGERR("UpMpd::getEventData: servid? [" << serviceid << "]" << endl);
|
214 |
return UPNP_E_INVALID_PARAM;
|
239 |
return UPNP_E_INVALID_PARAM;
|
215 |
}
|
240 |
}
|
216 |
}
|
241 |
}
|
|
... |
|
... |
546 |
status["CurrentMediaDuration"] = is_song?
|
571 |
status["CurrentMediaDuration"] = is_song?
|
547 |
upnpduration(mpds.songlenms):"00:00:00";
|
572 |
upnpduration(mpds.songlenms):"00:00:00";
|
548 |
status["CurrentTrackDuration"] = is_song?
|
573 |
status["CurrentTrackDuration"] = is_song?
|
549 |
upnpduration(mpds.songlenms):"00:00:00";
|
574 |
upnpduration(mpds.songlenms):"00:00:00";
|
550 |
status["AVTransportURI"] = uri;
|
575 |
status["AVTransportURI"] = uri;
|
|
|
576 |
//status["AVTransportURIMetaData"] = is_song ? m_curMetadata : "";
|
551 |
status["AVTransportURIMetaData"] = is_song?didlmake(mpds) : "";
|
577 |
status["AVTransportURIMetaData"] = is_song ? didlmake(mpds) : "";
|
552 |
status["RelativeTimePosition"] = is_song?
|
578 |
status["RelativeTimePosition"] = is_song?
|
553 |
upnpduration(mpds.songelapsedms):"0:00:00";
|
579 |
upnpduration(mpds.songelapsedms):"0:00:00";
|
554 |
status["AbsoluteTimePosition"] = is_song?
|
580 |
status["AbsoluteTimePosition"] = is_song?
|
555 |
upnpduration(mpds.songelapsedms) : "0:00:00";
|
581 |
upnpduration(mpds.songelapsedms) : "0:00:00";
|
556 |
|
582 |
|
557 |
status["NextAVTransportURI"] = mapget(mpds.nextsong, "uri");
|
583 |
status["NextAVTransportURI"] = mapget(mpds.nextsong, "uri");
|
|
|
584 |
//status["NextAVTransportURIMetaData"] = is_song ? m_nextMetadata : "";
|
558 |
status["NextAVTransportURIMetaData"] = is_song?didlmake(mpds, true) : "";
|
585 |
status["NextAVTransportURIMetaData"] = is_song ? didlmake(mpds, true) : "";
|
559 |
|
586 |
|
560 |
status["PlaybackStorageMedium"] = playmedium;
|
587 |
status["PlaybackStorageMedium"] = playmedium;
|
561 |
status["PossiblePlaybackStorageMedium"] = "HDD,NETWORK";
|
588 |
status["PossiblePlaybackStorageMedium"] = "HDD,NETWORK";
|
562 |
status["RecordStorageMedium"] = "NOT_IMPLEMENTED";
|
589 |
status["RecordStorageMedium"] = "NOT_IMPLEMENTED";
|
563 |
status["RelativeCounterPosition"] = "0";
|
590 |
status["RelativeCounterPosition"] = "0";
|
|
... |
|
... |
632 |
string metadata;
|
659 |
string metadata;
|
633 |
it = setnext? sc.args.find("NextURIMetaData") :
|
660 |
it = setnext? sc.args.find("NextURIMetaData") :
|
634 |
sc.args.find("CurrentURIMetaData");
|
661 |
sc.args.find("CurrentURIMetaData");
|
635 |
if (it != sc.args.end())
|
662 |
if (it != sc.args.end())
|
636 |
metadata = it->second;
|
663 |
metadata = it->second;
|
|
|
664 |
//cerr << "SetTransport: setnext " << setnext << " metadata[" << metadata <<
|
|
|
665 |
// "]" << endl;
|
637 |
|
666 |
|
638 |
if ((m_options & upmpdOwnQueue) && !setnext) {
|
667 |
if ((m_options & upmpdOwnQueue) && !setnext) {
|
639 |
// If we own the queue, just clear it before setting the
|
668 |
// If we own the queue, just clear it before setting the
|
640 |
// track. Else it's difficult to impossible to prevent it
|
669 |
// track. Else it's difficult to impossible to prevent it
|
641 |
// from growing if upmpdcli restarts. If the option is not set, the
|
670 |
// from growing if upmpdcli restarts. If the option is not set, the
|
|
... |
|
... |
663 |
}
|
692 |
}
|
664 |
int songid;
|
693 |
int songid;
|
665 |
if ((songid = m_mpdcli->insert(uri, setnext?curpos+1:curpos)) < 0) {
|
694 |
if ((songid = m_mpdcli->insert(uri, setnext?curpos+1:curpos)) < 0) {
|
666 |
return UPNP_E_INTERNAL_ERROR;
|
695 |
return UPNP_E_INTERNAL_ERROR;
|
667 |
}
|
696 |
}
|
|
|
697 |
if (setnext)
|
|
|
698 |
m_nextMetadata = metadata;
|
|
|
699 |
else
|
|
|
700 |
m_curMetadata = metadata;
|
|
|
701 |
|
668 |
if (!setnext) {
|
702 |
if (!setnext) {
|
669 |
MpdStatus::State st = mpds.state;
|
703 |
MpdStatus::State st = mpds.state;
|
670 |
// Have to tell mpd which track to play, else it will keep on
|
704 |
// Have to tell mpd which track to play, else it will keep on
|
671 |
// the previous despite of the insertion. The UPnP docs say
|
705 |
// the previous despite of the insertion. The UPnP docs say
|
672 |
// that setAVTransportURI should not change the transport
|
706 |
// that setAVTransportURI should not change the transport
|
|
... |
|
... |
970 |
|
1004 |
|
971 |
loopWakeup();
|
1005 |
loopWakeup();
|
972 |
return m_mpdcli->seek(abs_seconds) ? UPNP_E_SUCCESS : UPNP_E_INTERNAL_ERROR;
|
1006 |
return m_mpdcli->seek(abs_seconds) ? UPNP_E_SUCCESS : UPNP_E_INTERNAL_ERROR;
|
973 |
}
|
1007 |
}
|
974 |
|
1008 |
|
|
|
1009 |
///////////////// ConnectionManager methods
|
|
|
1010 |
|
|
|
1011 |
// "http-get:*:audio/mpeg:DLNA.ORG_PN=MP3,"
|
|
|
1012 |
// "http-get:*:audio/L16:DLNA.ORG_PN=LPCM,"
|
|
|
1013 |
// "http-get:*:audio/x-flac:DLNA.ORG_PN=FLAC"
|
|
|
1014 |
static const string
|
|
|
1015 |
myProtocolInfo(
|
|
|
1016 |
"http-get:*:audio/wav:*,"
|
|
|
1017 |
"http-get:*:audio/wave:*,"
|
|
|
1018 |
"http-get:*:audio/x-wav:*,"
|
|
|
1019 |
"http-get:*:audio/mpeg:*,"
|
|
|
1020 |
"http-get:*:audio/x-mpeg:*,"
|
|
|
1021 |
"http-get:*:audio/mp1:*,"
|
|
|
1022 |
"http-get:*:audio/aac:*,"
|
|
|
1023 |
"http-get:*:audio/flac:*,"
|
|
|
1024 |
"http-get:*:audio/x-flac:*,"
|
|
|
1025 |
"http-get:*:audio/m4a:*,"
|
|
|
1026 |
"http-get:*:audio/mp4:*,"
|
|
|
1027 |
"http-get:*:audio/x-m4a:*,"
|
|
|
1028 |
"http-get:*:audio/vorbis:*,"
|
|
|
1029 |
"http-get:*:audio/ogg:*,"
|
|
|
1030 |
"http-get:*:audio/x-ogg:*,"
|
|
|
1031 |
"http-get:*:audio/x-scpls:*,"
|
|
|
1032 |
"http-get:*:audio/L16;rate=11025;channels=1:*,"
|
|
|
1033 |
"http-get:*:audio/L16;rate=22050;channels=1:*,"
|
|
|
1034 |
"http-get:*:audio/L16;rate=44100;channels=1:*,"
|
|
|
1035 |
"http-get:*:audio/L16;rate=48000;channels=1:*,"
|
|
|
1036 |
"http-get:*:audio/L16;rate=88200;channels=1:*,"
|
|
|
1037 |
"http-get:*:audio/L16;rate=96000;channels=1:*,"
|
|
|
1038 |
"http-get:*:audio/L16;rate=176400;channels=1:*,"
|
|
|
1039 |
"http-get:*:audio/L16;rate=192000;channels=1:*,"
|
|
|
1040 |
"http-get:*:audio/L16;rate=11025;channels=2:*,"
|
|
|
1041 |
"http-get:*:audio/L16;rate=22050;channels=2:*,"
|
|
|
1042 |
"http-get:*:audio/L16;rate=44100;channels=2:*,"
|
|
|
1043 |
"http-get:*:audio/L16;rate=48000;channels=2:*,"
|
|
|
1044 |
"http-get:*:audio/L16;rate=88200;channels=2:*,"
|
|
|
1045 |
"http-get:*:audio/L16;rate=96000;channels=2:*,"
|
|
|
1046 |
"http-get:*:audio/L16;rate=176400;channels=2:*,"
|
|
|
1047 |
"http-get:*:audio/L16;rate=192000;channels=2:*"
|
|
|
1048 |
);
|
|
|
1049 |
|
|
|
1050 |
bool UpMpd::getEventDataCM(bool all, std::vector<std::string>& names,
|
|
|
1051 |
std::vector<std::string>& values)
|
|
|
1052 |
{
|
|
|
1053 |
//LOGDEB("UpMpd:getEventDataCM" << endl);
|
|
|
1054 |
|
|
|
1055 |
// Our data never changes, so if this is not an unconditional request,
|
|
|
1056 |
// we return nothing.
|
|
|
1057 |
if (all) {
|
|
|
1058 |
names.push_back("SinkProtocolInfo");
|
|
|
1059 |
values.push_back(myProtocolInfo);
|
|
|
1060 |
}
|
|
|
1061 |
return true;
|
|
|
1062 |
}
|
|
|
1063 |
|
|
|
1064 |
int UpMpd::getCurrentConnectionIDs(const SoapArgs& sc, SoapData& data)
|
|
|
1065 |
{
|
|
|
1066 |
LOGDEB("UpMpd:getCurrentConnectionIDs" << endl);
|
|
|
1067 |
data.addarg("ConnectionIDs", "0");
|
|
|
1068 |
return UPNP_E_SUCCESS;
|
|
|
1069 |
}
|
|
|
1070 |
|
|
|
1071 |
int UpMpd::getCurrentConnectionInfo(const SoapArgs& sc, SoapData& data)
|
|
|
1072 |
{
|
|
|
1073 |
LOGDEB("UpMpd:getCurrentConnectionInfo" << endl);
|
|
|
1074 |
map<string, string>::const_iterator it;
|
|
|
1075 |
it = sc.args.find("ConnectionID");
|
|
|
1076 |
if (it == sc.args.end() || it->second.empty()) {
|
|
|
1077 |
return UPNP_E_INVALID_PARAM;
|
|
|
1078 |
}
|
|
|
1079 |
if (it->second.compare("0")) {
|
|
|
1080 |
return UPNP_E_INVALID_PARAM;
|
|
|
1081 |
}
|
|
|
1082 |
|
|
|
1083 |
data.addarg("RcsID", "0");
|
|
|
1084 |
data.addarg("AVTransportID", "0");
|
|
|
1085 |
data.addarg("ProtocolInfo", "");
|
|
|
1086 |
data.addarg("PeerConnectionManager", "");
|
|
|
1087 |
data.addarg("PeerConnectionID", "-1");
|
|
|
1088 |
data.addarg("Direction", "Input");
|
|
|
1089 |
data.addarg("Status", "Unknown");
|
|
|
1090 |
|
|
|
1091 |
return UPNP_E_SUCCESS;
|
|
|
1092 |
}
|
|
|
1093 |
|
|
|
1094 |
int UpMpd::getProtocolInfo(const SoapArgs& sc, SoapData& data)
|
|
|
1095 |
{
|
|
|
1096 |
LOGDEB("UpMpd:getProtocolInfo" << endl);
|
|
|
1097 |
data.addarg("Source", "");
|
|
|
1098 |
data.addarg("Sink", myProtocolInfo);
|
|
|
1099 |
|
|
|
1100 |
return UPNP_E_SUCCESS;
|
|
|
1101 |
}
|
975 |
|
1102 |
|
976 |
/////////////////////////////////////////////////////////////////////
|
1103 |
/////////////////////////////////////////////////////////////////////
|
977 |
// Main program
|
1104 |
// Main program
|
978 |
|
1105 |
|
979 |
#include "conftree.hxx"
|
1106 |
#include "conftree.hxx"
|
|
... |
|
... |
1011 |
|
1138 |
|
1012 |
static string myDeviceUUID;
|
1139 |
static string myDeviceUUID;
|
1013 |
|
1140 |
|
1014 |
static string datadir(DATADIR "/");
|
1141 |
static string datadir(DATADIR "/");
|
1015 |
static string configdir(CONFIGDIR "/");
|
1142 |
static string configdir(CONFIGDIR "/");
|
|
|
1143 |
|
|
|
1144 |
// Our XML description data. !Keep description.xml first!
|
|
|
1145 |
static const char *xmlfilenames[] = {/* keep first */ "description.xml",
|
|
|
1146 |
"RenderingControl.xml", "AVTransport.xml", "ConnectionManager.xml"};
|
|
|
1147 |
|
|
|
1148 |
static const int xmlfilenamescnt = sizeof(xmlfilenames) / sizeof(char *);
|
1016 |
|
1149 |
|
1017 |
int main(int argc, char *argv[])
|
1150 |
int main(int argc, char *argv[])
|
1018 |
{
|
1151 |
{
|
1019 |
string mpdhost("localhost");
|
1152 |
string mpdhost("localhost");
|
1020 |
int mpdport = 6600;
|
1153 |
int mpdport = 6600;
|
|
... |
|
... |
1123 |
}
|
1256 |
}
|
1124 |
|
1257 |
|
1125 |
// Create unique ID
|
1258 |
// Create unique ID
|
1126 |
string UUID = LibUPnP::makeDevUUID(friendlyname);
|
1259 |
string UUID = LibUPnP::makeDevUUID(friendlyname);
|
1127 |
|
1260 |
|
1128 |
// Read our XML data.
|
1261 |
// Read our XML data to make it available from the virtual directory
|
1129 |
string reason;
|
1262 |
string reason;
|
1130 |
|
|
|
1131 |
string description;
|
|
|
1132 |
string filename = datadir + "description.xml";
|
|
|
1133 |
if (!file_to_string(filename, description, &reason)) {
|
|
|
1134 |
LOGFAT("Failed reading " << filename << " : " << reason << endl);
|
|
|
1135 |
return 1;
|
|
|
1136 |
}
|
|
|
1137 |
// Update device description with UUID and friendlyname
|
|
|
1138 |
description = regsub1("@UUID@", description, UUID);
|
|
|
1139 |
description = regsub1("@FRIENDLYNAME@", description, friendlyname);
|
|
|
1140 |
|
|
|
1141 |
string rdc_scdp;
|
|
|
1142 |
filename = datadir + "RenderingControl.xml";
|
|
|
1143 |
if (!file_to_string(filename, rdc_scdp, &reason)) {
|
|
|
1144 |
LOGFAT("Failed reading " << filename << " : " << reason << endl);
|
|
|
1145 |
return 1;
|
|
|
1146 |
}
|
|
|
1147 |
|
|
|
1148 |
string avt_scdp;
|
|
|
1149 |
filename = datadir + "AVTransport.xml";
|
|
|
1150 |
if (!file_to_string(filename, avt_scdp, &reason)) {
|
|
|
1151 |
LOGFAT("Failed reading " << filename << " : " << reason << endl);
|
|
|
1152 |
return 1;
|
|
|
1153 |
}
|
|
|
1154 |
|
|
|
1155 |
// List the XML files to be served through http (all will live in '/')
|
|
|
1156 |
unordered_map<string, string> xmlfiles;
|
1263 |
unordered_map<string, string> xmlfiles;
|
1157 |
xmlfiles["description.xml"] = description;
|
1264 |
for (int i = 0; i < xmlfilenamescnt; i++) {
|
1158 |
xmlfiles["RenderingControl.xml"] = rdc_scdp;
|
1265 |
string filename = path_cat(datadir, xmlfilenames[i]);
|
1159 |
xmlfiles["AVTransport.xml"] = avt_scdp;
|
1266 |
string data;
|
|
|
1267 |
if (!file_to_string(filename, data, &reason)) {
|
|
|
1268 |
LOGFAT("Failed reading " << filename << " : " << reason << endl);
|
|
|
1269 |
return 1;
|
|
|
1270 |
}
|
|
|
1271 |
if (i == 0) {
|
|
|
1272 |
// Special for description: set UUID and friendlyname
|
|
|
1273 |
data = regsub1("@UUID@", data, UUID);
|
|
|
1274 |
data = regsub1("@FRIENDLYNAME@", data, friendlyname);
|
|
|
1275 |
}
|
|
|
1276 |
xmlfiles[xmlfilenames[i]] = data;
|
|
|
1277 |
}
|
1160 |
|
1278 |
|
1161 |
// Initialize the UPnP device object.
|
1279 |
// Initialize the UPnP device object.
|
1162 |
UpMpd device(string("uuid:") + UUID, xmlfiles, &mpdcli,
|
1280 |
UpMpd device(string("uuid:") + UUID, xmlfiles, &mpdcli,
|
1163 |
ownqueue?UpMpd::upmpdOwnQueue:UpMpd::upmpdNone);
|
1281 |
ownqueue ? UpMpd::upmpdOwnQueue : UpMpd::upmpdNone);
|
1164 |
|
1282 |
|
|
|
1283 |
// And forever generate state change events.
|
1165 |
LOGDEB("Entering event loop" << endl);
|
1284 |
LOGDEB("Entering event loop" << endl);
|
1166 |
|
|
|
1167 |
// And forever generate state change events.
|
|
|
1168 |
device.eventloop();
|
1285 |
device.eventloop();
|
1169 |
|
1286 |
|
1170 |
return 0;
|
1287 |
return 0;
|
1171 |
}
|
1288 |
}
|
1172 |
|
1289 |
|