Switch to unified view

a/src/ohsndrcv.cxx b/src/ohsndrcv.cxx
...
...
23
#include "execmd.h"
23
#include "execmd.h"
24
#include "upmpd.hxx"
24
#include "upmpd.hxx"
25
#include "mpdcli.hxx"
25
#include "mpdcli.hxx"
26
#include "upmpdutils.hxx"
26
#include "upmpdutils.hxx"
27
#include "ohreceiver.hxx"
27
#include "ohreceiver.hxx"
28
#include "ohplaylist.hxx"
29
28
30
using namespace std;
29
using namespace std;
31
using namespace std::placeholders;
30
using namespace std::placeholders;
32
using namespace UPnPP;
31
using namespace UPnPP;
33
32
33
#ifndef deleteZ
34
#define deleteZ(X) {delete (X); X = 0;}
35
#endif
36
34
class SenderReceiver::Internal {
37
class SenderReceiver::Internal {
35
public:
38
public:
39
    // isender is the process we use for internal sources:
40
    //   internal source -> local mpd -> fifo -> isender->Songcast
41
    // ssender is an arbitrary script probably reading from an audio
42
    // driver input and managing a sender. Our local source or mpd are
43
    // uninvolved
36
    Internal(UpMpd *dv, const string& starterpath, int port)
44
    Internal(UpMpd *dv, const string& starterpath, int port)
37
        : dev(dv), mpd(0), origmpd(0), sender(0), makesendercmd(starterpath),
45
        : dev(dv), mpd(0), origmpd(0), isender(0), ssender(0),
38
          mpdport(port) {
46
          makeisendercmd(starterpath), mpdport(port) {
39
    }
47
    }
40
    ~Internal() {
48
    ~Internal() {
41
        clear();
49
        clear();
42
    }
50
    }
43
    void clear() {
51
    void clear() {
44
        if (dev && origmpd) {
52
        if (dev && origmpd) {
45
            dev->m_mpdcli = origmpd;
53
            dev->m_mpdcli = origmpd;
46
            origmpd = 0;
54
            origmpd = 0;
55
        }
47
            if (dev->m_ohrcv) {
56
        if (dev && dev->m_ohrcv) {
48
                dev->m_ohrcv->iStop();
57
            dev->m_ohrcv->iStop();
49
            }
58
        }
50
            if (dev->m_ohpl) {
51
                dev->m_ohpl->refreshState();
52
            }
53
        }
54
        delete mpd;
59
        deleteZ(mpd);
55
        mpd = 0;
56
        delete sender;
60
        deleteZ(isender);
57
        sender = 0;
61
        deleteZ(ssender);
58
    }
62
    }
59
    UpMpd *dev;
63
    UpMpd *dev;
60
    MPDCli *mpd;
64
    MPDCli *mpd;
61
    MPDCli *origmpd;
65
    MPDCli *origmpd;
62
    ExecCmd *sender;
66
    ExecCmd *isender;
67
    ExecCmd *ssender;
63
    string uri;
68
    string iuri;
64
    string meta;
69
    string imeta;
65
    string makesendercmd;
70
    string makeisendercmd;
66
    int mpdport;
71
    int mpdport;
67
};
72
};
68
73
69
74
70
SenderReceiver::SenderReceiver(UpMpd *dev, const string& starterpath, int port)
75
SenderReceiver::SenderReceiver(UpMpd *dev, const string& starterpath, int port)
...
...
86
    }
91
    }
87
    MpdState st;
92
    MpdState st;
88
    return src->saveState(st, seekms) && dest->restoreState(st);
93
    return src->saveState(st, seekms) && dest->restoreState(st);
