1 /*****************************************************************
3 | Platinum - AV Media Browser (Media Server Control Point)
5 | Copyright (c) 2004-2010, Plutinosoft, LLC.
7 | http://www.plutinosoft.com
9 | This program is free software; you can redistribute it and/or
10 | modify it under the terms of the GNU General Public License
11 | as published by the Free Software Foundation; either version 2
12 | of the License, or (at your option) any later version.
14 | OEMs, ISVs, VARs and other distributors that combine and
15 | distribute commercially licensed software with Platinum software
16 | and do not wish to distribute the source code for the commercially
17 | licensed software under version 2, or (at your option) any later
18 | version, of the GNU General Public License (the "GPL") must enter
19 | into a commercial license agreement with Plutinosoft, LLC.
20 | licensing@plutinosoft.com
22 | This program is distributed in the hope that it will be useful,
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 | GNU General Public License for more details.
27 | You should have received a copy of the GNU General Public License
28 | along with this program; see the file LICENSE.txt. If not, write to
29 | the Free Software Foundation, Inc.,
30 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 | http://www.gnu.org/licenses/gpl-2.0.html
33 ****************************************************************/
35 /*----------------------------------------------------------------------
37 +---------------------------------------------------------------------*/
39 #include "PltMediaBrowser.h"
42 NPT_SET_LOCAL_LOGGER("platinum.media.server.browser")
44 /*----------------------------------------------------------------------
45 | PLT_MediaBrowser::PLT_MediaBrowser
46 +---------------------------------------------------------------------*/
47 PLT_MediaBrowser::PLT_MediaBrowser(PLT_CtrlPointReference
& ctrl_point
,
48 PLT_MediaBrowserDelegate
* delegate
/* = NULL */) :
49 m_CtrlPoint(ctrl_point
),
52 m_CtrlPoint
->AddListener(this);
55 /*----------------------------------------------------------------------
56 | PLT_MediaBrowser::~PLT_MediaBrowser
57 +---------------------------------------------------------------------*/
58 PLT_MediaBrowser::~PLT_MediaBrowser()
60 m_CtrlPoint
->RemoveListener(this);
63 /*----------------------------------------------------------------------
64 | PLT_MediaBrowser::OnDeviceAdded
65 +---------------------------------------------------------------------*/
67 PLT_MediaBrowser::OnDeviceAdded(PLT_DeviceDataReference
& device
)
69 // verify the device implements the function we need
70 PLT_Service
* serviceCDS
;
71 PLT_Service
* serviceCMR
;
74 if (!device
->GetType().StartsWith("urn:schemas-upnp-org:device:MediaServer"))
77 type
= "urn:schemas-upnp-org:service:ContentDirectory:*";
78 if (NPT_FAILED(device
->FindServiceByType(type
, serviceCDS
))) {
79 NPT_LOG_WARNING_2("Service %s not found in device \"%s\"",
81 device
->GetFriendlyName().GetChars());
84 // in case it's a newer upnp implementation, force to 1
85 serviceCDS
->ForceVersion(1);
88 type
= "urn:schemas-upnp-org:service:ConnectionManager:*";
89 if (NPT_FAILED(device
->FindServiceByType(type
, serviceCMR
))) {
90 NPT_LOG_WARNING_2("Service %s not found in device \"%s\"",
92 device
->GetFriendlyName().GetChars());
95 // in case it's a newer upnp implementation, force to 1
96 serviceCMR
->ForceVersion(1);
100 NPT_AutoLock
lock(m_MediaServers
);
102 PLT_DeviceDataReference data
;
103 NPT_String uuid
= device
->GetUUID();
105 // is it a new device?
106 if (NPT_SUCCEEDED(NPT_ContainerFind(m_MediaServers
, PLT_DeviceDataFinder(uuid
), data
))) {
107 NPT_LOG_WARNING_1("Device (%s) is already in our list!", (const char*)uuid
);
111 NPT_LOG_FINE_1("Device Found: %s", (const char*)*device
);
113 m_MediaServers
.Add(device
);
116 if (m_Delegate
&& m_Delegate
->OnMSAdded(device
)) {
117 m_CtrlPoint
->Subscribe(serviceCDS
);
118 m_CtrlPoint
->Subscribe(serviceCMR
);
124 /*----------------------------------------------------------------------
125 | PLT_MediaBrowser::OnDeviceRemoved
126 +---------------------------------------------------------------------*/
128 PLT_MediaBrowser::OnDeviceRemoved(PLT_DeviceDataReference
& device
)
130 if (!device
->GetType().StartsWith("urn:schemas-upnp-org:device:MediaServer"))
134 NPT_AutoLock
lock(m_MediaServers
);
136 // only release if we have kept it around
137 PLT_DeviceDataReference data
;
138 NPT_String uuid
= device
->GetUUID();
140 // Have we seen that device?
141 if (NPT_FAILED(NPT_ContainerFind(m_MediaServers
, PLT_DeviceDataFinder(uuid
), data
))) {
142 NPT_LOG_WARNING_1("Device (%s) not found in our list!", (const char*)uuid
);
146 NPT_LOG_FINE_1("Device Removed: %s", (const char*)*device
);
148 m_MediaServers
.Remove(device
);
152 m_Delegate
->OnMSRemoved(device
);
158 /*----------------------------------------------------------------------
159 | PLT_MediaBrowser::FindServer
160 +---------------------------------------------------------------------*/
162 PLT_MediaBrowser::FindServer(const char* uuid
, PLT_DeviceDataReference
& device
)
164 NPT_AutoLock
lock(m_MediaServers
);
166 if (NPT_FAILED(NPT_ContainerFind(m_MediaServers
, PLT_DeviceDataFinder(uuid
), device
))) {
167 NPT_LOG_FINE_1("Device (%s) not found in our list of servers", (const char*)uuid
);
174 /*----------------------------------------------------------------------
175 | PLT_MediaBrowser::Search
176 +---------------------------------------------------------------------*/
178 PLT_MediaBrowser::Search(PLT_DeviceDataReference
& device
,
179 const char* container_id
,
180 const char* search_criteria
,
181 NPT_UInt32 start_index
,
186 // verify device still in our list
187 PLT_DeviceDataReference device_data
;
188 NPT_CHECK_WARNING(FindServer(device
->GetUUID(), device_data
));
191 PLT_ActionReference action
;
192 NPT_CHECK_SEVERE(m_CtrlPoint
->CreateAction(
194 "urn:schemas-upnp-org:service:ContentDirectory:1",
198 // Set the container id
200 if (NPT_FAILED(action
->SetArgumentValue("ContainerID", container_id
))) {
201 return NPT_ERROR_INVALID_PARAMETERS
;
204 // set the Search Criteria
205 if (NPT_FAILED(action
->SetArgumentValue("SearchCriteria", search_criteria
))) {
206 return NPT_ERROR_INVALID_PARAMETERS
;
211 if (NPT_FAILED(action
->SetArgumentValue("Filter", filter
))) {
212 return NPT_ERROR_INVALID_PARAMETERS
;
215 // set the Starting Index
216 if (NPT_FAILED(action
->SetArgumentValue("StartingIndex",
217 NPT_String::FromInteger(start_index
)))) {
218 return NPT_ERROR_INVALID_PARAMETERS
;
221 // set the Requested Count
222 if (NPT_FAILED(action
->SetArgumentValue("RequestedCount",
223 NPT_String::FromInteger(count
)))) {
224 return NPT_ERROR_INVALID_PARAMETERS
;
227 // set the Requested Count
228 if (NPT_FAILED(action
->SetArgumentValue("SortCriteria", ""))) {
229 return NPT_ERROR_INVALID_PARAMETERS
;
233 if (NPT_FAILED(m_CtrlPoint
->InvokeAction(action
, userdata
))) {
234 return NPT_ERROR_INVALID_PARAMETERS
;
240 /*----------------------------------------------------------------------
241 | PLT_MediaBrowser::Browse
242 +---------------------------------------------------------------------*/
244 PLT_MediaBrowser::Browse(PLT_DeviceDataReference
& device
,
246 NPT_UInt32 start_index
,
248 bool browse_metadata
,
250 const char* sort_criteria
,
253 // verify device still in our list
254 PLT_DeviceDataReference device_data
;
255 NPT_CHECK_WARNING(FindServer(device
->GetUUID(), device_data
));
258 PLT_ActionReference action
;
259 NPT_CHECK_SEVERE(m_CtrlPoint
->CreateAction(
261 "urn:schemas-upnp-org:service:ContentDirectory:1",
267 if (NPT_FAILED(action
->SetArgumentValue("ObjectID", obj_id
))) {
268 return NPT_ERROR_INVALID_PARAMETERS
;
271 // set the browse_flag
272 if (NPT_FAILED(action
->SetArgumentValue("BrowseFlag",
273 browse_metadata
?"BrowseMetadata":"BrowseDirectChildren"))) {
274 return NPT_ERROR_INVALID_PARAMETERS
;
278 if (NPT_FAILED(action
->SetArgumentValue("Filter", filter
))) {
279 return NPT_ERROR_INVALID_PARAMETERS
;
282 // set the Starting Index
283 if (NPT_FAILED(action
->SetArgumentValue("StartingIndex",
284 NPT_String::FromInteger(start_index
)))) {
285 return NPT_ERROR_INVALID_PARAMETERS
;
288 // set the Requested Count
289 if (NPT_FAILED(action
->SetArgumentValue("RequestedCount",
290 NPT_String::FromInteger(count
)))) {
291 return NPT_ERROR_INVALID_PARAMETERS
;
294 // set the Requested Count
295 if (NPT_FAILED(action
->SetArgumentValue("SortCriteria", sort_criteria
))) {
296 return NPT_ERROR_INVALID_PARAMETERS
;
300 if (NPT_FAILED(m_CtrlPoint
->InvokeAction(action
, userdata
))) {
301 return NPT_ERROR_INVALID_PARAMETERS
;
307 /*----------------------------------------------------------------------
308 | PLT_MediaBrowser::GetSearchCapabilities
309 +---------------------------------------------------------------------*/
311 PLT_MediaBrowser::GetSearchCapabilities(PLT_DeviceDataReference
& device
,
314 // verify device still in our list
315 PLT_DeviceDataReference device_data
;
316 NPT_CHECK_WARNING(FindServer(device
->GetUUID(), device_data
));
319 PLT_ActionReference action
;
320 NPT_CHECK_SEVERE(m_CtrlPoint
->CreateAction(
322 "urn:schemas-upnp-org:service:ContentDirectory:1",
323 "GetSearchCapabilities",
327 if (NPT_FAILED(m_CtrlPoint
->InvokeAction(action
, userdata
))) {
328 return NPT_ERROR_INVALID_PARAMETERS
;
334 /*----------------------------------------------------------------------
335 | PLT_MediaBrowser::GetSortCapabilities
336 +---------------------------------------------------------------------*/
338 PLT_MediaBrowser::GetSortCapabilities(PLT_DeviceDataReference
& device
,
341 // verify device still in our list
342 PLT_DeviceDataReference device_data
;
343 NPT_CHECK_WARNING(FindServer(device
->GetUUID(), device_data
));
346 PLT_ActionReference action
;
347 NPT_CHECK_SEVERE(m_CtrlPoint
->CreateAction(
349 "urn:schemas-upnp-org:service:ContentDirectory:1",
350 "GetSortCapabilities",
354 if (NPT_FAILED(m_CtrlPoint
->InvokeAction(action
, userdata
))) {
355 return NPT_ERROR_INVALID_PARAMETERS
;
361 /*----------------------------------------------------------------------
362 | PLT_MediaBrowser::OnActionResponse
363 +---------------------------------------------------------------------*/
365 PLT_MediaBrowser::OnActionResponse(NPT_Result res
,
366 PLT_ActionReference
& action
,
369 // look for device in our list first
370 PLT_DeviceDataReference device
;
371 NPT_String uuid
= action
->GetActionDesc().GetService()->GetDevice()->GetUUID();
372 if (NPT_FAILED(FindServer(uuid
, device
))) res
= NPT_FAILURE
;
374 NPT_String actionName
= action
->GetActionDesc().GetName();
375 if (actionName
.Compare("Browse", true) == 0) {
376 return OnBrowseResponse(res
, device
, action
, userdata
);
377 } else if (actionName
.Compare("Search", true) == 0) {
378 return OnSearchResponse(res
, device
, action
, userdata
);
379 } else if (actionName
.Compare("GetSearchCapabilities", true) == 0) {
380 return OnGetSearchCapabilitiesResponse(res
, device
, action
, userdata
);
381 } else if (actionName
.Compare("GetSortCapabilities", true) == 0) {
382 return OnGetSortCapabilitiesResponse(res
, device
, action
, userdata
);
388 /*----------------------------------------------------------------------
389 | PLT_MediaBrowser::OnBrowseResponse
390 +---------------------------------------------------------------------*/
392 PLT_MediaBrowser::OnBrowseResponse(NPT_Result res
,
393 PLT_DeviceDataReference
& device
,
394 PLT_ActionReference
& action
,
399 NPT_String unescaped
;
401 if (!m_Delegate
) return NPT_SUCCESS
;
403 if (NPT_FAILED(res
) || action
->GetErrorCode() != 0) {
407 if (NPT_FAILED(action
->GetArgumentValue("ObjectID", info
.object_id
))) {
410 if (NPT_FAILED(action
->GetArgumentValue("UpdateID", value
)) ||
411 value
.GetLength() == 0 ||
412 NPT_FAILED(value
.ToInteger(info
.uid
))) {
415 if (NPT_FAILED(action
->GetArgumentValue("NumberReturned", value
)) ||
416 value
.GetLength() == 0 ||
417 NPT_FAILED(value
.ToInteger(info
.nr
))) {
420 if (NPT_FAILED(action
->GetArgumentValue("TotalMatches", value
)) ||
421 value
.GetLength() == 0 ||
422 NPT_FAILED(value
.ToInteger(info
.tm
))) {
425 if (NPT_FAILED(action
->GetArgumentValue("Result", value
)) ||
426 value
.GetLength() == 0) {
430 if (NPT_FAILED(PLT_Didl::FromDidl(value
, info
.items
))) {
434 m_Delegate
->OnBrowseResult(NPT_SUCCESS
, device
, &info
, userdata
);
438 m_Delegate
->OnBrowseResult(NPT_FAILURE
, device
, NULL
, userdata
);
442 /*----------------------------------------------------------------------
443 | PLT_MediaBrowser::OnSearchResponse
444 +---------------------------------------------------------------------*/
446 PLT_MediaBrowser::OnSearchResponse(NPT_Result res
,
447 PLT_DeviceDataReference
& device
,
448 PLT_ActionReference
& action
,
453 NPT_String unescaped
;
455 if (!m_Delegate
) return NPT_SUCCESS
;
457 if (NPT_FAILED(res
) || action
->GetErrorCode() != 0) {
461 if (NPT_FAILED(action
->GetArgumentValue("ContainerId", info
.object_id
))) {
464 if (NPT_FAILED(action
->GetArgumentValue("UpdateID", value
)) ||
465 value
.GetLength() == 0 ||
466 NPT_FAILED(value
.ToInteger(info
.uid
))) {
469 if (NPT_FAILED(action
->GetArgumentValue("NumberReturned", value
)) ||
470 value
.GetLength() == 0 ||
471 NPT_FAILED(value
.ToInteger(info
.nr
))) {
474 if (NPT_FAILED(action
->GetArgumentValue("TotalMatches", value
)) ||
475 value
.GetLength() == 0 ||
476 NPT_FAILED(value
.ToInteger(info
.tm
))) {
479 if (NPT_FAILED(action
->GetArgumentValue("Result", value
)) ||
480 value
.GetLength() == 0) {
484 if (NPT_FAILED(PLT_Didl::FromDidl(value
, info
.items
))) {
488 m_Delegate
->OnSearchResult(NPT_SUCCESS
, device
, &info
, userdata
);
492 m_Delegate
->OnSearchResult(NPT_FAILURE
, device
, NULL
, userdata
);
496 /*----------------------------------------------------------------------
497 | PLT_MediaBrowser::OnGetSearchCapabilitiesResponse
498 +---------------------------------------------------------------------*/
500 PLT_MediaBrowser::OnGetSearchCapabilitiesResponse(NPT_Result res
,
501 PLT_DeviceDataReference
& device
,
502 PLT_ActionReference
& action
,
507 if (!m_Delegate
) return NPT_SUCCESS
;
509 if (NPT_FAILED(res
) || action
->GetErrorCode() != 0) {
513 if (NPT_FAILED(action
->GetArgumentValue("SearchCaps", value
))) {
517 m_Delegate
->OnGetSearchCapabilitiesResult(NPT_SUCCESS
, device
, value
, userdata
);
521 m_Delegate
->OnGetSearchCapabilitiesResult(NPT_FAILURE
, device
, value
, userdata
);
525 /*----------------------------------------------------------------------
526 | PLT_MediaBrowser::OnGetSearchCapabilitiesResponse
527 +---------------------------------------------------------------------*/
529 PLT_MediaBrowser::OnGetSortCapabilitiesResponse(NPT_Result res
,
530 PLT_DeviceDataReference
& device
,
531 PLT_ActionReference
& action
,
536 if (!m_Delegate
) return NPT_SUCCESS
;
538 if (NPT_FAILED(res
) || action
->GetErrorCode() != 0) {
542 if (NPT_FAILED(action
->GetArgumentValue("SortCaps", value
))) {
546 m_Delegate
->OnGetSortCapabilitiesResult(NPT_SUCCESS
, device
, value
, userdata
);
550 m_Delegate
->OnGetSortCapabilitiesResult(NPT_FAILURE
, device
, value
, userdata
);
554 /*----------------------------------------------------------------------
555 | PLT_MediaBrowser::OnEventNotify
556 +---------------------------------------------------------------------*/
558 PLT_MediaBrowser::OnEventNotify(PLT_Service
* service
, NPT_List
<PLT_StateVariable
*>* vars
)
560 if (!service
->GetDevice()->GetType().StartsWith("urn:schemas-upnp-org:device:MediaServer"))
563 if (!m_Delegate
) return NPT_SUCCESS
;
565 /* make sure device associated to service is still around */
566 PLT_DeviceDataReference data
;
567 NPT_CHECK_WARNING(FindServer(service
->GetDevice()->GetUUID(), data
));
569 m_Delegate
->OnMSStateVariablesChanged(service
, vars
);