|
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 |
}
|