--- a/src/main.cxx
+++ b/src/main.cxx
@@ -51,19 +51,20 @@
static char *thisprog;
static int op_flags;
-#define OPT_MOINS 0x1
-#define OPT_h 0x2
-#define OPT_p 0x4
-#define OPT_d 0x8
-#define OPT_D 0x10
-#define OPT_c 0x20
-#define OPT_l 0x40
-#define OPT_f 0x80
-#define OPT_q 0x100
-#define OPT_i 0x200
-#define OPT_P 0x400
-#define OPT_O 0x800
-#define OPT_v 0x1000
+#define OPT_MOINS 0x1
+#define OPT_D 0x2
+#define OPT_O 0x4
+#define OPT_P 0x8
+#define OPT_c 0x10
+#define OPT_d 0x20
+#define OPT_f 0x40
+#define OPT_h 0x80
+#define OPT_i 0x100
+#define OPT_l 0x200
+#define OPT_m 0x400
+#define OPT_p 0x800
+#define OPT_q 0x1000
+#define OPT_v 0x2000
static const char usage[] =
"-c configfile \t configuration file to use\n"
@@ -78,8 +79,12 @@
"-P upport \t specify port number to be used for UPnP\n"
"-O 0|1\t decide if we run and export the OpenHome services\n"
"-v \tprint version info\n"
+ "-m <0|1|2|3> media server mode "
+ "(default, forked|only renderer|only media|combined)\n"
"\n"
;
+
+enum MSMode {Forked, RdrOnly, MSOnly, Combined};
static void
versionInfo(FILE *fp)
@@ -162,6 +167,11 @@
int main(int argc, char *argv[])
{
+ vector<string> savedargs;
+ for (int i = 0; i < argc; i++) {
+ savedargs.push_back(argv[i]);
+ }
+
// Path for the sc2mpd command, or empty
string sc2mpdpath;
@@ -190,7 +200,10 @@
string iface;
unsigned short upport = 0;
string upnpip;
-
+ int msm = 0;
+ bool inprocessms = false;
+ bool msonly = false;
+
const char *cp;
if ((cp = getenv("UPMPD_HOST")))
mpdhost = cp;
@@ -226,6 +239,8 @@
iface = *(++argv); argc--; goto b1;
case 'l': op_flags |= OPT_l; if (argc < 2) Usage();
loglevel = atoi(*(++argv)); argc--; goto b1;
+ case 'm': op_flags |= OPT_m; if (argc < 2) Usage();
+ msm = atoi(*(++argv)); argc--; goto b1;
case 'O': {
op_flags |= OPT_O;
if (argc < 2) Usage();
@@ -247,9 +262,11 @@
b1: argc--; argv++;
}
- if (argc != 0)
+ if (argc != 0 || msm < 0 || msm > 3) {
Usage();
-
+ }
+ MSMode msmode = MSMode(msm);
+
UpMpd::Options opts;
string cachedir;
@@ -346,8 +363,27 @@
if (g_config->get("scsendermpdport", value))
sendermpdport = atoi(value.c_str());
+ // If a streaming service is enabled (only tidal for now), we
+ // need a Media Server. The way we implement it depends on the
+ // command line option:
if (g_config->hasNameAnywhere("tidaluser")) {
enableMediaServer = true;
+ switch (msmode) {
+ case MSOnly:
+ inprocessms = true;
+ msonly = true;
+ break;
+ case Combined:
+ inprocessms = true;
+ msonly = false;
+ break;
+ case RdrOnly:
+ case Forked:
+ default:
+ inprocessms = false;
+ msonly = false;
+ break;
+ }
}
}
if (Logger::getTheLog(logfilename) == 0) {
@@ -550,12 +586,18 @@
// Create unique ID
string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
+ // If running as mediaserver only, make sure we don't conflict
+ // with a possible renderer
+ if (msonly) {
+ pidfilename = pidfilename + "-ms";
+ }
+
// Initialize the data we serve through HTTP (device and service
// descriptions, icons, presentation page, etc.)
unordered_map<string, VDirContent> files;
if (!initHttpFs(files, g_datadir, UUID, friendlyname, enableAV, enableOH,
- !senderpath.empty(), enableL16, enableMediaServer,
- iconpath, presentationhtml)) {
+ !senderpath.empty(), enableL16, inprocessms,
+ msonly, iconpath, presentationhtml)) {
exit(1);
}
@@ -579,25 +621,61 @@
opts.options |= UpMpd::upmpdNoAV;
// Initialize the UPnP root device object.
- UpMpd device(string("uuid:") + UUID, friendlyname, ohProductDesc,
- files, mpdclip, opts);
- dev = &device;
-
- MediaServer *devmedia = nullptr;
- if (enableMediaServer) {
+ UpMpd *mediarenderer = nullptr;
+ if (!msonly) {
+ mediarenderer = new UpMpd(string("uuid:") + UUID, friendlyname,
+ ohProductDesc, files, mpdclip, opts);
+ }
+
+ MediaServer *mediaserver = nullptr;
+ unordered_map<string, VDirContent> emptyfiles =
+ unordered_map<string, VDirContent>();
+ unordered_map<string, VDirContent> *msfiles = &emptyfiles;
+ vector<string> args{"-m", "2"};
+ ExecCmd cmd;
+
+ if (inprocessms) {
+ if (op_flags & OPT_m) {
+ msfiles = &files;
+ }
// Create the Media Server embedded device object. There needs
// be no reference to the root object because there can be
// only one (libupnp restriction)
- devmedia = new MediaServer(string("uuid:") + uuidMediaServer(UUID),
- friendlyNameMediaServer(friendlyname));
- }
- UPMPD_UNUSED(devmedia);
+ mediaserver = new MediaServer(string("uuid:") + uuidMediaServer(UUID),
+ friendlyNameMediaServer(friendlyname),
+ *msfiles);
+ } else if (enableMediaServer) {
+ // Fork process for media server, replacing whatever -m option
+ // was given with -m 2 (ms only)
+ string cmdpath(savedargs[0]);
+ for (unsigned int i = 1; i < savedargs.size(); i++) {
+ string sa(savedargs[i]);
+ if (sa[sa.length()-1] == 'm') {
+ sa = sa.substr(0, sa.length()-1);
+ if (int(i) == argc -1)
+ Usage();
+ i++;
+ }
+ if (!sa.empty() && sa.compare("-")) {
+ args.push_back(sa);
+ }
+ }
+ cmd.startExec(cmdpath, args, false, false);
+ }
+ UPMPD_UNUSED(mediaserver);
// And forever generate state change events.
LOGDEB("Entering event loop" << endl);
setupsigs();
- device.eventloop();
+ if (msonly) {
+ dev = mediaserver;
+ LOGDEB("Media server event loop" << endl);
+ mediaserver->eventloop();
+ } else {
+ LOGDEB("Renderer event loop" << endl);
+ dev = mediarenderer;
+ mediarenderer->eventloop();
+ }
LOGDEB("Event loop returned" << endl);
-
return 0;
}