Switch to unified view

a/src/main.cxx b/src/main.cxx
...
...
41
#include "conftree.h"
41
#include "conftree.h"
42
#include "mpdcli.hxx"
42
#include "mpdcli.hxx"
43
#include "upmpd.hxx"
43
#include "upmpd.hxx"
44
#include "mediaserver/mediaserver.hxx"
44
#include "mediaserver/mediaserver.hxx"
45
#include "mediaserver/contentdirectory.hxx"
45
#include "mediaserver/contentdirectory.hxx"
46
#include "httpfs.hxx"
47
#include "upmpdutils.hxx"
46
#include "upmpdutils.hxx"
48
#include "pathut.h"
47
#include "pathut.h"
48
#include "readfile.h"
49
49
50
using namespace std;
50
using namespace std;
51
using namespace UPnPP;
51
using namespace UPnPP;
52
52
53
static char *thisprog;
53
static char *thisprog;
...
...
79
    "-q 0|1\t if set, we own the mpd queue, else avoid clearing it whenever we feel like it\n"
79
    "-q 0|1\t if set, we own the mpd queue, else avoid clearing it whenever we feel like it\n"
80
    "-i iface    \t specify network interface name to be used for UPnP\n"
80
    "-i iface    \t specify network interface name to be used for UPnP\n"
81
    "-P upport    \t specify port number to be used for UPnP\n"
81
    "-P upport    \t specify port number to be used for UPnP\n"
82
    "-O 0|1\t decide if we run and export the OpenHome services\n"
82
    "-O 0|1\t decide if we run and export the OpenHome services\n"
83
    "-v      \tprint version info\n"
83
    "-v      \tprint version info\n"
84
    "-m <0|1|2|3> media server mode "
84
    "-m <0|1|2|3|4> media server mode "
85
    "(default, forked|only renderer|only media|combined)\n"
85
    "(default, forked|only renderer|only media|combined/embedded|combined/multidev)\n"
86
    "\n"
86
    "\n"
87
    ;
87
    ;
