--- a/libupnpp/control/avtransport.cxx
+++ b/libupnpp/control/avtransport.cxx
@@ -26,8 +26,10 @@
#include "libupnpp/soaphelp.hxx"
#include "libupnpp/upnpp_p.hxx"
#include "libupnpp/log.hxx"
+#include "libupnpp/upnpavutils.hxx"
#include "libupnpp/control/avtransport.hxx"
#include "libupnpp/control/avlastchg.hxx"
+#include "libupnpp/control/cdircontent.hxx"
namespace UPnPClient {
@@ -41,16 +43,75 @@
return !SType.compare(0, sz, st, 0, sz);
}
+static AVTransport::TransportState stringToTpState(const string& s)
+{
+ if (!stringuppercmp("STOPPED", s)) {
+ return AVTransport::Stopped;
+ } else if (!stringuppercmp("PLAYING", s)) {
+ return AVTransport::Playing;
+ } else if (!stringuppercmp("TRANSITIONING", s)) {
+ return AVTransport::Transitioning;
+ } else if (!stringuppercmp("PAUSED_PLAYBACK", s)) {
+ return AVTransport::PausedPlayback;
+ } else if (!stringuppercmp("PAUSED_RECORDING", s)) {
+ return AVTransport::PausedRecording;
+ } else if (!stringuppercmp("RECORDING", s)) {
+ return AVTransport::Recording;
+ } else if (!stringuppercmp("NO MEDIA PRESENT", s)) {
+ return AVTransport::NoMediaPresent;
+ } else {
+ LOGERR("AVTransport event: bad value for TransportState: "
+ << s << endl);
+ return AVTransport::Unknown;
+ }
+}
+
+static AVTransport::TransportStatus stringToTpStatus(const string& s)
+{
+ if (!stringuppercmp("OK", s)) {
+ return AVTransport::TPS_Ok;
+ } else if (!stringuppercmp("ERROR_OCCURRED", s)) {
+ return AVTransport::TPS_Error;
+ } else {
+ LOGERR("AVTransport event: bad value for TransportStatus: "
+ << s << endl);
+ return AVTransport::TPS_Unknown;
+ }
+}
+
+static AVTransport::PlayMode stringToPlayMode(const string& s)
+{
+ if (!stringuppercmp("NORMAL", s)) {
+ return AVTransport::PM_Normal;
+ } else if (!stringuppercmp("SHUFFLE", s)) {
+ return AVTransport::PM_Shuffle;
+ } else if (!stringuppercmp("REPEAT_ONE", s)) {
+ return AVTransport::PM_RepeatOne;
+ } else if (!stringuppercmp("REPEAT_ALL", s)) {
+ return AVTransport::PM_RepeatAll;
+ } else if (!stringuppercmp("RANDOM", s)) {
+ return AVTransport::PM_Random;
+ } else if (!stringuppercmp("DIRECT_1", s)) {
+ return AVTransport::PM_Direct1;
+ } else {
+ LOGERR("AVTransport event: bad value for PlayMode: "
+ << s << endl);
+ return AVTransport::PM_Unknown;
+ }
+}
+
void AVTransport::evtCallback(
const std::unordered_map<std::string, std::string>& props)
{
- //LOGDEB("AVTransport::evtCallback:" << endl);
+ LOGDEB1("AVTransport::evtCallback:" << endl);
for (auto& entry: props) {
if (entry.first.compare("LastChange")) {
LOGINF("AVTransport:event: var not lastchange: "
<< entry.first << " -> " << entry.second << endl;);
continue;
}
+ LOGDEB1("AVTransport:event: "
+ << entry.first << " -> " << entry.second << endl;);
std::unordered_map<std::string, std::string> props1;
if (!decodeAVLastChange(entry.second, props1)) {
@@ -59,39 +120,304 @@
return;
}
for (auto& entry1: props1) {
- //LOGDEB(" " << entry1.first << " -> " <<
- // entry1.second << endl);
+ if (!m_reporter) {
+ LOGDEB1("AVTransport::evtCallback: " << entry1.first << " -> "
+ << entry1.second << endl);
+ continue;
+ }
+
if (!entry1.first.compare("TransportState")) {
- } else if (!entry1.first.compare("CurrentTransportActions")) {
+ m_reporter->changed(entry1.first.c_str(),
+ stringToTpState(entry1.second));
+
} else if (!entry1.first.compare("TransportStatus")) {
- } else if (!entry1.first.compare("TransportPlaySpeed")) {
- } else if (!entry1.first.compare("CurrentTrack")) {
- } else if (!entry1.first.compare("CurrentTrackURI")) {
- } else if (!entry1.first.compare("CurrentTrackMetaData")) {
- } else if (!entry1.first.compare("NumberOfTracks")) {
- } else if (!entry1.first.compare("CurrentMediaDuration")) {
- } else if (!entry1.first.compare("CurrentTrackDuration")) {
- } else if (!entry1.first.compare("AVTransportURI")) {
- } else if (!entry1.first.compare("AVTransportURIMetaData")) {
- } else if (!entry1.first.compare("RelativeTimePosition")) {
- } else if (!entry1.first.compare("AbsoluteTimePosition")) {
- } else if (!entry1.first.compare("NextAVTransportURI")) {
- } else if (!entry1.first.compare("NextAVTransportURIMetaData")){
- } else if (!entry1.first.compare("PlaybackStorageMedium")) {
- } else if (!entry1.first.compare("PossiblePlaybackStorageMedium")) {
- } else if (!entry1.first.compare("RecordStorageMedium")) {
- } else if (!entry1.first.compare("RelativeCounterPosition")) {
- } else if (!entry1.first.compare("AbsoluteCounterPosition")) {
+ m_reporter->changed(entry1.first.c_str(),
+ stringToTpStatus(entry1.second));
+
} else if (!entry1.first.compare("CurrentPlayMode")) {
- } else if (!entry1.first.compare("PossibleRecordStorageMedium")) {
- } else if (!entry1.first.compare("RecordMediumWriteStatus")) {
- } else if (!entry1.first.compare("CurrentRecordQualityMode")) {
- } else if (!entry1.first.compare("PossibleRecordQualityModes")){
+ m_reporter->changed(entry1.first.c_str(),
+ stringToPlayMode(entry1.second));
+
+ } else if (!entry1.first.compare("CurrentTransportActions") ||
+ !entry1.first.compare("CurrentTrackURI") ||
+ !entry1.first.compare("AVTransportURI") ||
+ !entry1.first.compare("NextAVTransportURI")) {
+ m_reporter->changed(entry1.first.c_str(),
+ entry1.second.c_str());
+
+ } else if (!entry1.first.compare("TransportPlaySpeed") ||
+ !entry1.first.compare("CurrentTrack") ||
+ !entry1.first.compare("NumberOfTracks") ||
+ !entry1.first.compare("RelativeCounterPosition") ||
+ !entry1.first.compare("AbsoluteCounterPosition") ||
+ !entry1.first.compare("InstanceID")) {
+ m_reporter->changed(entry1.first.c_str(),
+ atoi(entry1.second.c_str()));
+
+ } else if (!entry1.first.compare("CurrentMediaDuration") ||
+ !entry1.first.compare("CurrentTrackDuration") ||
+ !entry1.first.compare("RelativeTimePosition") ||
+ !entry1.first.compare("AbsoluteTimePosition")) {
+ m_reporter->changed(entry1.first.c_str(),
+ upnpdurationtos(entry1.second));
+
+ } else if (!entry1.first.compare("AVTransportURIMetaData") ||
+ !entry1.first.compare("NextAVTransportURIMetaData") ||
+ !entry1.first.compare("CurrentTrackMetaData")) {
+ UPnPDirContent meta;
+ if (!meta.parse(entry1.second)) {
+ LOGERR("AVTransport event: bad metadata: [" <<
+ entry1.second << "]" << endl);
+ } else {
+ LOGDEB1("AVTransport event: metadata: " <<
+ meta.m_items.size() << " items " << endl);
+ }
+
+ m_reporter->changed(entry1.first.c_str(), meta);
+
+ } else if (!entry1.first.compare("PlaybackStorageMedium") ||
+ !entry1.first.compare("PossiblePlaybackStorageMedium") ||
+ !entry1.first.compare("RecordStorageMedium") ||
+ !entry1.first.compare("PossibleRecordStorageMedium") ||
+ !entry1.first.compare("RecordMediumWriteStatus") ||
+ !entry1.first.compare("CurrentRecordQualityMode") ||
+ !entry1.first.compare("PossibleRecordQualityModes")){
+ m_reporter->changed(entry1.first.c_str(),entry1.second.c_str());
+
+ } else {
+ LOGERR("AVTransport event: unknown variable: name [" <<
+ entry1.first << "] value [" << entry1.second << endl);
+ m_reporter->changed(entry1.first.c_str(),entry1.second.c_str());
}
}
}
}
+
+int AVTransport::setURI(const string& uri, const string& metadata,
+ int instanceID, bool next)
+{
+ SoapEncodeInput args(m_serviceType, next ? "SetNextAVTransportURI" :
+ "SetAVTransportURI");
+ args("InstanceID", SoapHelp::i2s(instanceID))
+ (next ? "NextURI" : "CurrentURI", uri)
+ (next ? "NextURIMetaData" : "CurrentURIMetaData", metadata);
+
+ SoapDecodeOutput data;
+ return runAction(args, data);
+}
+
+int AVTransport::setPlayMode(PlayMode pm, int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "SetPlayMode");
+ string playmode;
+ switch (pm) {
+ case PM_Normal: playmode = "NORMAL"; break;
+ case PM_Shuffle: playmode = "SHUFFLE"; break;
+ case PM_RepeatOne: playmode = "REPEAT_ONE"; break;
+ case PM_RepeatAll: playmode = "REPEAT_ALL"; break;
+ case PM_Random: playmode = "RANDOM"; break;
+ case PM_Direct1: playmode = "DIRECT_1"; break;
+ default: playmode = "NORMAL"; break;
+ }
+
+ args("InstanceID", SoapHelp::i2s(instanceID))
+ ("NewPlayMode", playmode);
+
+ SoapDecodeOutput data;
+ return runAction(args, data);
+}
+
+int AVTransport::getMediaInfo(MediaInfo& info, int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "GetMediaInfo");
+ args("InstanceID", SoapHelp::i2s(instanceID));
+ SoapDecodeOutput data;
+ int ret = runAction(args, data);
+ if (ret != UPNP_E_SUCCESS) {
+ return ret;
+ }
+ string s;
+ data.getInt("NrTracks", &info.nrtracks);
+ data.getString("MediaDuration", &s);
+ info.mduration = upnpdurationtos(s);
+ data.getString("CurrentURI", &info.cururi);
+ data.getString("CurrentURIMetaData", &s);
+ UPnPDirContent meta;
+ meta.parse(s);
+ if (meta.m_items.size() > 0)
+ info.curmeta = meta.m_items[0];
+ meta.clear();
+ data.getString("NextURI", &info.nexturi);
+ data.getString("NextURIMetaData", &s);
+ if (meta.m_items.size() > 0)
+ info.nextmeta = meta.m_items[0];
+ data.getString("PlayMedium", &info.pbstoragemed);
+ data.getString("RecordMedium", &info.pbstoragemed);
+ data.getString("WriteStatus", &info.ws);
+ return 0;
+}
+
+int AVTransport::getTransportInfo(TransportInfo& info, int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "GetTransportInfo");
+ args("InstanceID", SoapHelp::i2s(instanceID));
+ SoapDecodeOutput data;
+ int ret = runAction(args, data);
+ if (ret != UPNP_E_SUCCESS) {
+ return ret;
+ }
+ string s;
+ data.getString("CurrentTransportState", &s);
+ info.tpstate = stringToTpState(s);
+ data.getString("CurrentTransportStatus", &s);
+ info.tpstatus = stringToTpStatus(s);
+ data.getInt("CurrentSpeed", &info.curspeed);
+ return 0;
+}
+
+int AVTransport::getPositionInfo(PositionInfo& info, int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "GetPositionInfo");
+ args("InstanceID", SoapHelp::i2s(instanceID));
+ SoapDecodeOutput data;
+ int ret = runAction(args, data);
+ if (ret != UPNP_E_SUCCESS) {
+ return ret;
+ }
+ string s;
+ data.getInt("Track", &info.track);
+ data.getString("TrackDuration", &s);
+ info.trackduration = upnpdurationtos(s);
+ data.getString("TrackMetaData", &s);
+ UPnPDirContent meta;
+ meta.parse(s);
+ if (meta.m_items.size() > 0) {
+ info.trackmeta = meta.m_items[0];
+ LOGDEB("AVTransport::getPositionInfo: size " <<
+ meta.m_items.size() << " current title: " << meta.m_items[0].m_title
+ << endl);
+ }
+ meta.clear();
+ data.getString("TrackURI", &info.trackuri);
+ data.getString("RelTime", &s);
+ info.reltime = upnpdurationtos(s);
+ data.getString("AbsTime", &s);
+ info.abstime = upnpdurationtos(s);
+ data.getInt("RelCount", &info.relcount);
+ data.getInt("AbsCount", &info.abscount);
+ return 0;
+}
+
+int AVTransport::getDeviceCapabilities(DeviceCapabilities& info, int iID)
+{
+ SoapEncodeInput args(m_serviceType, "GetDeviceCapabilities");
+ args("InstanceID", SoapHelp::i2s(iID));
+ SoapDecodeOutput data;
+ int ret = runAction(args, data);
+ if (ret != UPNP_E_SUCCESS) {
+ return ret;
+ }
+ data.getString("PlayMedia", &info.playmedia);
+ data.getString("RecMedia", &info.recmedia);
+ data.getString("RecQualityModes", &info.recqualitymodes);
+ return 0;
+}
+
+int AVTransport::getTransportSettings(TransportSettings& info, int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "GetTransportSettings");
+ args("InstanceID", SoapHelp::i2s(instanceID));
+ SoapDecodeOutput data;
+ int ret = runAction(args, data);
+ if (ret != UPNP_E_SUCCESS) {
+ return ret;
+ }
+ string s;
+ data.getString("PlayMedia", &s);
+ info.playmode = stringToPlayMode(s);
+ data.getString("RecQualityMode", &info.recqualitymode);
+ return 0;
+}
+
+int AVTransport::getCurrentTransportActions(std::string& actions, int iID)
+{
+ SoapEncodeInput args(m_serviceType, "GetCurrentTransportActions");
+ args("InstanceID", SoapHelp::i2s(iID));
+ SoapDecodeOutput data;
+ int ret = runAction(args, data);
+ if (ret != UPNP_E_SUCCESS) {
+ return ret;
+ }
+ data.getString("Actions", &actions);
+ return 0;
+}
+
+int AVTransport::stop(int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "Stop");
+ args("InstanceID", SoapHelp::i2s(instanceID));
+ SoapDecodeOutput data;
+ return runAction(args, data);
+}
+
+int AVTransport::pause(int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "Pause");
+ args("InstanceID", SoapHelp::i2s(instanceID));
+ SoapDecodeOutput data;
+ return runAction(args, data);
+}
+
+int AVTransport::play(int speed, int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "Play");
+ args("InstanceID", SoapHelp::i2s(instanceID))
+ ("Speed", SoapHelp::i2s(speed));
+ SoapDecodeOutput data;
+ return runAction(args, data);
+}
+
+int AVTransport::seek(SeekMode mode, int target, int instanceID)
+{
+ string sm;
+ switch (mode) {
+ case SEEK_TRACK_NR: sm = "TRACK_NR"; break;
+ case SEEK_ABS_TIME: sm = "ABS_TIME"; break;
+ case SEEK_REL_TIME: sm = "REL_TIME"; break;
+ case SEEK_ABS_COUNT: sm = "ABS_COUNT"; break;
+ case SEEK_REL_COUNT: sm = "REL_COUNT"; break;
+ case SEEK_CHANNEL_FREQ: sm = "CHANNEL_FREQ"; break;
+ case SEEK_TAPE_INDEX: sm = "TAPE-INDEX"; break;
+ case SEEK_FRAME: sm = "FRAME"; break;
+ default:
+ return UPNP_E_INVALID_PARAM;
+ }
+
+ SoapEncodeInput args(m_serviceType, "Play");
+ args("InstanceID", SoapHelp::i2s(instanceID))
+ ("Unit", sm)
+ ("Target", SoapHelp::i2s(target));
+ SoapDecodeOutput data;
+ return runAction(args, data);
+}
+
+int AVTransport::next(int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "Next");
+ args("InstanceID", SoapHelp::i2s(instanceID));
+ SoapDecodeOutput data;
+ return runAction(args, data);
+}
+
+int AVTransport::previous(int instanceID)
+{
+ SoapEncodeInput args(m_serviceType, "Previous");
+ args("InstanceID", SoapHelp::i2s(instanceID));
+ SoapDecodeOutput data;
+ return runAction(args, data);
+}
+
void AVTransport::registerCallback()
{
Service::registerCallback(bind(&AVTransport::evtCallback, this, _1));