b991b42d98fe01643f1b5fcec55fb135dc49121a
[vuplus_xbmc] / xbmc / network / upnp / UPnPRenderer.cpp
1 /*
2  *      Copyright (C) 2012-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20 #include "network/Network.h"
21 #include "UPnPRenderer.h"
22 #include "UPnP.h"
23 #include "UPnPInternal.h"
24 #include "Platinum.h"
25 #include "Application.h"
26 #include "ApplicationMessenger.h"
27 #include "FileItem.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"
38 #include "URL.h"
39 #include "utils/URIUtils.h"
40 #include "utils/Variant.h"
41 #include "playlists/PlayList.h"
42 #include "GUIUserMessages.h"
43
44 using namespace ANNOUNCEMENT;
45
46 namespace UPNP
47 {
48
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)
55 {
56     CAnnouncementManager::AddAnnouncer(this);
57 }
58
59 /*----------------------------------------------------------------------
60 |   CUPnPRenderer::~CUPnPRenderer
61 +---------------------------------------------------------------------*/
62 CUPnPRenderer::~CUPnPRenderer()
63 {
64     CAnnouncementManager::RemoveAnnouncer(this);
65 }
66
67 /*----------------------------------------------------------------------
68 |   CUPnPRenderer::SetupServices
69 +---------------------------------------------------------------------*/
70 NPT_Result
71 CUPnPRenderer::SetupServices()
72 {
73     NPT_CHECK(PLT_MediaRenderer::SetupServices());
74
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"
79         ,"http-get:*:*:*"
80         ",xbmc-get:*:*:*"
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:*"
169         );
170
171     NPT_CHECK_FATAL(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
172     service->SetStateVariable("NextAVTransportURI", "");
173     service->SetStateVariable("NextAVTransportURIMetadata", "");
174
175     return NPT_SUCCESS;
176 }
177
178 /*----------------------------------------------------------------------
179 |   CUPnPRenderer::ProcessHttpRequest
180 +---------------------------------------------------------------------*/
181 NPT_Result
182 CUPnPRenderer::ProcessHttpGetRequest(NPT_HttpRequest&              request,
183                                   const NPT_HttpRequestContext& context,
184                                   NPT_HttpResponse&             response)
185 {
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();
191
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;
198
199             // check the method
200             if (request.GetMethod() != NPT_HTTP_METHOD_GET &&
201                 request.GetMethod() != NPT_HTTP_METHOD_HEAD) {
202                 response.SetStatus(405, "Method Not Allowed");
203                 return NPT_SUCCESS;
204             }
205
206             // prevent hackers from accessing files outside of our root
207             if ((filepath.Find("/..") >= 0) || (filepath.Find("\\..") >=0)) {
208                 return NPT_FAILURE;
209             }
210
211             // open the file
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");
217                 return NPT_SUCCESS;
218             }
219             NPT_InputStreamReference stream;
220             file.GetInputStream(stream);
221             entity->SetContentType(GetMimeType(filepath));
222             entity->SetInputStream(stream, true);
223
224             return NPT_SUCCESS;
225         }
226     }
227
228     return PLT_MediaRenderer::ProcessHttpGetRequest(request, context, response);
229 }
230
231 /*----------------------------------------------------------------------
232 |   CUPnPRenderer::Announce
233 +---------------------------------------------------------------------*/
234 void
235 CUPnPRenderer::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
236 {
237     if (strcmp(sender, "xbmc") != 0)
238       return;
239
240     NPT_AutoLock lock(m_state);
241     PLT_Service *avt, *rct;
242
243     if (flag == Player) {
244         if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", avt)))
245             return;
246         if (strcmp(message, "OnPlay") == 0) {
247             avt->SetStateVariable("AVTransportURI", g_application.CurrentFile().c_str());
248             avt->SetStateVariable("CurrentTrackURI", g_application.CurrentFile().c_str());
249
250             NPT_String meta;
251             if (NPT_SUCCEEDED(GetMetadata(meta))) {
252                 avt->SetStateVariable("CurrentTrackMetadata", meta);
253                 avt->SetStateVariable("AVTransportURIMetaData", meta);
254             }
255
256             avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
257             avt->SetStateVariable("TransportState", "PLAYING");
258
259             /* this could be a transition to next track, so clear next */
260             avt->SetStateVariable("NextAVTransportURI", "");
261             avt->SetStateVariable("NextAVTransportURIMetaData", "");
262         }
263         else if (strcmp(message, "OnPause") == 0) {
264             avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
265             avt->SetStateVariable("TransportState", "PAUSED_PLAYBACK");
266         }
267         else if (strcmp(message, "OnSpeedChanged") == 0) {
268             avt->SetStateVariable("TransportPlaySpeed", NPT_String::FromInteger(data["speed"].asInteger()));
269         }
270     }
271     else if (flag == Application && strcmp(message, "OnVolumeChanged") == 0) {
272         if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:RenderingControl:1", rct)))
273             return;
274
275         CStdString buffer;
276
277         buffer.Format("%ld", data["volume"].asInteger());
278         rct->SetStateVariable("Volume", buffer.c_str());
279
280         buffer.Format("%ld", 256 * (data["volume"].asInteger() * 60 - 60) / 100);
281         rct->SetStateVariable("VolumeDb", buffer.c_str());
282
283         rct->SetStateVariable("Mute", data["muted"].asBoolean() ? "1" : "0");
284     }
285 }
286
287 /*----------------------------------------------------------------------
288 |   CUPnPRenderer::UpdateState
289 +---------------------------------------------------------------------*/
290 void
291 CUPnPRenderer::UpdateState()
292 {
293     NPT_AutoLock lock(m_state);
294
295     PLT_Service *avt;
296
297     if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", avt)))
298         return;
299
300     /* don't update state while transitioning */
301     NPT_String state;
302     avt->GetStateVariableValue("TransportState", state);
303     if(state == "TRANSITIONING")
304         return;
305
306     avt->SetStateVariable("TransportStatus", "OK");
307
308     if (g_application.m_pPlayer->IsPlaying() || g_application.m_pPlayer->IsPausedPlayback()) {
309         avt->SetStateVariable("NumberOfTracks", "1");
310         avt->SetStateVariable("CurrentTrack", "1");
311
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());
315
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());
320         } else {
321           avt->SetStateVariable("CurrentTrackDuration", "00:00:00");
322           avt->SetStateVariable("CurrentMediaDuration", "00:00:00");
323         }
324
325     } else if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
326         avt->SetStateVariable("TransportState", "PLAYING");
327
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");
331
332         CGUIWindowSlideShow *slideshow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
333         if (slideshow)
334         {
335           CStdString index;
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());
340
341         }
342
343         avt->SetStateVariable("CurrentTrackMetadata", "");
344         avt->SetStateVariable("AVTransportURIMetaData", "");
345
346     } else {
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", "");
357     }
358 }
359
360 /*----------------------------------------------------------------------
361 |   CUPnPRenderer::SetupIcons
362 +---------------------------------------------------------------------*/
363 NPT_Result
364 CUPnPRenderer::SetupIcons()
365 {
366     NPT_String file_root = CSpecialProtocol::TranslatePath("special://xbmc/media/").c_str();
367     AddIcon(
368         PLT_DeviceIcon("image/png", 256, 256, 24, "/icon-flat-256x256.png"),
369         file_root);
370     AddIcon(
371         PLT_DeviceIcon("image/png", 120, 120, 24, "/icon-flat-120x120.png"),
372         file_root);
373     return NPT_SUCCESS;
374 }
375
376 /*----------------------------------------------------------------------
377 |   CUPnPRenderer::GetMetadata
378 +---------------------------------------------------------------------*/
379 NPT_Result
380 CUPnPRenderer::GetMetadata(NPT_String& meta)
381 {
382     NPT_Result res = NPT_FAILURE;
383     CFileItem item(g_application.CurrentFileItem());
384     NPT_String file_path, tmp;
385
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);
390     if (object) {
391         // fetch the item's artwork
392         CStdString thumb;
393         if (object->m_ObjectClass.type == "object.item.audioItem.musicTrack")
394             thumb = g_infoManager.GetImage(MUSICPLAYER_COVER, -1);
395         else
396             thumb = g_infoManager.GetImage(VIDEOPLAYER_COVER, -1);
397
398         thumb = CTextureUtils::GetWrappedImageURL(thumb);
399
400         NPT_String ip;
401         if (g_application.getNetwork().GetFirstConnectedInterface()) {
402             ip = g_application.getNetwork().GetFirstConnectedInterface()->GetCurrentIPAddress().c_str();
403         }
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(
409             ip,
410             m_URLDescription.GetPort(),
411             "/thumb",
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";
416         } else {
417             art.dlna_profile = "JPEG_TN";
418         }
419         object->m_ExtraInfo.album_arts.Add(art);
420
421         res = PLT_Didl::ToDidl(*object, "*", tmp);
422         meta = didl_header + tmp + didl_footer;
423         delete object;
424     }
425     return res;
426 }
427
428 /*----------------------------------------------------------------------
429 |   CUPnPRenderer::OnNext
430 +---------------------------------------------------------------------*/
431 NPT_Result
432 CUPnPRenderer::OnNext(PLT_ActionReference& action)
433 {
434     if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
435         CAction action(ACTION_NEXT_PICTURE);
436         CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
437     } else {
438         CApplicationMessenger::Get().PlayListPlayerNext();
439     }
440     return NPT_SUCCESS;
441 }
442
443 /*----------------------------------------------------------------------
444 |   CUPnPRenderer::OnPause
445 +---------------------------------------------------------------------*/
446 NPT_Result
447 CUPnPRenderer::OnPause(PLT_ActionReference& action)
448 {
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();
454     return NPT_SUCCESS;
455 }
456
457 /*----------------------------------------------------------------------
458 |   CUPnPRenderer::OnPlay
459 +---------------------------------------------------------------------*/
460 NPT_Result
461 CUPnPRenderer::OnPlay(PLT_ActionReference& action)
462 {
463     if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
464         return NPT_SUCCESS;
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));
474
475         // if not set, use the current file being played
476         PlayMedia(uri, meta);
477     }
478     return NPT_SUCCESS;
479 }
480
481 /*----------------------------------------------------------------------
482 |   CUPnPRenderer::OnPrevious
483 +---------------------------------------------------------------------*/
484 NPT_Result
485 CUPnPRenderer::OnPrevious(PLT_ActionReference& action)
486 {
487     if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
488         CAction action(ACTION_PREV_PICTURE);
489         CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
490     } else {
491         CApplicationMessenger::Get().PlayListPlayerPrevious();
492     }
493     return NPT_SUCCESS;
494 }
495
496 /*----------------------------------------------------------------------
497 |   CUPnPRenderer::OnStop
498 +---------------------------------------------------------------------*/
499 NPT_Result
500 CUPnPRenderer::OnStop(PLT_ActionReference& action)
501 {
502     if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
503         CAction action(ACTION_STOP);
504         CApplicationMessenger::Get().SendAction(action, WINDOW_SLIDESHOW);
505     } else {
506         CApplicationMessenger::Get().MediaStop();
507     }
508     return NPT_SUCCESS;
509 }
510
511 /*----------------------------------------------------------------------
512 |   CUPnPRenderer::OnSetAVTransportURI
513 +---------------------------------------------------------------------*/
514 NPT_Result
515 CUPnPRenderer::OnSetAVTransportURI(PLT_ActionReference& action)
516 {
517     NPT_String uri, meta;
518     PLT_Service* service;
519     NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
520
521     NPT_CHECK_SEVERE(action->GetArgumentValue("CurrentURI", uri));
522     NPT_CHECK_SEVERE(action->GetArgumentValue("CurrentURIMetaData", meta));
523
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", "");
534
535         NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
536         return NPT_SUCCESS;
537     }
538
539     return PlayMedia(uri, meta, action.AsPointer());
540 }
541
542 /*----------------------------------------------------------------------
543  |   CUPnPRenderer::OnSetAVTransportURI
544  +---------------------------------------------------------------------*/
545 NPT_Result
546 CUPnPRenderer::OnSetNextAVTransportURI(PLT_ActionReference& action)
547 {
548     NPT_String uri, meta;
549     PLT_Service* service;
550     NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
551
552     NPT_CHECK_SEVERE(action->GetArgumentValue("NextURI", uri));
553     NPT_CHECK_SEVERE(action->GetArgumentValue("NextURIMetaData", meta));
554
555     CFileItemPtr item = GetFileItem(uri, meta);
556     if (!item) {
557         return NPT_FAILURE;
558     }
559
560     if (g_application.m_pPlayer->IsPlaying()) {
561
562         int playlist = PLAYLIST_MUSIC;
563         if(item->IsVideo())
564           playlist = PLAYLIST_VIDEO;
565
566         {   CSingleLock lock(g_graphicsContext);
567             g_playlistPlayer.ClearPlaylist(playlist);
568             g_playlistPlayer.Add(playlist, item);
569
570             g_playlistPlayer.SetCurrentSong(-1);
571             g_playlistPlayer.SetCurrentPlaylist(playlist);
572         }
573
574         CGUIMessage msg(GUI_MSG_PLAYLIST_CHANGED, 0, 0);
575         g_windowManager.SendThreadMessage(msg);
576
577
578         service->SetStateVariable("NextAVTransportURI", uri);
579         service->SetStateVariable("NextAVTransportURIMetaData", meta);
580
581         NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
582
583         return NPT_SUCCESS;
584
585   } else if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
586         return NPT_FAILURE;
587   } else {
588         return NPT_FAILURE;
589   }
590 }
591
592 /*----------------------------------------------------------------------
593 |   CUPnPRenderer::PlayMedia
594 +---------------------------------------------------------------------*/
595 NPT_Result
596 CUPnPRenderer::PlayMedia(const NPT_String& uri, const NPT_String& meta, PLT_Action* action)
597 {
598     PLT_Service* service;
599     NPT_CHECK_SEVERE(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service));
600
601     { NPT_AutoLock lock(m_state);
602       service->SetStateVariable("TransportState", "TRANSITIONING");
603       service->SetStateVariable("TransportStatus", "OK");
604     }
605
606     CFileItemPtr item = GetFileItem(uri, meta);
607     if (!item) {
608         return NPT_FAILURE;
609     }
610
611     if (item->IsPicture()) {
612         CApplicationMessenger::Get().PictureShow(item->GetPath());
613     } else {
614         CApplicationMessenger::Get().MediaPlay(*item);
615     }
616
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);
623     } else {
624         NPT_AutoLock lock(m_state);
625         service->SetStateVariable("TransportState", "STOPPED");
626         service->SetStateVariable("TransportStatus", "ERROR_OCCURRED");
627     }
628
629     service->SetStateVariable("NextAVTransportURI", "");
630     service->SetStateVariable("NextAVTransportURIMetaData", "");
631
632     if (action) {
633         NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
634     }
635     return NPT_SUCCESS;
636 }
637
638 /*----------------------------------------------------------------------
639 |   CUPnPRenderer::OnSetVolume
640 +---------------------------------------------------------------------*/
641 NPT_Result
642 CUPnPRenderer::OnSetVolume(PLT_ActionReference& action)
643 {
644     NPT_String volume;
645     NPT_CHECK_SEVERE(action->GetArgumentValue("DesiredVolume", volume));
646     g_application.SetVolume((float)strtod((const char*)volume, NULL));
647     return NPT_SUCCESS;
648 }
649
650 /*----------------------------------------------------------------------
651 |   CUPnPRenderer::OnSetMute
652 +---------------------------------------------------------------------*/
653 NPT_Result
654 CUPnPRenderer::OnSetMute(PLT_ActionReference& action)
655 {
656     NPT_String mute;
657     NPT_CHECK_SEVERE(action->GetArgumentValue("DesiredMute",mute));
658     if((mute == "1") ^ g_application.IsMuted())
659         g_application.ToggleMute();
660     return NPT_SUCCESS;
661 }
662
663 /*----------------------------------------------------------------------
664 |   CUPnPRenderer::OnSeek
665 +---------------------------------------------------------------------*/
666 NPT_Result
667 CUPnPRenderer::OnSeek(PLT_ActionReference& action)
668 {
669     if (!g_application.m_pPlayer->IsPlaying()) return NPT_ERROR_INVALID_STATE;
670
671     NPT_String unit, target;
672     NPT_CHECK_SEVERE(action->GetArgumentValue("Unit", unit));
673     NPT_CHECK_SEVERE(action->GetArgumentValue("Target", target));
674
675     if (!unit.Compare("REL_TIME")) {
676         // converts target to seconds
677         NPT_UInt32 seconds;
678         NPT_CHECK_SEVERE(PLT_Didl::ParseTimeStamp(target, seconds));
679         g_application.SeekTime(seconds);
680     }
681
682     return NPT_SUCCESS;
683 }
684
685 } /* namespace UPNP */
686