|
a/src/avtransport.cxx |
|
b/src/avtransport.cxx |
|
... |
|
... |
87 |
this, _1, _2, 0));
|
87 |
this, _1, _2, 0));
|
88 |
m_dev->addActionMapping(this, "Previous",
|
88 |
m_dev->addActionMapping(this, "Previous",
|
89 |
bind(&UpMpdAVTransport::seqcontrol,
|
89 |
bind(&UpMpdAVTransport::seqcontrol,
|
90 |
this, _1, _2, 1));
|
90 |
this, _1, _2, 1));
|
91 |
|
91 |
|
|
|
92 |
// This would make our life easier, but it's incompatible if
|
|
|
93 |
// ohplaylist is also in use, so refrain.
|
92 |
// dev->m_mpdcli->consume(true);
|
94 |
// dev->m_mpdcli->consume(true);
|
93 |
#ifdef NO_SETNEXT
|
95 |
#ifdef NO_SETNEXT
|
94 |
// If no setnext, fake stopping at each track
|
96 |
// If no setnext, we'd like to fake stopping at each track but this does not work because mpd goes into PAUSED PLAY at the end of track, not STOP.
|
95 |
m_dev->m_mpdcli->single(true);
|
97 |
// m_dev->m_mpdcli->single(true);
|
96 |
#endif
|
98 |
#endif
|
97 |
}
|
99 |
}
|
98 |
|
100 |
|
99 |
// AVTransport Errors
|
101 |
// AVTransport Errors
|
100 |
enum AVTErrorCode {
|
102 |
enum AVTErrorCode {
|
|
... |
|
... |
359 |
LOGDEB1("UpMpdAVTransport::getEventDataTransport: " << chgdata << endl);
|
361 |
LOGDEB1("UpMpdAVTransport::getEventDataTransport: " << chgdata << endl);
|
360 |
return true;
|
362 |
return true;
|
361 |
}
|
363 |
}
|
362 |
|
364 |
|
363 |
// http://192.168.4.4:8200/MediaItems/246.mp3
|
365 |
// http://192.168.4.4:8200/MediaItems/246.mp3
|
364 |
int UpMpdAVTransport::setAVTransportURI(const SoapIncoming& sc, SoapOutgoing& data,
|
366 |
int UpMpdAVTransport::setAVTransportURI(const SoapIncoming& sc,
|
365 |
bool setnext)
|
367 |
SoapOutgoing& data, bool setnext)
|
366 |
{
|
368 |
{
|
|
|
369 |
#ifdef NO_SETNEXT
|
367 |
// pretend not to support setnext:
|
370 |
// pretend not to support setnext:
|
368 |
#ifdef NO_SETNEXT
|
|
|
369 |
if (setnext) {
|
371 |
if (setnext) {
|
370 |
LOGERR("SetNextAVTransportURI: faking error\n");
|
372 |
LOGERR("SetNextAVTransportURI: faking error\n");
|
371 |
return UPNP_E_INVALID_PARAM;
|
373 |
return UPNP_E_INVALID_PARAM;
|
372 |
}
|
374 |
}
|
373 |
#endif
|
375 |
#endif
|
|
... |
|
... |
392 |
LOGERR("set(Next)AVTransportURI: unsupported format: uri " << uri <<
|
394 |
LOGERR("set(Next)AVTransportURI: unsupported format: uri " << uri <<
|
393 |
" metadata [" << metadata << "]\n");
|
395 |
" metadata [" << metadata << "]\n");
|
394 |
return UPNP_E_INVALID_PARAM;
|
396 |
return UPNP_E_INVALID_PARAM;
|
395 |
}
|
397 |
}
|
396 |
|
398 |
|
397 |
bool is_song = (st == MpdStatus::MPDS_PLAY) ||
|
399 |
bool is_song = (st == MpdStatus::MPDS_PLAY) || (st == MpdStatus::MPDS_PAUSE);
|
398 |
(st == MpdStatus::MPDS_PAUSE);
|
|
|
399 |
UPMPD_UNUSED(is_song);
|
400 |
UPMPD_UNUSED(is_song);
|
400 |
int curpos = mpds.songpos;
|
401 |
int curpos = mpds.songpos;
|
401 |
LOGDEB1("UpMpdAVTransport::set" << (setnext?"Next":"") <<
|
402 |
LOGDEB1("UpMpdAVTransport::set" << (setnext?"Next":"") <<
|
402 |
"AVTransportURI: curpos: " <<
|
403 |
"AVTransportURI: curpos: " <<
|
403 |
curpos << " is_song " << is_song << " qlen " << mpds.qlen << endl);
|
404 |
curpos << " is_song " << is_song << " qlen " << mpds.qlen << endl);
|
|
... |
|
... |
410 |
m_dev->m_mpdcli->clearQueue();
|
411 |
m_dev->m_mpdcli->clearQueue();
|
411 |
// mpds is now invalid!
|
412 |
// mpds is now invalid!
|
412 |
curpos = -1;
|
413 |
curpos = -1;
|
413 |
}
|
414 |
}
|
414 |
|
415 |
|
|
|
416 |
// If setAVTransport is called, the Control Point wants to control
|
|
|
417 |
// the playing, so we reset any special mpd playlist
|
|
|
418 |
// mode. Especially, repeat would prevent us from ever seeing the
|
|
|
419 |
// end of the track. Note that always setting repeat to false is
|
|
|
420 |
// one of the ways which we are incompatible with simultaneous
|
|
|
421 |
// mpc or ohplaylist use (there are many others of course).
|
|
|
422 |
m_dev->m_mpdcli->repeat(false);
|
|
|
423 |
m_dev->m_mpdcli->random(false);
|
|
|
424 |
// See comment about single in init
|
|
|
425 |
m_dev->m_mpdcli->single(false);
|
|
|
426 |
|
415 |
// curpos == -1 means that the playlist was cleared or we just started. A
|
427 |
// curpos == -1 means that the playlist was cleared or we just started. A
|
416 |
// play will use position 0, so it's actually equivalent to curpos == 0
|
428 |
// play will use position 0, so it's actually equivalent to curpos == 0
|
417 |
if (curpos == -1) {
|
429 |
if (curpos == -1) {
|
418 |
curpos = 0;
|
430 |
curpos = 0;
|
419 |
}
|
431 |
}
|
|
... |
|
... |
472 |
default: break;
|
484 |
default: break;
|
473 |
}
|
485 |
}
|
474 |
#endif
|
486 |
#endif
|
475 |
// Clean up old song ids
|
487 |
// Clean up old song ids
|
476 |
if (!(m_dev->m_options & UpMpd::upmpdOwnQueue)) {
|
488 |
if (!(m_dev->m_options & UpMpd::upmpdOwnQueue)) {
|
477 |
for (set<int>::iterator it = m_songids.begin();
|
489 |
for (auto id : m_songids) {
|
478 |
it != m_songids.end(); it++) {
|
|
|
479 |
// Can't just delete here. If the id does not exist, MPD
|
490 |
// Can't just delete here. If the id does not exist, MPD
|
480 |
// gets into an apparently permanent error state, where even
|
491 |
// gets into an apparently permanent error state, where even
|
481 |
// get_status does not work
|
492 |
// get_status does not work
|
482 |
if (m_dev->m_mpdcli->statId(*it)) {
|
493 |
if (m_dev->m_mpdcli->statId(id)) {
|
483 |
m_dev->m_mpdcli->deleteId(*it);
|
494 |
m_dev->m_mpdcli->deleteId(id);
|
484 |
}
|
495 |
}
|
485 |
}
|
496 |
}
|
486 |
m_songids.clear();
|
497 |
m_songids.clear();
|
487 |
}
|
498 |
}
|
488 |
}
|
499 |
}
|
|
... |
|
... |
680 |
}
|
691 |
}
|
681 |
|
692 |
|
682 |
m_dev->loopWakeup();
|
693 |
m_dev->loopWakeup();
|
683 |
return ok ? UPNP_E_SUCCESS : UPNP_E_INTERNAL_ERROR;
|
694 |
return ok ? UPNP_E_SUCCESS : UPNP_E_INTERNAL_ERROR;
|
684 |
}
|
695 |
}
|
685 |
|
696 |
|
|
|
697 |
/*
|
|
|
698 |
* For the AVTransport service, this only makes sense if we're playing a
|
|
|
699 |
* multi-track media, else we're only dealing with a single track (and
|
|
|
700 |
* possibly the next), and none of the repeat/shuffle modes make
|
|
|
701 |
* sense. If ownqueue is 0, it might still make sense for us to
|
|
|
702 |
* control the mpd play mode though, but any special mode will be reset if
|
|
|
703 |
* set(Next)AVTransport is called.
|
|
|
704 |
*/
|
686 |
int UpMpdAVTransport::setPlayMode(const SoapIncoming& sc, SoapOutgoing& data)
|
705 |
int UpMpdAVTransport::setPlayMode(const SoapIncoming& sc, SoapOutgoing& data)
|
687 |
{
|
706 |
{
|
688 |
string playmode;
|
707 |
string playmode;
|
689 |
if (!sc.get("NewPlayMode", &playmode)) {
|
708 |
if (!sc.get("NewPlayMode", &playmode)) {
|
690 |
return UPNP_E_INVALID_PARAM;
|
709 |
return UPNP_E_INVALID_PARAM;
|
691 |
}
|
710 |
}
|
692 |
LOGDEB("UpMpdAVTransport::setPlayMode: " << playmode << endl);
|
711 |
LOGDEB("UpMpdAVTransport::setPlayMode: " << playmode << endl);
|
|
|
712 |
|
|
|
713 |
if ((m_dev->m_options & UpMpd::upmpdOwnQueue)) {
|
|
|
714 |
// If we own the queue then none of this makes sense, we're
|
|
|
715 |
// only keeping 1 or 2 entries on the queue and controlling
|
|
|
716 |
// everything.
|
|
|
717 |
LOGDEB("AVTRansport::setPlayMode: ownqueue is set, doing nothing\n");
|
|
|
718 |
return 0;
|
|
|
719 |
}
|
693 |
|
720 |
|
694 |
bool ok;
|
721 |
bool ok;
|
695 |
if (!playmode.compare("NORMAL")) {
|
722 |
if (!playmode.compare("NORMAL")) {
|
696 |
ok = m_dev->m_mpdcli->repeat(false) && m_dev->m_mpdcli->random(false) &&
|
723 |
ok = m_dev->m_mpdcli->repeat(false) && m_dev->m_mpdcli->random(false) &&
|
697 |
m_dev->m_mpdcli->single(false);
|
724 |
m_dev->m_mpdcli->single(false);
|
|
... |
|
... |
715 |
}
|
742 |
}
|
716 |
m_dev->loopWakeup();
|
743 |
m_dev->loopWakeup();
|
717 |
return ok ? UPNP_E_SUCCESS : UPNP_E_INTERNAL_ERROR;
|
744 |
return ok ? UPNP_E_SUCCESS : UPNP_E_INTERNAL_ERROR;
|
718 |
}
|
745 |
}
|
719 |
|
746 |
|
720 |
int UpMpdAVTransport::getTransportSettings(const SoapIncoming& sc, SoapOutgoing& data)
|
747 |
int UpMpdAVTransport::getTransportSettings(const SoapIncoming& sc,
|
|
|
748 |
SoapOutgoing& data)
|
721 |
{
|
749 |
{
|
722 |
const MpdStatus &mpds = m_dev->getMpdStatus();
|
750 |
const MpdStatus &mpds = m_dev->getMpdStatus();
|
723 |
string playmode = mpdsToPlaymode(mpds);
|
751 |
string playmode = mpdsToPlaymode(mpds);
|
724 |
data.addarg("PlayMode", playmode);
|
752 |
data.addarg("PlayMode", playmode);
|
725 |
data.addarg("RecQualityMode", "NOT_IMPLEMENTED");
|
753 |
data.addarg("RecQualityMode", "NOT_IMPLEMENTED");
|