Switch to unified view

a/src/upmpd.cxx b/src/upmpd.cxx
...
...
48
#include "ohvolume.hxx"                 // for OHVolume
48
#include "ohvolume.hxx"                 // for OHVolume
49
#include "renderctl.hxx"                // for UpMpdRenderCtl
49
#include "renderctl.hxx"                // for UpMpdRenderCtl
50
#include "upmpdutils.hxx"               // for path_cat, Pidfile, regsub1, etc
50
#include "upmpdutils.hxx"               // for path_cat, Pidfile, regsub1, etc
51
#include "execmd.h"
51
#include "execmd.h"
52
#include "httpfs.hxx"
52
#include "httpfs.hxx"
53
#include "ohsndrcv.hxx"
53
54
54
using namespace std;
55
using namespace std;
55
using namespace std::placeholders;
56
using namespace std::placeholders;
56
using namespace UPnPP;
57
using namespace UPnPP;
57
58
...
...
61
             const unordered_map<string, VDirContent>& files,
62
             const unordered_map<string, VDirContent>& files,
62
             MPDCli *mpdcli, Options opts)
63
             MPDCli *mpdcli, Options opts)
63
    : UpnpDevice(deviceid, files), m_mpdcli(mpdcli), m_mpds(0),
64
    : UpnpDevice(deviceid, files), m_mpdcli(mpdcli), m_mpds(0),
64
      m_options(opts.options),
65
      m_options(opts.options),
65
      m_mcachefn(opts.cachefn),
66
      m_mcachefn(opts.cachefn),
66
      m_rdctl(0), m_avt(0), m_ohpr(0), m_ohpl(0), m_ohrcv(0),
67
      m_rdctl(0), m_avt(0), m_ohpr(0), m_ohpl(0), m_ohrcv(0), m_sndrcv(0),
67
      m_friendlyname(friendlyname)
68
      m_friendlyname(friendlyname)
68
{
69
{
69
    bool avtnoev = (m_options & upmpdNoAV) != 0; 
70
    bool avtnoev = (m_options & upmpdNoAV) != 0; 
70
    // Note: the order is significant here as it will be used when
71
    // Note: the order is significant here as it will be used when
71
    // calling the getStatus() methods, and we want AVTransport to
72
    // calling the getStatus() methods, and we want AVTransport to
...
...
73
    m_rdctl = new UpMpdRenderCtl(this, avtnoev);
74
    m_rdctl = new UpMpdRenderCtl(this, avtnoev);
74
    m_services.push_back(m_rdctl);
75
    m_services.push_back(m_rdctl);
75
    m_avt = new UpMpdAVTransport(this, avtnoev);
76
    m_avt = new UpMpdAVTransport(this, avtnoev);
76
    m_services.push_back(m_avt);
77
    m_services.push_back(m_avt);
77
    m_services.push_back(new UpMpdConMan(this));
78
    m_services.push_back(new UpMpdConMan(this));
78
    bool haveReceiver = (m_options & upmpdOhReceiver) != 0; 
79
79
    if (m_options & upmpdDoOH) {
80
    if (m_options & upmpdDoOH) {
80
        m_ohpr = new OHProduct(this, friendlyname, haveReceiver);
81
        m_services.push_back(m_ohpr);
82
        m_services.push_back(new OHInfo(this));
81
        m_services.push_back(new OHInfo(this));
83
        m_services.push_back(new OHTime(this));
82
        m_services.push_back(new OHTime(this));
84
        m_services.push_back(new OHVolume(this));
83
        m_services.push_back(new OHVolume(this));
85
        m_ohpl = new OHPlaylist(this, opts.ohmetasleep);
84
        m_ohpl = new OHPlaylist(this, opts.ohmetasleep);
86
        m_services.push_back(m_ohpl);
85
        m_services.push_back(m_ohpl);
87
        if (haveReceiver) {
86
        if (m_options & upmpdOhReceiver) {
88
            struct OHReceiverParams parms;
87
            struct OHReceiverParams parms;
89
            if (opts.schttpport)
88
            if (opts.schttpport)
90
                parms.httpport = opts.schttpport;
89
                parms.httpport = opts.schttpport;
91
            if (!opts.scplaymethod.empty()) {
90
            if (!opts.scplaymethod.empty()) {
92
                if (!opts.scplaymethod.compare("alsa")) {
91
                if (!opts.scplaymethod.compare("alsa")) {
93
                    parms.pm = OHReceiverParams::OHRP_ALSA;
92
                    parms.pm = OHReceiverParams::OHRP_ALSA;
94
                } else if (!opts.scplaymethod.compare("mpd")) {
93
                } else if (!opts.scplaymethod.compare("mpd")) {
95
                    parms.pm = OHReceiverParams::OHRP_MPD;
94
                    parms.pm = OHReceiverParams::OHRP_MPD;
96
                }
95
                }
97
            }
96
            }
97
            parms.sc2mpdpath = opts.sc2mpdpath;
98
            m_ohrcv = new OHReceiver(this, parms);
98
            m_ohrcv = new OHReceiver(this, parms);
99
            m_services.push_back(m_ohrcv);
99
            m_services.push_back(m_ohrcv);
100
        }
100
        }
101
        if (m_options& upmpdOhSenderReceiver) {
102
            // Note: this is not an UPnP service
103
            m_sndrcv = new SenderReceiver(this, opts.senderpath,
104
                                          opts.sendermpdport);
105
        }
106
        // Create ohpr last, so that it can ask questions to other services
107
        m_ohpr = new OHProduct(this, friendlyname);
108
        m_services.push_back(m_ohpr);
101
    }
109
    }
102
}
110
}
103
111
104
UpMpd::~UpMpd()
112
UpMpd::~UpMpd()
105
{
113
{
114
    delete m_sndrcv;
106
    for (vector<UpnpService*>::iterator it = m_services.begin();
115
    for (vector<UpnpService*>::iterator it = m_services.begin();
107
         it != m_services.end(); it++) {
116
         it != m_services.end(); it++) {
108
        delete(*it);
117
        delete(*it);
109
    }
118
    }
110
}
119
}
...
...
169
static string datadir(DATADIR "/");
178
static string datadir(DATADIR "/");
170
179
171
// Global
180
// Global
172
string g_configfilename(CONFIGDIR "/upmpdcli.conf");
181
string g_configfilename(CONFIGDIR "/upmpdcli.conf");
173
182
174
// Path for the sc2mpd command, or empty
175
string g_sc2mpd_path;
176
177
static void onsig(int)
183
static void onsig(int)
178
{
184
{
179
    LOGDEB("Got sig" << endl);
185
    LOGDEB("Got sig" << endl);
180
    dev->shouldExit();
186
    dev->shouldExit();
181
}
187
}
...
...
195
        }
