|
a/src/upmpd.cxx |
|
b/src/upmpd.cxx |
|
... |
|
... |
39 |
#include "conman.hxx" // for UpMpdConMan
|
39 |
#include "conman.hxx" // for UpMpdConMan
|
40 |
#include "mpdcli.hxx" // for MPDCli
|
40 |
#include "mpdcli.hxx" // for MPDCli
|
41 |
#include "ohinfo.hxx" // for OHInfo
|
41 |
#include "ohinfo.hxx" // for OHInfo
|
42 |
#include "ohplaylist.hxx" // for OHPlaylist
|
42 |
#include "ohplaylist.hxx" // for OHPlaylist
|
43 |
#include "ohproduct.hxx" // for OHProduct
|
43 |
#include "ohproduct.hxx" // for OHProduct
|
|
|
44 |
#include "ohreceiver.hxx"
|
44 |
#include "ohtime.hxx" // for OHTime
|
45 |
#include "ohtime.hxx" // for OHTime
|
45 |
#include "ohvolume.hxx" // for OHVolume
|
46 |
#include "ohvolume.hxx" // for OHVolume
|
46 |
#include "renderctl.hxx" // for UpMpdRenderCtl
|
47 |
#include "renderctl.hxx" // for UpMpdRenderCtl
|
47 |
#include "upmpdutils.hxx" // for path_cat, Pidfile, regsub1, etc
|
48 |
#include "upmpdutils.hxx" // for path_cat, Pidfile, regsub1, etc
|
|
|
49 |
#include "execmd.h"
|
48 |
|
50 |
|
49 |
using namespace std;
|
51 |
using namespace std;
|
50 |
using namespace std::placeholders;
|
52 |
using namespace std::placeholders;
|
51 |
using namespace UPnPP;
|
53 |
using namespace UPnPP;
|
52 |
|
54 |
|
53 |
static const string dfltFriendlyName("UpMpd");
|
55 |
static const string dfltFriendlyName("UpMpd");
|
54 |
string upmpdProtocolInfo;
|
56 |
string upmpdProtocolInfo;
|
|
|
57 |
|
|
|
58 |
// Is scmpdcli (songcast-to-HTTP command) installed ? We only create
|
|
|
59 |
// an OpenHome Receiver service if it is. This is checked when
|
|
|
60 |
// starting up
|
|
|
61 |
static bool has_scmpdcli(false);
|
55 |
|
62 |
|
56 |
static UpnpDevice *dev;
|
63 |
static UpnpDevice *dev;
|
57 |
|
64 |
|
58 |
static void onsig(int)
|
65 |
static void onsig(int)
|
59 |
{
|
66 |
{
|
|
... |
|
... |
91 |
// urn:upnp-org:serviceId:ConnectionManager
|
98 |
// urn:upnp-org:serviceId:ConnectionManager
|
92 |
// The solution would be to have a separate init call to start the
|
99 |
// The solution would be to have a separate init call to start the
|
93 |
// device at the end of the constructor code.
|
100 |
// device at the end of the constructor code.
|
94 |
UpMpd::UpMpd(const string& deviceid, const string& friendlyname,
|
101 |
UpMpd::UpMpd(const string& deviceid, const string& friendlyname,
|
95 |
const unordered_map<string, VDirContent>& files,
|
102 |
const unordered_map<string, VDirContent>& files,
|
96 |
MPDCli *mpdcli, unsigned int opts, const string& cachefn)
|
103 |
MPDCli *mpdcli, unsigned int opts, const string& cachefn,
|
|
|
104 |
int schttpport
|
|
|
105 |
)
|
97 |
: UpnpDevice(deviceid, files), m_mpdcli(mpdcli), m_mpds(0),
|
106 |
: UpnpDevice(deviceid, files), m_mpdcli(mpdcli), m_mpds(0),
|
98 |
m_options(opts),
|
107 |
m_options(opts),
|
99 |
m_mcachefn(cachefn)
|
108 |
m_mcachefn(cachefn)
|
100 |
{
|
109 |
{
|
101 |
// Note: the order is significant here as it will be used when
|
110 |
// Note: the order is significant here as it will be used when
|
|
... |
|
... |
105 |
m_services.push_back(rdctl);
|
114 |
m_services.push_back(rdctl);
|
106 |
UpMpdAVTransport* avt = new UpMpdAVTransport(this);
|
115 |
UpMpdAVTransport* avt = new UpMpdAVTransport(this);
|
107 |
m_services.push_back(avt);
|
116 |
m_services.push_back(avt);
|
108 |
m_services.push_back(new UpMpdConMan(this));
|
117 |
m_services.push_back(new UpMpdConMan(this));
|
109 |
if (m_options & upmpdDoOH) {
|
118 |
if (m_options & upmpdDoOH) {
|
110 |
m_services.push_back(new OHProduct(this, friendlyname));
|
119 |
m_services.push_back(new OHProduct(this, friendlyname, has_scmpdcli));
|
111 |
m_services.push_back(new OHInfo(this));
|
120 |
m_services.push_back(new OHInfo(this));
|
112 |
m_services.push_back(new OHTime(this));
|
121 |
m_services.push_back(new OHTime(this));
|
113 |
m_services.push_back(new OHVolume(this, rdctl));
|
122 |
m_services.push_back(new OHVolume(this, rdctl));
|
114 |
OHPlaylist *ohp = new OHPlaylist(this, rdctl);
|
123 |
OHPlaylist *ohp = new OHPlaylist(this, rdctl);
|
115 |
m_services.push_back(ohp);
|
124 |
m_services.push_back(ohp);
|
116 |
if (avt)
|
125 |
if (avt)
|
117 |
avt->setOHP(ohp);
|
126 |
avt->setOHP(ohp);
|
|
|
127 |
if (has_scmpdcli) {
|
|
|
128 |
m_services.push_back(new OHReceiver(this, ohp, schttpport));
|
|
|
129 |
}
|
118 |
}
|
130 |
}
|
119 |
}
|
131 |
}
|
120 |
|
132 |
|
121 |
UpMpd::~UpMpd()
|
133 |
UpMpd::~UpMpd()
|
122 |
{
|
134 |
{
|
|
... |
|
... |
135 |
/////////////////////////////////////////////////////////////////////
|
147 |
/////////////////////////////////////////////////////////////////////
|
136 |
// Main program
|
148 |
// Main program
|
137 |
|
149 |
|
138 |
#include "conftree.hxx"
|
150 |
#include "conftree.hxx"
|
139 |
|
151 |
|
140 |
static const string ohDesc(
|
152 |
static string ohDesc(
|
141 |
"<service>"
|
153 |
"<service>"
|
142 |
" <serviceType>urn:av-openhome-org:service:Product:1</serviceType>"
|
154 |
" <serviceType>urn:av-openhome-org:service:Product:1</serviceType>"
|
143 |
" <serviceId>urn:av-openhome-org:serviceId:Product</serviceId>"
|
155 |
" <serviceId>urn:av-openhome-org:serviceId:Product</serviceId>"
|
144 |
" <SCPDURL>/OHProduct.xml</SCPDURL>"
|
156 |
" <SCPDURL>/OHProduct.xml</SCPDURL>"
|
145 |
" <controlURL>/ctl/OHProduct</controlURL>"
|
157 |
" <controlURL>/ctl/OHProduct</controlURL>"
|
|
... |
|
... |
170 |
" <serviceType>urn:av-openhome-org:service:Playlist:1</serviceType>"
|
182 |
" <serviceType>urn:av-openhome-org:service:Playlist:1</serviceType>"
|
171 |
" <serviceId>urn:av-openhome-org:serviceId:Playlist</serviceId>"
|
183 |
" <serviceId>urn:av-openhome-org:serviceId:Playlist</serviceId>"
|
172 |
" <SCPDURL>/OHPlaylist.xml</SCPDURL>"
|
184 |
" <SCPDURL>/OHPlaylist.xml</SCPDURL>"
|
173 |
" <controlURL>/ctl/OHPlaylist</controlURL>"
|
185 |
" <controlURL>/ctl/OHPlaylist</controlURL>"
|
174 |
" <eventSubURL>/evt/OHPlaylist</eventSubURL>"
|
186 |
" <eventSubURL>/evt/OHPlaylist</eventSubURL>"
|
|
|
187 |
"</service>"
|
|
|
188 |
);
|
|
|
189 |
static string ohDescReceive(
|
|
|
190 |
"<service>"
|
|
|
191 |
" <serviceType>urn:av-openhome-org:service:Receiver:1</serviceType>"
|
|
|
192 |
" <serviceId>urn:av-openhome-org:serviceId:Receiver</serviceId>"
|
|
|
193 |
" <SCPDURL>/OHReceiver.xml</SCPDURL>"
|
|
|
194 |
" <controlURL>/ctl/OHReceiver</controlURL>"
|
|
|
195 |
" <eventSubURL>/evt/OHReceiver</eventSubURL>"
|
175 |
"</service>"
|
196 |
"</service>"
|
176 |
);
|
197 |
);
|
177 |
|
198 |
|
178 |
static const string iconDesc(
|
199 |
static const string iconDesc(
|
179 |
"<iconList>"
|
200 |
"<iconList>"
|
|
... |
|
... |
316 |
}
|
337 |
}
|
317 |
|
338 |
|
318 |
if (argc != 0)
|
339 |
if (argc != 0)
|
319 |
Usage();
|
340 |
Usage();
|
320 |
|
341 |
|
|
|
342 |
int schttpport(8888);
|
321 |
string iconpath;
|
343 |
string iconpath;
|
322 |
if (!configfile.empty()) {
|
344 |
if (!configfile.empty()) {
|
323 |
ConfSimple config(configfile.c_str(), 1, true);
|
345 |
ConfSimple config(configfile.c_str(), 1, true);
|
324 |
if (!config.ok()) {
|
346 |
if (!config.ok()) {
|
325 |
cerr << "Could not open config: " << configfile << endl;
|
347 |
cerr << "Could not open config: " << configfile << endl;
|
|
... |
|
... |
355 |
}
|
377 |
}
|
356 |
}
|
378 |
}
|
357 |
if (!(op_flags & OPT_P) && config.get("upnpport", value)) {
|
379 |
if (!(op_flags & OPT_P) && config.get("upnpport", value)) {
|
358 |
upport = atoi(value.c_str());
|
380 |
upport = atoi(value.c_str());
|
359 |
}
|
381 |
}
|
|
|
382 |
if (config.get("schttpport", value))
|
|
|
383 |
schttpport = atoi(value.c_str());
|
360 |
}
|
384 |
}
|
361 |
|
385 |
|
362 |
if (Logger::getTheLog(logfilename) == 0) {
|
386 |
if (Logger::getTheLog(logfilename) == 0) {
|
363 |
cerr << "Can't initialize log" << endl;
|
387 |
cerr << "Can't initialize log" << endl;
|
364 |
return 1;
|
388 |
return 1;
|
|
... |
|
... |
456 |
} else {
|
480 |
} else {
|
457 |
break;
|
481 |
break;
|
458 |
}
|
482 |
}
|
459 |
}
|
483 |
}
|
460 |
|
484 |
|
|
|
485 |
// Do we have an scmpdcli command installed (for songcast)?
|
|
|
486 |
string unused;
|
|
|
487 |
has_scmpdcli = ExecCmd::which("scmpdcli", unused);
|
|
|
488 |
|
461 |
// Initialize libupnpp, and check health
|
489 |
// Initialize libupnpp, and check health
|
462 |
LibUPnP *mylib = 0;
|
490 |
LibUPnP *mylib = 0;
|
463 |
string hwaddr;
|
491 |
string hwaddr;
|
464 |
int libretrysecs = 10;
|
492 |
int libretrysecs = 10;
|
465 |
for (;;) {
|
493 |
for (;;) {
|
|
... |
|
... |
497 |
// Create unique ID
|
525 |
// Create unique ID
|
498 |
string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
|
526 |
string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
|
499 |
|
527 |
|
500 |
// Read our XML data to make it available from the virtual directory
|
528 |
// Read our XML data to make it available from the virtual directory
|
501 |
if (openhome) {
|
529 |
if (openhome) {
|
|
|
530 |
if (has_scmpdcli) {
|
|
|
531 |
ohxmlfilenames.push_back("OHReceiver.xml");
|
|
|
532 |
}
|
502 |
xmlfilenames.insert(xmlfilenames.end(), ohxmlfilenames.begin(),
|
533 |
xmlfilenames.insert(xmlfilenames.end(), ohxmlfilenames.begin(),
|
503 |
ohxmlfilenames.end());
|
534 |
ohxmlfilenames.end());
|
504 |
}
|
535 |
}
|
505 |
|
536 |
|
506 |
{
|
537 |
{
|
|
... |
|
... |
530 |
}
|
561 |
}
|
531 |
if (i == 0) {
|
562 |
if (i == 0) {
|
532 |
// Special for description: set UUID and friendlyname
|
563 |
// Special for description: set UUID and friendlyname
|
533 |
data = regsub1("@UUID@", data, UUID);
|
564 |
data = regsub1("@UUID@", data, UUID);
|
534 |
data = regsub1("@FRIENDLYNAME@", data, friendlyname);
|
565 |
data = regsub1("@FRIENDLYNAME@", data, friendlyname);
|
535 |
if (openhome)
|
566 |
if (openhome) {
|
|
|
567 |
if (has_scmpdcli) {
|
|
|
568 |
ohDesc += ohDescReceive;
|
|
|
569 |
}
|
536 |
data = regsub1("@OPENHOME@", data, ohDesc);
|
570 |
data = regsub1("@OPENHOME@", data, ohDesc);
|
537 |
else
|
571 |
} else {
|
538 |
data = regsub1("@OPENHOME@", data, "");
|
572 |
data = regsub1("@OPENHOME@", data, "");
|
|
|
573 |
}
|
539 |
if (!icondata.empty())
|
574 |
if (!icondata.empty())
|
540 |
data = regsub1("@ICONLIST@", data, iconDesc);
|
575 |
data = regsub1("@ICONLIST@", data, iconDesc);
|
541 |
else
|
576 |
else
|
542 |
data = regsub1("@ICONLIST@", data, "");
|
577 |
data = regsub1("@ICONLIST@", data, "");
|
543 |
}
|
578 |
}
|
|
... |
|
... |
558 |
if (ohmetapersist)
|
593 |
if (ohmetapersist)
|
559 |
options |= UpMpd::upmpdOhMetaPersist;
|
594 |
options |= UpMpd::upmpdOhMetaPersist;
|
560 |
|
595 |
|
561 |
// Initialize the UPnP device object.
|
596 |
// Initialize the UPnP device object.
|
562 |
UpMpd device(string("uuid:") + UUID, friendlyname,
|
597 |
UpMpd device(string("uuid:") + UUID, friendlyname,
|
563 |
files, mpdclip, options, mcfn);
|
598 |
files, mpdclip, options, mcfn, schttpport);
|
564 |
dev = &device;
|
599 |
dev = &device;
|
565 |
|
600 |
|
566 |
// And forever generate state change events.
|
601 |
// And forever generate state change events.
|
567 |
LOGDEB("Entering event loop" << endl);
|
602 |
LOGDEB("Entering event loop" << endl);
|
568 |
setupsigs();
|
603 |
setupsigs();
|