88
88
89
// We can implement a Media Server in addition to the Renderer, for
89
// We can implement a Media Server in addition to the Renderer, for
90
// accessing streaming services. This can happen in several modes. In
90
// accessing streaming services. This can happen in several modes. In
...
...
93
// All this complication is needed because libupnp does not support
93
// All this complication is needed because libupnp does not support
94
// having several root devices in a single process, and because many
94
// having several root devices in a single process, and because many
95
// control points are confused by embedded devices.
95
// control points are confused by embedded devices.
96
// 
96
// 
97
// - -m 0, default, Forked: this is for the main process, which will
97
// - -m 0, default, Forked: this is for the main process, which will
98
//   implement a Media Renderer device, and, if needed, fork/exec the
98
//    implement a Media Renderer device, and, if needed, fork/exec the
99
//   Media Server (with option -m 2)
99
//    Media Server (with option -m 2)
100
// - -m 1, RdrOnly: for the main instance: be a Renderer, do not start the
100
// - -m 1, RdrOnly: for the main instance: be a Renderer, do not start the
101
//   Media Server even if the configuration indicates it is needed
101
//    Media Server even if the configuration indicates it is needed
102
//   (this is not used in normal situations, just edit the config
102
//    (this is not used in normal situations, just edit the config
103
//   instead!)
103
//    instead!)
104
// - -m 2, MSOnly Media Server only, this is for the process forked/execed
104
// - -m 2, MSOnly Media Server only, this is for the process forked/execed
105
//   by a main Renderer process, or a standalone Media Server.
105
//    by a main Renderer process, or a standalone Media Server.
106
// - -m 3, Combined: for the main process: implement the Media Server
106
// - -m 3, Combined: for the main process: implement the Media Server
107
//   as an embedded device. This works just fine with, for example,
107
//    as an embedded device. This works just fine with, for example,
108
//   upplay, but confuses most of the other Control Points.
108
//    upplay, but confuses most of the other Control Points.
109
// - -m 4, Combined: for the main process: implement the Media Server
110
//    as a separate root device. Only works with a modified libupnp.
109
enum MSMode {Forked, RdrOnly, MSOnly, Combined};
111
enum MSMode {Forked, RdrOnly, MSOnly, CombinedEmbedded, CombinedMultiDev};
110
112
111
static void
113
static void
112
versionInfo(FILE *fp)
114
versionInfo(FILE *fp)
113
{
115
{
114
    fprintf(fp, "Upmpdcli %s %s\n",
116
    fprintf(fp, "Upmpdcli %s %s\n",
...
...
148
        "",                                         // url
150
        "",                                         // url
149
        ""                                          // imageUri
151
        ""                                          // imageUri
150
    }
152
    }
151
};
153
};
152
154
155
// Ad-hoc struct to hold the input identification parameters for the device(s)
156
struct UDevIds {
157
    std::string fname;
158
    std::string uuid;
159
    std::string fnameMS;
160
    std::string uuidMS;
161
};
162
153
// Static for cleanup in sig handler.
163
// Static for cleanup in sig handler.
154
static UpnpDevice *dev;
164
static vector<UpnpDevice *> devs;
155
165
156
string g_datadir(DATADIR "/");
166
string g_datadir(DATADIR "/");
157
string g_cachedir("/var/cache/upmpdcli");
167
string g_cachedir("/var/cache/upmpdcli");
158
168
159
// Global
169
// Global
...
...
163
bool g_lumincompat = false;
173
bool g_lumincompat = false;
164
174
165
static void onsig(int)
175
static void onsig(int)
166
{
176
{
167
    LOGDEB("Got sig" << endl);
177
    LOGDEB("Got sig" << endl);
178
    for (auto& dev : devs) {
168
    dev->shouldExit();
179
        dev->shouldExit();
180
    }
169
}
181
}
170
182
171
static const int catchedSigs[] = {SIGINT, SIGQUIT, SIGTERM};
183
static const int catchedSigs[] = {SIGINT, SIGQUIT, SIGTERM};
172
static void setupsigs()
184
static void setupsigs()
173
{
185
{
...
...
245
    string presentationhtml(DATADIR "/presentation.html");
257
    string presentationhtml(DATADIR "/presentation.html");
246
    string iface;
258
    string iface;
247
    unsigned short upport = 0;
259
    unsigned short upport = 0;
248
    string upnpip;
260
    string upnpip;
249
    int msm = 0;
261
    int msm = 0;
250
    bool inprocessms = false;
262
    bool inprocessms{false};
251
    bool msonly = false;
263
    bool msonly{false};
264
    bool msroot{false};
252
    
265
    
253
    const char *cp;
266
    const char *cp;
254
    if ((cp = getenv("UPMPD_HOST")))
267
    if ((cp = getenv("UPMPD_HOST")))
255
        mpdhost = cp;
268
        mpdhost = cp;
256
    if ((cp = getenv("UPMPD_PORT")))
269
    if ((cp = getenv("UPMPD_PORT")))
...
...
306
            default: Usage();   break;
319
            default: Usage();   break;
307
            }
320
            }
308
    b1: argc--; argv++;
321
    b1: argc--; argv++;
309
    }
322
    }
310
323
311
    if (argc != 0 || msm < 0 || msm > 3) {
324
    if (argc != 0 || msm < 0 || msm > 4) {
312
        Usage();
325
        Usage();
313
    }
326
    }
314
    MSMode arg_msmode = MSMode(msm);
327
    MSMode arg_msmode = MSMode(msm);
315
    
328
    
316
    UpMpd::Options opts;
329
    UpMpd::Options opts;
...
...
440
    switch (arg_msmode) {
453
    switch (arg_msmode) {
441
    case MSOnly:
454
    case MSOnly:
442
        inprocessms = true;
455
        inprocessms = true;
443
        msonly = true;
456
        msonly = true;
444
        break;
457
        break;
445
    case Combined:
458
    case CombinedEmbedded:
446
        inprocessms = true;
459
        inprocessms = true;
447
        msonly = false;
460
        msonly = false;
461
        msroot = false;
462
        break;
463
    case CombinedMultiDev:
464
        inprocessms = true;
465
        msonly = false;
466
        msroot = true;
448
        break;
467
        break;
449
    case RdrOnly:
468
    case RdrOnly:
450
    case Forked:
469
    case Forked:
451
    default:
470
    default:
452
        inprocessms = false;
471
        inprocessms = false;
...
...
688
    // with a possible renderer
707
    // with a possible renderer
689
    if (msonly) {
708
    if (msonly) {
690
        pidfilename = pidfilename + "-ms";
709
        pidfilename = pidfilename + "-ms";
691
    }
710
    }
692
711
693
    // Initialize the data we serve through HTTP (device and service
712
    opts.iconpath = iconpath;
694
    // descriptions, icons, presentation page, etc.)
713
    opts.presentationhtml = presentationhtml;
695
    unordered_map<string, VDirContent> files;
696
    if (!initHttpFs(files, g_datadir, ids, enableAV, enableOH,
697
                    !senderpath.empty(), inprocessms, msonly,
698
                    iconpath, presentationhtml)) {
699
        exit(1);
700
    }
701
702
    if (ownqueue)
714
    if (ownqueue)
703
        opts.options |= UpMpd::upmpdOwnQueue;
715
        opts.options |= UpMpd::upmpdOwnQueue;
704
    if (enableOH)
716
    if (enableOH)
705
        opts.options |= UpMpd::upmpdDoOH;
717
        opts.options |= UpMpd::upmpdDoOH;
706
    if (ohmetapersist)
718
    if (ohmetapersist)
...
...
732
    }
744
    }