201
        }
196
}
202
}
197
203
198
int main(int argc, char *argv[])
204
int main(int argc, char *argv[])
199
{
205
{
206
    // Path for the sc2mpd command, or empty
207
    string sc2mpdpath;
208
209
    // Sender mode: path for the command creating the mpd and mpd2sc
210
    // processes, and port for the auxiliary mpd.
211
    string senderpath;
212
    int sendermpdport = 6700;
213
214
    // Main MPD parameters
200
    string mpdhost("localhost");
215
    string mpdhost("localhost");
201
    int mpdport = 6600;
216
    int mpdport = 6600;
202
    string mpdpassword;
217
    string mpdpassword;
218
203
    string logfilename;
219
    string logfilename;
204
    int loglevel(Logger::LLINF);
220
    int loglevel(Logger::LLINF);
205
    string friendlyname(dfltFriendlyName);
221
    string friendlyname(dfltFriendlyName);
206
    bool ownqueue = true;
222
    bool ownqueue = true;
207
    bool enableAV = true;
223
    bool enableAV = true;
...
...
326
            upport = atoi(value.c_str());
342
            upport = atoi(value.c_str());
327
        }
343
        }
328
        if (config.get("schttpport", value))
344
        if (config.get("schttpport", value))
329
            opts.schttpport = atoi(value.c_str());
345
            opts.schttpport = atoi(value.c_str());
330
        config.get("scplaymethod", opts.scplaymethod);
346
        config.get("scplaymethod", opts.scplaymethod);
331
        config.get("sc2mpd", g_sc2mpd_path);
347
        config.get("sc2mpd", sc2mpdpath);
332
        if (config.get("ohmetasleep", value))
348
        if (config.get("ohmetasleep", value))
333
            opts.ohmetasleep = atoi(value.c_str());
349
            opts.ohmetasleep = atoi(value.c_str());
350
351
        config.get("scsenderpath", senderpath);
352
        if (config.get("scsendermpdport", value))
353
            sendermpdport = atoi(value.c_str());
334
    }
354
    }
335
    if (Logger::getTheLog(logfilename) == 0) {
355
    if (Logger::getTheLog(logfilename) == 0) {
336
        cerr << "Can't initialize log" << endl;
356
        cerr << "Can't initialize log" << endl;
337
        return 1;
357
        return 1;
338
    }
358
    }
339
    Logger::getTheLog("")->setLogLevel(Logger::LogLevel(loglevel));
359
    Logger::getTheLog("")->setLogLevel(Logger::LogLevel(loglevel));
340
341
    if (g_sc2mpd_path.empty()) {
342
        // Do we have an sc2mpd command installed (for songcast)?
343
        if (!ExecCmd::which("sc2mpd", g_sc2mpd_path))
344
            g_sc2mpd_path.clear();
345
    }
346
360
347
    Pidfile pidfile(pidfilename);
361
    Pidfile pidfile(pidfilename);
348
362
349
    // If started by root, do the pidfile + change uid thing
363
    // If started by root, do the pidfile + change uid thing
350
    uid_t runas(0);
364
    uid_t runas(0);
