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 "playlists/PlayList.h"
42 #include "GUIUserMessages.h"
44 using namespace ANNOUNCEMENT;
49 /*----------------------------------------------------------------------
50 | CUPnPRenderer::CUPnPRenderer
51 +---------------------------------------------------------------------*/
52 CUPnPRenderer::CUPnPRenderer(const char* friendly_name, bool show_ip /*= false*/,
53 const char* uuid /*= NULL*/, unsigned int port /*= 0*/)
54 : PLT_MediaRenderer(friendly_name, show_ip, uuid, port)
56 CAnnouncementManager::AddAnnouncer(this);
59 /*----------------------------------------------------------------------
60 | CUPnPRenderer::~CUPnPRenderer
61 +---------------------------------------------------------------------*/
62 CUPnPRenderer::~CUPnPRenderer()
64 CAnnouncementManager::RemoveAnnouncer(this);
67 /*----------------------------------------------------------------------
68 | CUPnPRenderer::SetupServices
69 +---------------------------------------------------------------------*/
71 CUPnPRenderer::SetupServices()
73 NPT_CHECK(PLT_MediaRenderer::SetupServices());
75 // update what we can play
76 PLT_Service* service = NULL;
77 NPT_CHECK_FATAL(FindServiceByType("urn:schemas-upnp-org:service:ConnectionManager:1", service));
78 service->SetStateVariable("SinkProtocolInfo"
81 ",http-get:*:audio/mkv:*"
82 ",http-get:*:audio/mpegurl:*"
83 ",http-get:*:audio/mpeg:*"
84 ",http-get:*:audio/mpeg3:*"
85 ",http-get:*:audio/mp3:*"
86 ",http-get:*:audio/mp4:*"
87 ",http-get:*:audio/basic:*"
88 ",http-get:*:audio/midi:*"
89 ",http-get:*:audio/ulaw:*"
90 ",http-get:*:audio/ogg:*"
91 ",http-get:*:audio/DVI4:*"
92 ",http-get:*:audio/G722:*"
93 ",http-get:*:audio/G723:*"
94 ",http-get:*:audio/G726-16:*"
95 ",http-get:*:audio/G726-24:*"
96 ",http-get:*:audio/G726-32:*"
97 ",http-get:*:audio/G726-40:*"
98 ",http-get:*:audio/G728:*"
99 ",http-get:*:audio/G729:*"
100 ",http-get:*:audio/G729D:*"
101 ",http-get:*:audio/G729E:*"
102 ",http-get:*:audio/GSM:*"
103 ",http-get:*:audio/GSM-EFR:*"
104 ",http-get:*:audio/L8:*"
105 ",http-get:*:audio/L16:*"
106 ",http-get:*:audio/LPC:*"
107 ",http-get:*:audio/MPA:*"
108 ",http-get:*:audio/PCMA:*"
109 ",http-get:*:audio/PCMU:*"
110 ",http-get:*:audio/QCELP:*"
111 ",http-get:*:audio/RED:*"
112 ",http-get:*:audio/VDVI:*"
113 ",http-get:*:audio/ac3:*"
114 ",http-get:*:audio/vorbis:*"
115 ",http-get:*:audio/speex:*"
116 ",http-get:*:audio/flac:*"
117 ",http-get:*:audio/x-flac:*"
118 ",http-get:*:audio/x-aiff:*"
119 ",http-get:*:audio/x-pn-realaudio:*"
120 ",http-get:*:audio/x-realaudio:*"
121 ",http-get:*:audio/x-wav:*"
122 ",http-get:*:audio/x-matroska:*"
123 ",http-get:*:audio/x-ms-wma:*"
124 ",http-get:*:audio/x-mpegurl:*"
125 ",http-get:*:application/x-shockwave-flash:*"
126 ",http-get:*:application/ogg:*"
127 ",http-get:*:application/sdp:*"
128 ",http-get:*:image/gif:*"
129 ",http-get:*:image/jpeg:*"
130 ",http-get:*:image/ief:*"
131 ",http-get:*:image/png:*"
132 ",http-get:*:image/tiff:*"
133 ",http-get:*:video/avi:*"
134 ",http-get:*:video/divx:*"
135 ",http-get:*:video/mpeg:*"
136 ",http-get:*:video/fli:*"
137 ",http-get:*:video/flv:*"
138 ",http-get:*:video/quicktime:*"
139 ",http-get:*:video/vnd.vivo:*"
140 ",http-get:*:video/vc1:*"
141 ",http-get:*:video/ogg:*"
142 ",http-get:*:video/mp4:*"
143 ",http-get:*:video/mkv:*"
144 ",http-get:*:video/BT656:*"
145 ",http-get:*:video/CelB:*"
146 ",http-get:*:video/JPEG:*"
147 ",http-get:*:video/H261:*"
148 ",http-get:*:video/H263:*"
149 ",http-get:*:video/H263-1998:*"
150 ",http-get:*:video/H263-2000:*"
151 ",http-get:*:video/MPV:*"
152 ",http-get:*:video/MP2T:*"
153 ",http-get:*:video/MP1S:*"
154 ",http-get:*:video/MP2P:*"
155 ",http-get:*:video/BMPEG:*"
156 ",http-get:*:video/xvid:*"
157 ",http-get:*:video/x-divx:*"
158 ",http-get:*:video/x-matroska:*"
159 ",http-get:*:video/x-ms-wmv:*"
160 ",http-get:*:video/x-ms-avi:*"
161 ",http-get:*:video/x-flv:*"
162 ",http-get:*:video/x-fli:*"
163 ",http-get:*:video/x-ms-asf:*"
164 ",http-get:*:video/x-ms-asx:*"
165 ",http-get:*:video/x-ms-wmx:*"
166 ",http-get:*:video/x-ms-wvx:*"
167 ",http-get:*:video/x-msvideo:*"
168 ",http-get:*:video/x-xvid:*"
171 NPT_CHECK_FATAL(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
172 service->SetStateVariable("NextAVTransportURI", "");
173 service->SetStateVariable("NextAVTransportURIMetadata", "");
178 /*----------------------------------------------------------------------
179 | CUPnPRenderer::ProcessHttpRequest
180 +---------------------------------------------------------------------*/
182 CUPnPRenderer::ProcessHttpGetRequest(NPT_HttpRequest& request,
183 const NPT_HttpRequestContext& context,
184 NPT_HttpResponse& response)
186 // get the address of who sent us some data back
187 NPT_String ip_address = context.GetRemoteAddress().GetIpAddress().ToString();
188 NPT_String method = request.GetMethod();
189 NPT_String protocol = request.GetProtocol();
190 NPT_HttpUrl url = request.GetUrl();
192 if (url.GetPath() == "/thumb") {
193 NPT_HttpUrlQuery query(url.GetQuery());
194 NPT_String filepath = query.GetField("path");
195 if (!filepath.IsEmpty()) {
196 NPT_HttpEntity* entity = response.GetEntity();
197 if (entity == NULL) return NPT_ERROR_INVALID_STATE;
200 if (request.GetMethod() != NPT_HTTP_METHOD_GET &&
201 request.GetMethod() != NPT_HTTP_METHOD_HEAD) {
202 response.SetStatus(405, "Method Not Allowed");
206 // prevent hackers from accessing files outside of our root
207 if ((filepath.Find("/..") >= 0) || (filepath.Find("\\..") >=0)) {
212 CStdString path = CURL::Decode((const char*) filepath);
213 NPT_File file(path.c_str());
214 NPT_Result result = file.Open(NPT_FILE_OPEN_MODE_READ);
215 if (NPT_FAILED(result)) {
216 response.SetStatus(404, "Not Found");
219 NPT_InputStreamReference stream;
220 file.GetInputStream(stream);
221 entity->SetContentType(GetMimeType(filepath));
222 entity->SetInputStream(stream, true);
228 return PLT_MediaRenderer::ProcessHttpGetRequest(request, context, response);
231 /*----------------------------------------------------------------------
232 | CUPnPRenderer::Announce
233 +---------------------------------------------------------------------*/
235 CUPnPRenderer::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
237 if (strcmp(sender, "xbmc") != 0)
240 NPT_AutoLock lock(m_state);
241 PLT_Service *avt, *rct;
243 if (flag == Player) {
244 if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", avt)))
246 if (strcmp(message, "OnPlay") == 0) {
247 avt->SetStateVariable("AVTransportURI", g_application.CurrentFile().c_str());
248 avt->SetStateVariable("CurrentTrackURI", g_application.CurrentFile().c_str());
251 if (NPT_SUCCEEDED(GetMetadata(meta))) {
252 avt->SetStateVariable("CurrentTrackMetadata", meta);
253 avt->SetStateVariable("AVTransportURIMetaData", meta);
256 avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
257 avt->SetStateVariable("TransportState", "PLAYING");
259 /* this could be a transition to next track, so clear next */
260 avt->SetStateVariable("NextAVTransportURI", "");
261 avt->SetStateVariable("NextAVTransportURIMetaData", "");
263 else if (strcmp(message, "OnPause") == 0) {
264 avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
265 avt->SetStateVariable("TransportState", "PAUSED_PLAYBACK");
267 else if (strcmp(message, "OnSpeedChanged") == 0) {
268 avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
271 else if (flag == Application && strcmp(message, "OnVolumeChanged") == 0) {
272 if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:RenderingControl:1", rct)))
277 buffer.Format("%ld", data["volume"].asInteger());
278 rct->SetStateVariable("Volume", buffer.c_str());
280 buffer.Format("%ld", 256 * (data["volume"].asInteger() * 60 - 60) / 100);
281 rct->SetStateVariable("VolumeDb", buffer.c_str());
283 rct->SetStateVariable("Mute", data["muted"].asBoolean() ? "1" : "0");
287 /*----------------------------------------------------------------------
288 | CUPnPRenderer::UpdateState
289 +---------------------------------------------------------------------*/
291 CUPnPRenderer::UpdateState()
293 NPT_AutoLock lock(m_state);
297 if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", avt)))
300 /* don't update state while transitioning */
302 avt->GetStateVariableValue("TransportState", state);
303 if(state == "TRANSITIONING")
306 avt->SetStateVariable("TransportStatus", "OK");
308 if (g_application.m_pPlayer->IsPlaying() || g_application.m_pPlayer->IsPausedPlayback()) {
309 avt->SetStateVariable("NumberOfTracks", "1");
310 avt->SetStateVariable("CurrentTrack", "1");
312 CStdString buffer = g_infoManager.GetCurrentPlayTime(TIME_FORMAT_HH_MM_SS);
313 avt->SetStateVariable("RelativeTimePosition", buffer.c_str());
314 avt->SetStateVariable("AbsoluteTimePosition", buffer.c_str());
316 buffer = g_infoManager.GetDuration(TIME_FORMAT_HH_MM_SS);
317 if (buffer.length() > 0) {
318 avt->SetStateVariable("CurrentTrackDuration", buffer.c_str());
319 avt->SetStateVariable("CurrentMediaDuration", buffer.c_str());
321 avt->SetStateVariable("CurrentTrackDuration", "00:00:00");
322 avt->SetStateVariable("CurrentMediaDuration", "00:00:00");
325 } else if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
326 avt->SetStateVariable("TransportState", "PLAYING");
328 avt->SetStateVariable("AVTransportURI" , g_infoManager.GetPictureLabel(SLIDE_FILE_PATH));
329 avt->SetStateVariable("CurrentTrackURI", g_infoManager.GetPictureLabel(SLIDE_FILE_PATH));
330 avt->SetStateVariable("TransportPlaySpeed", "1");
332 CGUIWindowSlideShow *slideshow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
336 index.Format("%d", slideshow->NumSlides());
337 avt->SetStateVariable("NumberOfTracks", index.c_str());
338 index.Format("%d", slideshow->CurrentSlide());
339 avt->SetStateVariable("CurrentTrack", index.c_str());
343 avt->SetStateVariable("CurrentTrackMetadata", "");
344 avt->SetStateVariable("AVTransportURIMetaData", "");
347 avt->SetStateVariable("TransportState", "STOPPED");
348 avt->SetStateVariable("TransportPlaySpeed", "1");
349 avt->SetStateVariable("NumberOfTracks", "0");
350 avt->SetStateVariable("CurrentTrack", "0");
351 avt->SetStateVariable("RelativeTimePosition", "00:00:00");
352 avt->SetStateVariable("AbsoluteTimePosition", "00:00:00");
353 avt->SetStateVariable("CurrentTrackDuration", "00:00:00");
354 avt->SetStateVariable("CurrentMediaDuration", "00:00:00");
355 avt->SetStateVariable("NextAVTransportURI", "");
356 avt->SetStateVariable("NextAVTransportURIMetaData", "");
360 /*----------------------------------------------------------------------
361 | CUPnPRenderer::SetupIcons
362 +---------------------------------------------------------------------*/
364 CUPnPRenderer::SetupIcons()
366 NPT_String file_root = CSpecialProtocol::TranslatePath("special://xbmc/media/").c_str();
368 PLT_DeviceIcon("image/png", 256, 256, 24, "/icon-flat-256x256.png"),
371 PLT_DeviceIcon("image/png", 120, 120, 24, "/icon-flat-120x120.png"),
376 /*----------------------------------------------------------------------
377 | CUPnPRenderer::GetMetadata
378 +---------------------------------------------------------------------*/
380 CUPnPRenderer::GetMetadata(NPT_String& meta)
382 NPT_Result res = NPT_FAILURE;
383 CFileItem item(g_application.CurrentFileItem());
384 NPT_String file_path, tmp;
386 // we pass an empty CThumbLoader reference, as it can't be used
387 // without CUPnPServer enabled
388 NPT_Reference<CThumbLoader> thumb_loader;
389 PLT_MediaObject* object = BuildObject(item, file_path, false, thumb_loader);
391 // fetch the item's artwork
393 if (object->m_ObjectClass.type == "object.item.audioItem.musicTrack")
394 thumb = g_infoManager.GetImage(MUSICPLAYER_COVER, -1);
396 thumb = g_infoManager.GetImage(VIDEOPLAYER_COVER, -1);
398 thumb = CTextureUtils::GetWrappedImageURL(thumb);
401 if (g_application.getNetwork().GetFirstConnectedInterface()) {
402 ip = g_application.getNetwork().GetFirstConnectedInterface()->GetCurrentIPAddress().c_str();
404 // build url, use the internal device http server to serv the image
405 NPT_HttpUrlQuery query;
406 query.AddField("path", thumb.c_str());
407 PLT_AlbumArtInfo art;
408 art.uri = NPT_HttpUrl(
410 m_URLDescription.GetPort(),
412 query.ToString()).ToString();
413 // Set DLNA profileID by extension, defaulting to JPEG.
414 if (URIUtils::HasExtension(item.GetArt("thumb"), ".png")) {
415 art.dlna_profile = "PNG_TN";
417 art.dlna_profile = "JPEG_TN";
419 object->m_ExtraInfo.album_arts.Add(art);
421 res = PLT_Didl::ToDidl(*object, "*", tmp);
422 meta = didl_header + tmp + didl_footer;
428 /*----------------------------------------------------------------------
429 | CUPnPRenderer::OnNext
430 +---------------------------------------------------------------------*/
432 CUPnPRenderer::OnNext(PLT_ActionReference& action)
434 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
435 CAction action(ACTION_NEXT_PICTURE);
436 CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
438 CApplicationMessenger::Get().PlayListPlayerNext();
443 /*----------------------------------------------------------------------
444 | CUPnPRenderer::OnPause
445 +---------------------------------------------------------------------*/
447 CUPnPRenderer::OnPause(PLT_ActionReference& action)
449 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
450 CAction action(ACTION_PAUSE);
451 CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
452 } else if (!g_application.m_pPlayer->IsPausedPlayback())
453 CApplicationMessenger::Get().MediaPause();
457 /*----------------------------------------------------------------------
458 | CUPnPRenderer::OnPlay
459 +---------------------------------------------------------------------*/
461 CUPnPRenderer::OnPlay(PLT_ActionReference& action)
463 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
465 } else if (g_application.m_pPlayer->IsPausedPlayback()) {
466 CApplicationMessenger::Get().MediaPause();
467 } else if (!g_application.m_pPlayer->IsPlaying()) {
468 NPT_String uri, meta;
469 PLT_Service* service;
470 // look for value set previously by SetAVTransportURI
471 NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
472 NPT_CHECK_SEVERE(service->GetStateVariableValue("AVTransportURI", uri));
473 NPT_CHECK_SEVERE(service->GetStateVariableValue("AVTransportURIMetaData", meta));
475 // if not set, use the current file being played
476 PlayMedia(uri, meta);
481 /*----------------------------------------------------------------------
482 | CUPnPRenderer::OnPrevious
483 +---------------------------------------------------------------------*/
485 CUPnPRenderer::OnPrevious(PLT_ActionReference& action)
487 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
488 CAction action(ACTION_PREV_PICTURE);
489 CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
491 CApplicationMessenger::Get().PlayListPlayerPrevious();
496 /*----------------------------------------------------------------------
497 | CUPnPRenderer::OnStop
498 +---------------------------------------------------------------------*/
500 CUPnPRenderer::OnStop(PLT_ActionReference& action)
502 if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
503 CAction action(ACTION_STOP);
504 CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
506 CApplicationMessenger::Get().MediaStop();
511 /*----------------------------------------------------------------------
512 | CUPnPRenderer::OnSetAVTransportURI
513 +---------------------------------------------------------------------*/
515 CUPnPRenderer::OnSetAVTransportURI(PLT_ActionReference& action)
517 NPT_String uri, meta;
518 PLT_Service* service;
519 NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
521 NPT_CHECK_SEVERE(action->GetArgumentValue("CurrentURI", uri));
522 NPT_CHECK_SEVERE(action->GetArgumentValue("CurrentURIMetaData", meta));
524 // if not playing already, just keep around uri & metadata
525 // and wait for play command
526 if (!g_application.m_pPlayer->IsPlaying() && g_windowManager.GetActiveWindow() != WINDOW_SLIDESHOW) {
527 service->SetStateVariable("TransportState", "STOPPED");
528 service->SetStateVariable("TransportStatus", "OK");
529 service->SetStateVariable("TransportPlaySpeed", "1");
530 service->SetStateVariable("AVTransportURI", uri);
531 service->SetStateVariable("AVTransportURIMetaData", meta);
532 service->SetStateVariable("NextAVTransportURI", "");
533 service->SetStateVariable("NextAVTransportURIMetaData", "");
535 NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
539 return PlayMedia(uri, meta, action.AsPointer());
542 /*----------------------------------------------------------------------
543 | CUPnPRenderer::OnSetAVTransportURI
544 +---------------------------------------------------------------------*/
546 CUPnPRenderer::OnSetNextAVTransportURI(PLT_ActionReference& action)
548 NPT_String uri, meta;
549 PLT_Service* service;
550 NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
552 NPT_CHECK_SEVERE(action->GetArgumentValue("NextURI", uri));
553 NPT_CHECK_SEVERE(action->GetArgumentValue("NextURIMetaData", meta));
555 CFileItemPtr item = GetFileItem(uri, meta);
560 if (g_application.m_pPlayer->IsPlaying()) {
562 int playlist = PLAYLIST_MUSIC;
564 playlist = PLAYLIST_VIDEO;
566 { CSingleLock lock(g_graphicsContext);
567 g_playlistPlayer.ClearPlaylist(playlist);
568 g_playlistPlayer.Add(playlist, item);
570 g_playlistPlayer.SetCurrentSong(-1);
571 g_playlistPlayer.SetCurrentPlaylist(playlist);
574 CGUIMessage msg(GUI_MSG_PLAYLIST_CHANGED, 0, 0);
575 g_windowManager.SendThreadMessage(msg);
578 service->SetStateVariable("NextAVTransportURI", uri);
579 service->SetStateVariable("NextAVTransportURIMetaData", meta);
581 NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
585 } else if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
592 /*----------------------------------------------------------------------
593 | CUPnPRenderer::PlayMedia
594 +---------------------------------------------------------------------*/
596 CUPnPRenderer::PlayMedia(const NPT_String& uri, const NPT_String& meta, PLT_Action* action)
598 PLT_Service* service;
599 NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
601 { NPT_AutoLock lock(m_state);
602 service->SetStateVariable("TransportState", "TRANSITIONING");
603 service->SetStateVariable("TransportStatus", "OK");
606 CFileItemPtr item = GetFileItem(uri, meta);
611 if (item->IsPicture()) {
612 CApplicationMessenger::Get().PictureShow(item->GetPath());
614 CApplicationMessenger::Get().MediaPlay(*item);
617 if (g_application.m_pPlayer->IsPlaying() || g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
618 NPT_AutoLock lock(m_state);
619 service->SetStateVariable("TransportState", "PLAYING");
620 service->SetStateVariable("TransportStatus", "OK");
621 service->SetStateVariable("AVTransportURI", uri);
622 service->SetStateVariable("AVTransportURIMetaData", meta);
624 NPT_AutoLock lock(m_state);
625 service->SetStateVariable("TransportState", "STOPPED");
626 service->SetStateVariable("TransportStatus", "ERROR_OCCURRED");
629 service->SetStateVariable("NextAVTransportURI", "");
630 service->SetStateVariable("NextAVTransportURIMetaData", "");
633 NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
638 /*----------------------------------------------------------------------
639 | CUPnPRenderer::OnSetVolume
640 +---------------------------------------------------------------------*/
642 CUPnPRenderer::OnSetVolume(PLT_ActionReference& action)
645 NPT_CHECK_SEVERE(action->GetArgumentValue("DesiredVolume", volume));
646 g_application.SetVolume((float)strtod((const char*)volume, NULL));
650 /*----------------------------------------------------------------------
651 | CUPnPRenderer::OnSetMute
652 +---------------------------------------------------------------------*/
654 CUPnPRenderer::OnSetMute(PLT_ActionReference& action)
657 NPT_CHECK_SEVERE(action->GetArgumentValue("DesiredMute",mute));
658 if((mute == "1") ^ g_application.IsMuted())
659 g_application.ToggleMute();
663 /*----------------------------------------------------------------------
664 | CUPnPRenderer::OnSeek
665 +---------------------------------------------------------------------*/
667 CUPnPRenderer::OnSeek(PLT_ActionReference& action)
669 if (!g_application.m_pPlayer->IsPlaying()) return NPT_ERROR_INVALID_STATE;
671 NPT_String unit, target;
672 NPT_CHECK_SEVERE(action->GetArgumentValue("Unit", unit));
673 NPT_CHECK_SEVERE(action->GetArgumentValue("Target", target));
675 if (!unit.Compare("REL_TIME")) {
676 // converts target to seconds
678 NPT_CHECK_SEVERE(PLT_Didl::ParseTimeStamp(target, seconds));
679 g_application.SeekTime(seconds);
685 } /* namespace UPNP */