733
745
734
    if (!enableAV)
746
    if (!enableAV)
735
        opts.options |= UpMpd::upmpdNoAV;
747
        opts.options |= UpMpd::upmpdNoAV;
736
748
749
    setupsigs();
750
737
    UpMpd *mediarenderer{nullptr};
751
    UpMpd *mediarenderer{nullptr};
738
    if (!msonly) {
752
    if (!msonly) {
739
        mediarenderer = new UpMpd(string("uuid:") + ids.uuid, ids.fname,
753
        mediarenderer = new UpMpd(string("uuid:") + ids.uuid, ids.fname,
740
                                  ohProductDesc, files, mpdclip, opts);
754
                                  ohProductDesc, mpdclip, opts);
755
        devs.push_back(mediarenderer);
741
    }
756
    }
742
757
743
    MediaServer *mediaserver = nullptr;
758
    MediaServer *mediaserver{nullptr};
744
    unordered_map<string, VDirContent> emptyfiles =
745
        unordered_map<string, VDirContent>();
746
    unordered_map<string, VDirContent> *msfiles = &emptyfiles;
747
    
759
    
748
    if (inprocessms) {
760
    if (inprocessms) {
749
        if (msonly) {
761
  // Create the Media Server device. If msonly is set, both
750
            msfiles = &files;
762
  // branches do the same thing and create a root device
751
        }
763
  // (mediarenderer is null).
752
  // Create the Media Server embedded device object. There needs
764
        // The multidev modified libupnp is needed for using 2 root devices
753
  // be no reference to the root object because there can be
765
        mediaserver = new MediaServer(msroot?nullptr:mediarenderer, string("uuid:") +
754
  // only one (libupnp restriction)
755
  mediaserver = new MediaServer(string("uuid:") + ids.uuidMS, ids.fnameMS,
756
                                      enableMediaServer, *msfiles);
766
                                      ids.uuidMS,ids.fnameMS, enableMediaServer);
767
        devs.push_back(mediaserver);
768
        LOGDEB("Media server event loop" << endl);
757
    } else if (enableMediaServer) {
769
    } else if (enableMediaServer) {
758
        startMsOnlyProcess();
770
        startMsOnlyProcess();
759
    }
771
    }
760
    
761
    // And forever generate state change events.
762
    LOGDEB("Entering event loop" << endl);
763
    setupsigs();
764
    if (msonly) {
772
    if (!msonly) {
765
        assert(nullptr != mediaserver);
766
        dev = mediaserver;
767
        LOGDEB("Media server event loop" << endl);
768
        if (enableMediaServer) {
769
            mediaserver->eventloop();
770
        } else {
771
            pause();
772
        }
773
    } else {
774
        LOGDEB("Renderer event loop" << endl);
773
        LOGDEB("Renderer event loop" << endl);
775
        assert(nullptr != mediarenderer);
776
        dev = mediarenderer;
777
        mediarenderer->eventloop();
774
        mediarenderer->startloop();
778
    }
775
    }
776
    if (inprocessms && enableMediaServer) {
777
        mediaserver->startloop();
778
    }
779
    pause();
779
    LOGDEB("Event loop returned" << endl);
780
    LOGDEB("Event loop returned" << endl);
780
    return 0;
781
    return 0;
781
}
782
}
783
784
// Read file from datadir
785
bool readLibFile(const std::string& name, std::string& contents)
786
{
787
    string path = path_cat(g_datadir, name);
788
    string reason;
789
    if (!file_to_string(path, contents, &reason)) {
790
        LOGERR("readLibFile: error reading " << name << " : " << reason << endl);
791
        return false;
792
    }
793
    return true;
794
}