89
}
94
}
90
95
96
// If script is empty, we are using an internal source and aux mpd +
97
// script. Which we reuse across start/stop/start.
98
// If script is non-empty, it's an external source, and we restart it
99
// each time.
91
bool SenderReceiver::start(bool useradio, int seekms)
100
bool SenderReceiver::start(const string& script, int seekms)
92
{
101
{
93
    LOGDEB("SenderReceiver::start. seekms " << seekms << endl);
102
    LOGDEB("SenderReceiver::start. script [" << script <<
103
           "] seekms " << seekms << endl);
94
    
104
    
95
    if (!m->dev || !m->dev->m_ohpl) {
105
    if (!m->dev || !m->dev->m_mpdcli || !m->dev->m_ohrcv) {
96
        LOGERR("SenderReceiver::start: no dev or ohpl??\n");
106
        LOGERR("SenderReceiver::start: no dev or absent service??\n");
97
        return false;
107
        return false;
98
    }
108
    }
99
    
109
    
100
    // Stop MPD Play (normally already done)
110
    // Stop MPD Play (normally already done)
101
    m->dev->m_mpdcli->stop();
111
    m->dev->m_mpdcli->stop();
102
112
103
    if (!m->sender) {
113
    // sndcmd will non empty if we actually started a script instead
114
    // of reusing an old one (then need to read the initial data).
115
    ExecCmd *sndcmd = 0;
116
    if (script.empty() && !m->isender) {
104
        // First time: Start fifo MPD and Sender
117
        // Internal source, first time: Start fifo MPD and Sender
105
        m->sender = new ExecCmd();
118
        m->isender = sndcmd = new ExecCmd();
106
        vector<string> args;
119
        vector<string> args;
107
        args.push_back("-p");
120
        args.push_back("-p");
108
        args.push_back(SoapHelp::i2s(m->mpdport));
121
        args.push_back(SoapHelp::i2s(m->mpdport));
109
        args.push_back("-f");
122
        args.push_back("-f");
110
        args.push_back(m->dev->m_friendlyname);
123
        args.push_back(m->dev->m_friendlyname);
111
        m->sender->startExec(m->makesendercmd, args, false, true);
124
        m->isender->startExec(m->makeisendercmd, args, false, true);
125
    } else if (!script.empty()) {
126
        // External source. ssender should already be zero, we delete
127
        // it just in case
128
        deleteZ(m->ssender);
129
        m->ssender = sndcmd = new ExecCmd();
130
        vector<string> args;
131
        args.push_back("-f");
132
        args.push_back(m->dev->m_friendlyname);
133
        m->ssender->startExec(script, args, false, true);
134
    }
112
135
136
    string meta, uri;
137
    if (sndcmd) {
138
        // Just started internal or external sender script, need to read the
139
        // details
113
        string output;
140
        string output;
114
        if (m->sender->getline(output) <= 0) {
141
        if (sndcmd->getline(output) <= 0) {
115
            LOGERR("SenderReceiver::start: makesender command failed\n");
142
            LOGERR("SenderReceiver::start: makesender command failed\n");
116
            m->clear();
143
            m->clear();
117
            return false;
144
            return false;
118
        }
145
        }
119
        LOGDEB("SenderReceiver::start got [" << output << "] from script\n");
146
        LOGDEB("SenderReceiver::start got [" << output << "] from script\n");
120
147
121
        // Output is like [Ok mpdport URI base64-encoded-uri METADATA b64-meta]
148
        // Output is like [Ok mpdport URI base64-encoded-uri METADATA b64-meta]
149
        // mpdport is bogus, but present, for ext scripts
122
        vector<string> toks;
150
        vector<string> toks;
123
        stringToTokens(output, toks);
151
        stringToTokens(output, toks);
124
        if (toks.size() != 6 || toks[0].compare("Ok")) {
152
        if (toks.size() != 6 || toks[0].compare("Ok")) {
125
            LOGERR("SenderReceiver::start: bad output from script: " << output
153
            LOGERR("SenderReceiver::start: bad output from script: " << output
126
                   << endl);
154
                   << endl);
127
            m->clear();
155
            m->clear();
128
            return false;
156
            return false;
129
        }
157
        }
130
        m->uri = base64_decode(toks[3]);
158
        uri = base64_decode(toks[3]);
131
        m->meta = base64_decode(toks[5]);
159
        meta = base64_decode(toks[5]);
132
160
        if (script.empty()) {
133
        // Connect to the new MPD
161
            m->iuri = uri;
162
            m->imeta = meta;
163
        }
164
    } else {
165
        // Reusing internal source
166
        uri = m->iuri;
167
        meta = m->imeta;
168
    }
169
    
170
    if (sndcmd && script.empty()) {
171
        // Just started the internal source script, connect to the new MPD
134
        m->mpd = new MPDCli("localhost", m->mpdport);
172
        m->mpd = new MPDCli("localhost", m->mpdport);
135
        if (!m->mpd || !m->mpd->ok()) {
173
        if (!m->mpd || !m->mpd->ok()) {
136
            LOGERR("SenderReceiver::start: can't connect to new MPD\n");
174
            LOGERR("SenderReceiver::start: can't connect to new MPD\n");
137
            m->clear();
175
            m->clear();
138
            return false;
176
            return false;
139
        }
177
        }
140
    }
178
    }
141
    
179
    
142
    // Start our receiver
180
    // Start our receiver
143
    if (!m->dev->m_ohrcv->iSetSender(m->uri, m->meta) ||
181
    if (!m->dev->m_ohrcv->iSetSender(uri, meta) ||
144
        !m->dev->m_ohrcv->iPlay()) {
182
        !m->dev->m_ohrcv->iPlay()) {
145
        m->clear();
183
        m->clear();
146
        return false;
184
        return false;
147
    }
185
    }
148
186
149
    // Copy mpd state 
187
    if (script.empty()) {
188
        // Internal source: copy mpd state
150
    copyMpd(m->dev->m_mpdcli, m->mpd, seekms);
189
        copyMpd(m->dev->m_mpdcli, m->mpd, seekms);
151
    m->origmpd = m->dev->m_mpdcli;
190
        m->origmpd = m->dev->m_mpdcli;
152
    m->dev->m_mpdcli = m->mpd;
191
        m->dev->m_mpdcli = m->mpd;
192
    } else {
193
        m->origmpd = 0;
194
    }
153
195
154
    return true;
196
    return true;
155
}
197
}
156
198
157
bool SenderReceiver::stop()
199
bool SenderReceiver::stop()
158
{
200
{
159
    LOGDEB("SenderReceiver::stop()\n");
201
    LOGDEB("SenderReceiver::stop()\n");
160
    // Do we want to transfer the playlist back ? Probably we do.
202
    if (!m->dev || !m->dev->m_ohrcv) {
161
    if (!m->dev || !m->origmpd || !m->mpd || !m->dev->m_ohpl ||
162
        !m->dev->m_ohrcv) {
163
        LOGERR("SenderReceiver::stop: bad state: dev/origmpd/mpd null\n");
203
        LOGERR("SenderReceiver::stop: bad state: dev/rcv null\n");
164
        return false;
204
        return false;
165
    }
205
    }
166
    copyMpd(m->mpd, m->origmpd, -1);
167
    m->mpd->stop();
168
    m->dev->m_mpdcli = m->origmpd;
169
    m->origmpd = 0;
170
    m->dev->m_ohrcv->iStop();
206
    m->dev->m_ohrcv->iStop();
171
    m->dev->m_ohpl->refreshState();
172
207
208
    if (m->origmpd && m->mpd) {
209
        // Do we want to transfer the playlist back ? Probably we do.
210
        copyMpd(m->mpd, m->origmpd, -1);
211
        m->mpd->stop();
212
        m->dev->m_mpdcli = m->origmpd;
213
        m->origmpd = 0;
214
    }
215
216
    // We don't reuse external source processes
217
    deleteZ(m->ssender);
173
    return true;
218
    return true;
174
}
219
}