2 * Copyright (C) 2012-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
20 #include "network/Network.h"
21 #include "UPnPRenderer.h"
23 #include "UPnPInternal.h"
25 #include "Application.h"
26 #include "ApplicationMessenger.h"
28 #include "filesystem/SpecialProtocol.h"
29 #include "GUIInfoManager.h"
30 #include "guilib/GUIWindowManager.h"
31 #include "guilib/Key.h"
32 #include "pictures/GUIWindowSlideShow.h"
33 #include "pictures/PictureInfoTag.h"
34 #include "interfaces/AnnouncementManager.h"
35 #include "settings/Settings.h"
36 #include "TextureDatabase.h"
37 #include "ThumbLoader.h"
39 #include "utils/URIUtils.h"
40 #include "utils/Variant.h"
41 #include "utils/StringUtils.h"
42 #include "playlists/PlayList.h"
43 #include "GUIUserMessages.h"
45 using namespace ANNOUNCEMENT;
50 /*----------------------------------------------------------------------
51 | CUPnPRenderer::CUPnPRenderer
52 +---------------------------------------------------------------------*/
53 CUPnPRenderer::CUPnPRenderer(const char* friendly_name, bool show_ip /*= false*/,
54 const char* uuid /*= NULL*/, unsigned int port /*= 0*/)
55 : PLT_MediaRenderer(friendly_name, show_ip, uuid, port)
57 CAnnouncementManager::AddAnnouncer(this);
60 /*----------------------------------------------------------------------
61 | CUPnPRenderer::~CUPnPRenderer
62 +---------------------------------------------------------------------*/
63 CUPnPRenderer::~CUPnPRenderer()
65 CAnnouncementManager::RemoveAnnouncer(this);
68 /*----------------------------------------------------------------------
69 | CUPnPRenderer::SetupServices
70 +---------------------------------------------------------------------*/
72 CUPnPRenderer::SetupServices()
74 NPT_CHECK(PLT_MediaRenderer::SetupServices());
76 // update what we can play
77 PLT_Service* service = NULL;
78 NPT_CHECK_FATAL(FindServiceByType("urn:schemas-upnp-org:service:ConnectionManager:1", service));
79 service->SetStateVariable("SinkProtocolInfo"
82 ",http-get:*:audio/mkv:*"
83 ",http-get:*:audio/mpegurl:*"
84 ",http-get:*:audio/mpeg:*"
85 ",http-get:*:audio/mpeg3:*"
86 ",http-get:*:audio/mp3:*"
87 ",http-get:*:audio/mp4:*"
88 ",http-get:*:audio/basic:*"
89 ",http-get:*:audio/midi:*"
90 ",http-get:*:audio/ulaw:*"
91 ",http-get:*:audio/ogg:*"
92 ",http-get:*:audio/DVI4:*"
93 ",http-get:*:audio/G722:*"
94 ",http-get:*:audio/G723:*"
95 ",http-get:*:audio/G726-16:*"
96 ",http-get:*:audio/G726-24:*"
97 ",http-get:*:audio/G726-32:*"
98 ",http-get:*:audio/G726-40:*"
99 ",http-get:*:audio/G728:*"
100 ",http-get:*:audio/G729:*"
101 ",http-get:*:audio/G729D:*"
102 ",http-get:*:audio/G729E:*"
103 ",http-get:*:audio/GSM:*"
104 ",http-get:*:audio/GSM-EFR:*"
105 ",http-get:*:audio/L8:*"
106 ",http-get:*:audio/L16:*"
107 ",http-get:*:audio/LPC:*"
108 ",http-get:*:audio/MPA:*"
109 ",http-get:*:audio/PCMA:*"
110 ",http-get:*:audio/PCMU:*"
111 ",http-get:*:audio/QCELP:*"
112 ",http-get:*:audio/RED:*"
113 ",http-get:*:audio/VDVI:*"
114 ",http-get:*:audio/ac3:*"
115 ",http-get:*:audio/vorbis:*"
116 ",http-get:*:audio/speex:*"
117 ",http-get:*:audio/flac:*"
118 ",http-get:*:audio/x-flac:*"
119 ",http-get:*:audio/x-aiff:*"
120 ",http-get:*:audio/x-pn-realaudio:*"
121 ",http-get:*:audio/x-realaudio:*"
122 ",http-get:*:audio/x-wav:*"
123 ",http-get:*:audio/x-matroska:*"
124 ",http-get:*:audio/x-ms-wma:*"
125 ",http-get:*:audio/x-mpegurl:*"
126 ",http-get:*:application/x-shockwave-flash:*"
127 ",http-get:*:application/ogg:*"
128 ",http-get:*:application/sdp:*"
129 ",http-get:*:image/gif:*"
130 ",http-get:*:image/jpeg:*"
131 ",http-get:*:image/ief:*"
132 ",http-get:*:image/png:*"
133 ",http-get:*:image/tiff:*"
134 ",http-get:*:video/avi:*"
135 ",http-get:*:video/divx:*"
136 ",http-get:*:video/mpeg:*"
137 ",http-get:*:video/fli:*"
138 ",http-get:*:video/flv:*"
139 ",http-get:*:video/quicktime:*"
140 ",http-get:*:video/vnd.vivo:*"
141 ",http-get:*:video/vc1:*"
142 ",http-get:*:video/ogg:*"
143 ",http-get:*:video/mp4:*"
144 ",http-get:*:video/mkv:*"
145 ",http-get:*:video/BT656:*"
146 ",http-get:*:video/CelB:*"
147 ",http-get:*:video/JPEG:*"
148 ",http-get:*:video/H261:*"
149 ",http-get:*:video/H263:*"
150 ",http-get:*:video/H263-1998:*"
151 ",http-get:*:video/H263-2000:*"
152 ",http-get:*:video/MPV:*"
153 ",http-get:*:video/MP2T:*"
154 ",http-get:*:video/MP1S:*"
155 ",http-get:*:video/MP2P:*"
156 ",http-get:*:video/BMPEG:*"
157 ",http-get:*:video/xvid:*"
158 ",http-get:*:video/x-divx:*"
159 ",http-get:*:video/x-matroska:*"
160 ",http-get:*:video/x-mkv:*"
161 ",http-get:*:video/x-ms-wmv:*"
162 ",http-get:*:video/x-ms-avi:*"
163 ",http-get:*:video/x-flv:*"
164 ",http-get:*:video/x-fli:*"
165 ",http-get:*:video/x-ms-asf:*"
166 ",http-get:*:video/x-ms-asx:*"
167 ",http-get:*:video/x-ms-wmx:*"
168 ",http-get:*:video/x-ms-wvx:*"
169 ",http-get:*:video/x-msvideo:*"
170 ",http-get:*:video/x-xvid:*"
173 NPT_CHECK_FATAL(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
174 service->SetStateVariable("NextAVTransportURI", "");
175 service->SetStateVariable("NextAVTransportURIMetadata", "");
180 /*----------------------------------------------------------------------
181 | CUPnPRenderer::ProcessHttpRequest
182 +---------------------------------------------------------------------*/
184 CUPnPRenderer::ProcessHttpGetRequest(NPT_HttpRequest& request,
185 const NPT_HttpRequestContext& context,
186 NPT_HttpResponse& response)
188 // get the address of who sent us some data back
189 NPT_String ip_address = context.GetRemoteAddress().GetIpAddress().ToString();
190 NPT_String method = request.GetMethod();
191 NPT_String protocol = request.GetProtocol();
192 NPT_HttpUrl url = request.GetUrl();
194 if (url.GetPath() == "/thumb") {
195 NPT_HttpUrlQuery query(url.GetQuery());
196 NPT_String filepath = query.GetField("path");
197 if (!filepath.IsEmpty()) {
198 NPT_HttpEntity* entity = response.GetEntity();
199 if (entity == NULL) return NPT_ERROR_INVALID_STATE;
202 if (request.GetMethod() != NPT_HTTP_METHOD_GET &&
203 request.GetMethod() != NPT_HTTP_METHOD_HEAD) {
204 response.SetStatus(405, "Method Not Allowed");
208 // prevent hackers from accessing files outside of our root
209 if ((filepath.Find("/..") >= 0) || (filepath.Find("\\..") >=0)) {
214 CStdString path (CURL::Decode((const char*) filepath));
215 NPT_File file(path.c_str());
216 NPT_Result result = file.Open(NPT_FILE_OPEN_MODE_READ);
217 if (NPT_FAILED(result)) {
218 response.SetStatus(404, "Not Found");
221 NPT_InputStreamReference stream;
222 file.GetInputStream(stream);
223 entity->SetContentType(GetMimeType(filepath));
224 entity->SetInputStream(stream, true);
230 return PLT_MediaRenderer::ProcessHttpGetRequest(request, context, response);
233 /*----------------------------------------------------------------------
234 | CUPnPRenderer::Announce
235 +---------------------------------------------------------------------*/
237 CUPnPRenderer::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
239 if (strcmp(sender, "xbmc") != 0)
242 NPT_AutoLock lock(m_state);
243 PLT_Service *avt, *rct;
245 if (flag == Player) {
246 if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", avt)))
248 if (strcmp(message, "OnPlay") == 0) {
249 avt->SetStateVariable("AVTransportURI", g_application.CurrentFile().c_str());
250 avt->SetStateVariable("CurrentTrackURI", g_application.CurrentFile().c_str());
253 if (NPT_SUCCEEDED(GetMetadata(meta))) {
254 avt->SetStateVariable("CurrentTrackMetadata", meta);
255 avt->SetStateVariable("AVTransportURIMetaData", meta);
258 avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
259 avt->SetStateVariable("TransportState", "PLAYING");
261 /* this could be a transition to next track, so clear next */
262 avt->SetStateVariable("NextAVTransportURI", "");
263 avt->SetStateVariable("NextAVTransportURIMetaData", "");
265 else if (strcmp(message, "OnPause") == 0) {
266 avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
267 avt->SetStateVariable("TransportState", "PAUSED_PLAYBACK");
269 else if (strcmp(message, "OnSpeedChanged") == 0) {
270 avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
273 else if (flag == Application && strcmp(message, "OnVolumeChanged") == 0) {
274 if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:RenderingControl:1", rct)))
279 buffer = StringUtils::Format("%ld", data["volume"].asInteger());
280 rct->SetStateVariable("Volume", buffer.c_str());
282 buffer = StringUtils::Format("%ld", 256 * (data["volume"].asInteger() * 60 - 60) / 100);
283 rct->SetStateVariable("VolumeDb", buffer.c_str());
285 rct->SetStateVariable("Mute", data["muted"].asBoolean() ? "1" : "0");
289 /*----------------------------------------------------------------------
290 | CUPnPRenderer::UpdateState
291 +---------------------------------------------------------------------*/
293 CUPnPRenderer::UpdateState()
295 NPT_AutoLock lock(m_state);
299 if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", avt)))
302 /* don't update state while transitioning */
304 avt->GetStateVariableValue("TransportState", state);
305 if(state == "TRANSITIONING")
308 avt->SetStateVariable("TransportStatus", "OK");
310 if (g_application.m_pPlayer->IsPlaying() || g_application.m_pPlayer->IsPausedPlayback()) {
311 avt->SetStateVariable("NumberOfTracks", "1");
312 avt->SetStateVariable("CurrentTrack", "1");
314 CStdString buffer = g_infoManager.GetCurrentPlayTime(TIME_FORMAT_HH_MM_SS);
315 avt->SetStateVariable("RelativeTimePosition", buffer.c_str());
316 avt->SetStateVariable("AbsoluteTimePosition", buffer.c_str());
318 buffer = g_infoManager.GetDuration(TIME_FORMAT_HH_MM_SS);
319 if (buffer.length() > 0) {
320 avt->SetStateVariable("CurrentTrackDuration", buffer.c_str());
321 avt->SetStateVariable("CurrentMediaDuration", buffer.c_str());
323 avt->SetStateVariable("CurrentTrackDuration", "00:00:00");
324 avt->SetStateVariable("CurrentMediaDuration", "00:00:00");
327 } else if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
328 avt->SetStateVariable("TransportState", "PLAYING");
330 avt->SetStateVariable("AVTransportURI" , g_infoManager.GetPictureLabel(SLIDE_FILE_PATH));
331 avt->SetStateVariable("CurrentTrackURI", g_infoManager.GetPictureLabel(SLIDE_FILE_PATH));
332 avt->SetStateVariable("TransportPlaySpeed", "1");
334 CGUIWindowSlideShow *slideshow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
338 index = StringUtils::Format("%d", slideshow->NumSlides());
339 avt->SetStateVariable("NumberOfTracks", index.c_str());
340 index = StringUtils::Format("%d", slideshow->CurrentSlide());
341 avt->SetStateVariable("CurrentTrack", index.c_str());
345 avt->SetStateVariable("CurrentTrackMetadata", "");
346 avt->SetStateVariable("AVTransportURIMetaData", "");
349 avt->SetStateVariable("TransportState", "STOPPED");
350 avt->SetStateVariable("TransportPlaySpeed", "1");
351 avt->SetStateVariable("NumberOfTracks", "0");
352 avt->SetStateVariable("CurrentTrack", "0");
353 avt->SetStateVariable("RelativeTimePosition", "00:00:00");
354 avt->SetStateVariable("AbsoluteTimePosition", "00:00:00");
355 avt->SetStateVariable("CurrentTrackDuration", "00:00:00");
356 avt->SetStateVariable("CurrentMediaDuration", "00:00:00");
357 avt->SetStateVariable("NextAVTransportURI", "");
358 avt->SetStateVariable("NextAVTransportURIMetaData", "");
362 /*----------------------------------------------------------------------
363 | CUPnPRenderer::SetupIcons
364 +---------------------------------------------------------------------*/
366 CUPnPRenderer::SetupIcons()
368 NPT_String file_root = CSpecialProtocol::TranslatePath("special://xbmc/media/").c_str();
370 PLT_DeviceIcon("image/png", 256, 256, 24, "/icon-flat-256x256.png"),
373 PLT_DeviceIcon("image/png", 120, 120, 24, "/icon-flat-120x120.png"),
378 /*----------------------------------------------------------------------
379 | CUPnPRenderer::GetMetadata
380 +---------------------------------------------------------------------*/
382 CUPnPRenderer::GetMetadata(NPT_String& meta)
384 NPT_Result res = NPT_FAILURE;
385 CFileItem item(g_application.CurrentFileItem());
386 NPT_String file_path, tmp;
388 // we pass an empty CThumbLoader reference, as it can't be used
389 // without CUPnPServer enabled
390 NPT_Reference<CThumbLoader> thumb_loader;
391 PLT_MediaObject* object = BuildObject(item, file_path, false, thumb_loader);
393 // fetch the item's artwork
395 if (object->m_ObjectClass.type == "object.item.audioItem.musicTrack")
396 thumb = g_infoManager.GetImage(MUSICPLAYER_COVER, -1);
398 thumb = g_infoManager.GetImage(VIDEOPLAYER_COVER, -1);
400 thumb = CTextureUtils::GetWrappedImageURL(thumb);
403 if (g_application.getNetwork().GetFirstConnectedInterface()) {
404 ip = g_application.getNetwork().GetFirstConnectedInterface()->GetCurrentIPAddress().c_str();
406 // build url, use the internal device http server to serv the image
407 NPT_HttpUrlQuery query;
408 query.AddField("path", thumb.c_str());
409 PLT_AlbumArtInfo art;
410 art.uri = NPT_HttpUrl(
412 m_URLDescription.GetPort(),
414 query.ToString()).ToString();
415 // Set DLNA profileID by extension, defaulting to JPEG.
416 if (URIUtils::HasExtension(item.GetArt("thumb"), ".png")) {
417 art.dlna_profile = "PNG_TN";
419 art.dlna_profile = "JPEG_TN";
421 object->m_ExtraInfo.album_arts.Add(art);
423 res = PLT_Didl::ToDidl(*object, "*", tmp);
424 meta = didl_header + tmp + didl_footer;
430 /*----------------------------------------------------------------------
431 | CUPnPRenderer::OnNext
432 +---------------------------------------------------------------------*/
434 CUPnPRenderer::OnNext(PLT_ActionReference& action)
436 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
437 CAction action(ACTION_NEXT_PICTURE);
438 CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
440 CApplicationMessenger::Get().PlayListPlayerNext();
445 /*----------------------------------------------------------------------
446 | CUPnPRenderer::OnPause
447 +---------------------------------------------------------------------*/
449 CUPnPRenderer::OnPause(PLT_ActionReference& action)
451 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
452 CAction action(ACTION_PAUSE);
453 CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
454 } else if (!g_application.m_pPlayer->IsPausedPlayback())
455 CApplicationMessenger::Get().MediaPause();
459 /*----------------------------------------------------------------------
460 | CUPnPRenderer::OnPlay
461 +---------------------------------------------------------------------*/
463 CUPnPRenderer::OnPlay(PLT_ActionReference& action)
465 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
467 } else if (g_application.m_pPlayer->IsPausedPlayback()) {
468 CApplicationMessenger::Get().MediaPause();
469 } else if (!g_application.m_pPlayer->IsPlaying()) {
470 NPT_String uri, meta;
471 PLT_Service* service;
472 // look for value set previously by SetAVTransportURI
473 NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
474 NPT_CHECK_SEVERE(service->GetStateVariableValue("AVTransportURI", uri));
475 NPT_CHECK_SEVERE(service->GetStateVariableValue("AVTransportURIMetaData", meta));
477 // if not set, use the current file being played
478 PlayMedia(uri, meta);
483 /*----------------------------------------------------------------------
484 | CUPnPRenderer::OnPrevious
485 +---------------------------------------------------------------------*/
487 CUPnPRenderer::OnPrevious(PLT_ActionReference& action)
489 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
490 CAction action(ACTION_PREV_PICTURE);
491 CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
493 CApplicationMessenger::Get().PlayListPlayerPrevious();
498 /*----------------------------------------------------------------------
499 | CUPnPRenderer::OnStop
500 +---------------------------------------------------------------------*/
502 CUPnPRenderer::OnStop(PLT_ActionReference& action)
504 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
505 CAction action(ACTION_STOP);
506 CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
508 CApplicationMessenger::Get().MediaStop();
513 /*----------------------------------------------------------------------
514 | CUPnPRenderer::OnSetAVTransportURI
515 +---------------------------------------------------------------------*/
517 CUPnPRenderer::OnSetAVTransportURI(PLT_ActionReference& action)
519 NPT_String uri, meta;
520 PLT_Service* service;
521 NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
523 NPT_CHECK_SEVERE(action->GetArgumentValue("CurrentURI", uri));
524 NPT_CHECK_SEVERE(action->GetArgumentValue("CurrentURIMetaData", meta));
526 // if not playing already, just keep around uri & metadata
527 // and wait for play command
528 if (!g_application.m_pPlayer->IsPlaying() && g_windowManager.GetActiveWindow() != WINDOW_SLIDESHOW) {
529 service->SetStateVariable("TransportState", "STOPPED");
530 service->SetStateVariable("TransportStatus", "OK");
531 service->SetStateVariable("TransportPlaySpeed", "1");
532 service->SetStateVariable("AVTransportURI", uri);
533 service->SetStateVariable("AVTransportURIMetaData", meta);
534 service->SetStateVariable("NextAVTransportURI", "");
535 service->SetStateVariable("NextAVTransportURIMetaData", "");
537 NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
541 return PlayMedia(uri, meta, action.AsPointer());
544 /*----------------------------------------------------------------------
545 | CUPnPRenderer::OnSetAVTransportURI
546 +---------------------------------------------------------------------*/
548 CUPnPRenderer::OnSetNextAVTransportURI(PLT_ActionReference& action)
550 NPT_String uri, meta;
551 PLT_Service* service;
552 NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
554 NPT_CHECK_SEVERE(action->GetArgumentValue("NextURI", uri));
555 NPT_CHECK_SEVERE(action->GetArgumentValue("NextURIMetaData", meta));
557 CFileItemPtr item = GetFileItem(uri, meta);
562 if (g_application.m_pPlayer->IsPlaying()) {
564 int playlist = PLAYLIST_MUSIC;
566 playlist = PLAYLIST_VIDEO;
568 { CSingleLock lock(g_graphicsContext);
569 g_playlistPlayer.ClearPlaylist(playlist);
570 g_playlistPlayer.Add(playlist, item);
572 g_playlistPlayer.SetCurrentSong(-1);
573 g_playlistPlayer.SetCurrentPlaylist(playlist);
576 CGUIMessage msg(GUI_MSG_PLAYLIST_CHANGED, 0, 0);
577 g_windowManager.SendThreadMessage(msg);
580 service->SetStateVariable("NextAVTransportURI", uri);
581 service->SetStateVariable("NextAVTransportURIMetaData", meta);
583 NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
587 } else if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
594 /*----------------------------------------------------------------------
595 | CUPnPRenderer::PlayMedia
596 +---------------------------------------------------------------------*/
598 CUPnPRenderer::PlayMedia(const NPT_String& uri, const NPT_String& meta, PLT_Action* action)
600 PLT_Service* service;
601 NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
603 { NPT_AutoLock lock(m_state);
604 service->SetStateVariable("TransportState", "TRANSITIONING");
605 service->SetStateVariable("TransportStatus", "OK");
608 CFileItemPtr item = GetFileItem(uri, meta);
613 if (item->IsPicture()) {
614 CApplicationMessenger::Get().PictureShow(item->GetPath());
616 CApplicationMessenger::Get().MediaPlay(*item);
619 if (g_application.m_pPlayer->IsPlaying() || g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
620 NPT_AutoLock lock(m_state);
621 service->SetStateVariable("TransportState", "PLAYING");
622 service->SetStateVariable("TransportStatus", "OK");
623 service->SetStateVariable("AVTransportURI", uri);
624 service->SetStateVariable("AVTransportURIMetaData", meta);
626 NPT_AutoLock lock(m_state);
627 service->SetStateVariable("TransportState", "STOPPED");
628 service->SetStateVariable("TransportStatus", "ERROR_OCCURRED");
631 service->SetStateVariable("NextAVTransportURI", "");
632 service->SetStateVariable("NextAVTransportURIMetaData", "");
635 NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
640 /*----------------------------------------------------------------------
641 | CUPnPRenderer::OnSetVolume
642 +---------------------------------------------------------------------*/
644 CUPnPRenderer::OnSetVolume(PLT_ActionReference& action)
647 NPT_CHECK_SEVERE(action->GetArgumentValue("DesiredVolume", volume));
648 g_application.SetVolume((float)strtod((const char*)volume, NULL));
652 /*----------------------------------------------------------------------
653 | CUPnPRenderer::OnSetMute
654 +---------------------------------------------------------------------*/
656 CUPnPRenderer::OnSetMute(PLT_ActionReference& action)
659 NPT_CHECK_SEVERE(action->GetArgumentValue("DesiredMute",mute));
660 if((mute == "1") ^ g_application.IsMuted())
661 g_application.ToggleMute();
665 /*----------------------------------------------------------------------
666 | CUPnPRenderer::OnSeek
667 +---------------------------------------------------------------------*/
669 CUPnPRenderer::OnSeek(PLT_ActionReference& action)
671 if (!g_application.m_pPlayer->IsPlaying()) return NPT_ERROR_INVALID_STATE;
673 NPT_String unit, target;
674 NPT_CHECK_SEVERE(action->GetArgumentValue("Unit", unit));
675 NPT_CHECK_SEVERE(action->GetArgumentValue("Target", target));
677 if (!unit.Compare("REL_TIME")) {
678 // converts target to seconds
680 NPT_CHECK_SEVERE(PLT_Didl::ParseTimeStamp(target, seconds));
681 g_application.SeekTime(seconds);
687 } /* namespace UPNP */