...
...
431
#endif
445
#endif
432
    }
446
    }
433
447
434
//// Dropped root 
448
//// Dropped root 
435
449
450
    if (sc2mpdpath.empty()) {
451
        // Do we have an sc2mpd command installed (for songcast)?
452
        if (!ExecCmd::which("sc2mpd", sc2mpdpath))
453
            sc2mpdpath.clear();
454
    }
455
    if (senderpath.empty()) {
456
        // Do we have an scmakempdsender command installed (for
457
        // starting the songcast sender and its auxiliary mpd)?
458
        if (!ExecCmd::which("scmakempdsender", senderpath))
459
            senderpath.clear();
460
    }
461
    
436
    if (!g_sc2mpd_path.empty()) {
462
    if (!sc2mpdpath.empty()) {
463
        // Check if sc2mpd is actually there
437
        if (access(g_sc2mpd_path.c_str(), X_OK|R_OK) != 0) {
464
        if (access(sc2mpdpath.c_str(), X_OK|R_OK) != 0) {
438
            LOGERR("Specified path for sc2mpd: " << g_sc2mpd_path << 
465
            LOGERR("Specified path for sc2mpd: " << sc2mpdpath << 
439
                   " is not executable" << endl);
466
                   " is not executable" << endl);
440
            g_sc2mpd_path.clear();
467
            sc2mpdpath.clear();
468
        }
469
    }
470
471
    if (!senderpath.empty()) {
472
        // Check that both the starter script and the mpd2sc sender
473
        // command are executable. We'll assume that mpd is ok
474
        if (access(senderpath.c_str(), X_OK|R_OK) != 0) {
475
            LOGERR("The specified path for the sender starter script: ["
476
                   << senderpath <<
477
                   "] is not executable, disabling the sender mode.\n");
478
            senderpath.clear();
479
        } else {
480
            string path;
481
            if (!ExecCmd::which("mpd2sc", path)) {
482
                LOGERR("Sender starter was specified and found but the mpd2sc "
483
                       "command is not found (or executable). Disabling "
484
                       "the sender mode.\n");
485
                senderpath.clear();
441
        }
486
            }
442
    }
487
        }
488
    }
489
443
490
444
    // Initialize MPD client object. Retry until it works or power fail.
491
    // Initialize MPD client object. Retry until it works or power fail.
445
    MPDCli *mpdclip = 0;
492
    MPDCli *mpdclip = 0;
446
    int mpdretrysecs = 2;
493
    int mpdretrysecs = 2;
447
    for (;;) {
494
    for (;;) {
...
...
502
    string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
549
    string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
503
550
504
    // Initialize the data we serve through HTTP (device and service
551
    // Initialize the data we serve through HTTP (device and service
505
    // descriptions, icons, presentation page, etc.)
552
    // descriptions, icons, presentation page, etc.)
506
    unordered_map<string, VDirContent> files;
553
    unordered_map<string, VDirContent> files;
507
    if (!initHttpFs(files, datadir, UUID, friendlyname, enableAV, enableOH, 
554
    if (!initHttpFs(files, datadir, UUID, friendlyname, enableAV, enableOH,
555
                    !senderpath.empty(),
508
                    iconpath, presentationhtml)) {
556
                    iconpath, presentationhtml)) {
509
        exit(1);
557
        exit(1);
510
    }
558
    }
511
559
512
    if (ownqueue)
560
    if (ownqueue)
513
        opts.options |= UpMpd::upmpdOwnQueue;
561
        opts.options |= UpMpd::upmpdOwnQueue;
514
    if (enableOH)
562
    if (enableOH)
515
        opts.options |= UpMpd::upmpdDoOH;
563
        opts.options |= UpMpd::upmpdDoOH;
516
    if (ohmetapersist)
564
    if (ohmetapersist)
517
        opts.options |= UpMpd::upmpdOhMetaPersist;
565
        opts.options |= UpMpd::upmpdOhMetaPersist;
518
    if (!g_sc2mpd_path.empty())
566
    if (!sc2mpdpath.empty()) {
567
        opts.sc2mpdpath = sc2mpdpath;
519
        opts.options |= UpMpd::upmpdOhReceiver;
568
        opts.options |= UpMpd::upmpdOhReceiver;
569
    }
570
    if (!senderpath.empty()) {
571
        opts.options |= UpMpd::upmpdOhSenderReceiver;
572
        opts.senderpath = senderpath;
573
        opts.sendermpdport = sendermpdport;
574
    }
575
520
    if (!enableAV)
576
    if (!enableAV)
521
        opts.options |= UpMpd::upmpdNoAV;
577
        opts.options |= UpMpd::upmpdNoAV;
522
    // Initialize the UPnP device object.
578
    // Initialize the UPnP device object.
523
    UpMpd device(string("uuid:") + UUID, friendlyname, 
579
    UpMpd device(string("uuid:") + UUID, friendlyname, 
524
                 files, mpdclip, opts);
580
                 files, mpdclip, opts);