Merge pull request #25959 from neo1973/TagLib_deprecation_warnings
[xbmc.git] / lib / libUPnP / Platinum / Source / Devices / MediaServer / PltSyncMediaBrowser.cpp
blob794b56be17fcfebf96bd369ebad1c8308a1c6bd6
1 /*****************************************************************
3 | Platinum - Synchronous Media Browser
5 | Copyright (c) 2004-2010, Plutinosoft, LLC.
6 | All rights reserved.
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 /*----------------------------------------------------------------------
36 | includes
37 +---------------------------------------------------------------------*/
38 #include "PltSyncMediaBrowser.h"
39 #include <algorithm>
41 NPT_SET_LOCAL_LOGGER("platinum.media.server.syncbrowser")
43 /*----------------------------------------------------------------------
44 | PLT_SyncMediaBrowser::PLT_SyncMediaBrowser
45 +---------------------------------------------------------------------*/
46 PLT_SyncMediaBrowser::PLT_SyncMediaBrowser(PLT_CtrlPointReference& ctrlPoint,
47 bool use_cache /* = false */,
48 PLT_MediaContainerChangesListener* listener /* = NULL */) :
49 PLT_MediaBrowser(ctrlPoint),
50 m_ContainerListener(listener),
51 m_UseCache(use_cache)
53 SetDelegate(this);
56 /*----------------------------------------------------------------------
57 | PLT_SyncMediaBrowser::~PLT_SyncMediaBrowser
58 +---------------------------------------------------------------------*/
59 PLT_SyncMediaBrowser::~PLT_SyncMediaBrowser()
63 /* Blocks forever waiting for a response from a request
64 * It is expected the request to succeed or to timeout and return an error eventually
66 /*----------------------------------------------------------------------
67 | PLT_SyncMediaBrowser::WaitForResponse
68 +---------------------------------------------------------------------*/
69 NPT_Result
70 PLT_SyncMediaBrowser::WaitForResponse(NPT_SharedVariable& shared_var)
72 return shared_var.WaitUntilEquals(1, 30000);
75 /*----------------------------------------------------------------------
76 | PLT_SyncMediaBrowser::OnDeviceAdded
77 +---------------------------------------------------------------------*/
78 NPT_Result
79 PLT_SyncMediaBrowser::OnDeviceAdded(PLT_DeviceDataReference& device)
81 NPT_String uuid = device->GetUUID();
83 // test if it's a media server
84 PLT_Service* service;
85 if (NPT_SUCCEEDED(device->FindServiceByType("urn:schemas-upnp-org:service:ContentDirectory:*", service))) {
86 NPT_AutoLock lock(m_MediaServers);
87 m_MediaServers.Put(uuid, device);
90 return PLT_MediaBrowser::OnDeviceAdded(device);
93 /*----------------------------------------------------------------------
94 | PLT_SyncMediaBrowser::OnDeviceRemoved
95 +---------------------------------------------------------------------*/
96 NPT_Result
97 PLT_SyncMediaBrowser::OnDeviceRemoved(PLT_DeviceDataReference& device)
99 NPT_String uuid = device->GetUUID();
101 // Remove from our list of servers first if found
103 NPT_AutoLock lock(m_MediaServers);
104 m_MediaServers.Erase(uuid);
107 // clear cache for that device
108 if (m_UseCache) m_Cache.Clear(device.AsPointer()->GetUUID());
110 return PLT_MediaBrowser::OnDeviceRemoved(device);
113 /*----------------------------------------------------------------------
114 | PLT_SyncMediaBrowser::Find
115 +---------------------------------------------------------------------*/
116 NPT_Result
117 PLT_SyncMediaBrowser::Find(const char* ip, PLT_DeviceDataReference& device)
119 NPT_AutoLock lock(m_MediaServers);
120 const NPT_List<PLT_DeviceMapEntry*>::Iterator it =
121 m_MediaServers.GetEntries().Find(PLT_DeviceMapFinderByIp(ip));
122 if (it) {
123 device = (*it)->GetValue();
124 return NPT_SUCCESS;
126 return NPT_FAILURE;
129 static void OnResult(NPT_Result res,
130 PLT_DeviceDataReference& device,
131 PLT_BrowseInfo* info,
132 void* userdata)
134 NPT_COMPILER_UNUSED(device);
136 if (!userdata) return;
138 PLT_BrowseDataReference* data = (PLT_BrowseDataReference*) userdata;
139 (*data)->res = res;
140 if (NPT_SUCCEEDED(res) && info) {
141 (*data)->info = *info;
143 (*data)->shared_var.SetValue(1);
144 delete data;
147 /*----------------------------------------------------------------------
148 | PLT_SyncMediaBrowser::OnBrowseResult
149 +---------------------------------------------------------------------*/
150 void
151 PLT_SyncMediaBrowser::OnBrowseResult(NPT_Result res,
152 PLT_DeviceDataReference& device,
153 PLT_BrowseInfo* info,
154 void* userdata)
156 OnResult(res, device, info, userdata);
159 /*----------------------------------------------------------------------
160 | PLT_SyncMediaBrowser::OnSearchResult
161 +---------------------------------------------------------------------*/
162 void
163 PLT_SyncMediaBrowser::OnSearchResult(NPT_Result res,
164 PLT_DeviceDataReference& device,
165 PLT_BrowseInfo* info,
166 void* userdata)
168 OnResult(res, device, info, userdata);
171 /*----------------------------------------------------------------------
172 | PLT_SyncMediaBrowser::OnGetSearchCapabilitiesResult
173 +---------------------------------------------------------------------*/
174 void
175 PLT_SyncMediaBrowser::OnGetSearchCapabilitiesResult(NPT_Result res,
176 PLT_DeviceDataReference& device,
177 NPT_String searchCapabilities,
178 void* userdata)
180 NPT_COMPILER_UNUSED(device);
182 if (!userdata) return;
184 PLT_CapabilitiesDataReference* data = (PLT_CapabilitiesDataReference*) userdata;
185 (*data)->res = res;
186 if (NPT_SUCCEEDED(res)) {
187 (*data)->capabilities = searchCapabilities;
189 (*data)->shared_var.SetValue(1);
190 delete data;
193 /*----------------------------------------------------------------------
194 | PLT_SyncMediaBrowser::OnGetSortCapabilitiesResult
195 +---------------------------------------------------------------------*/
196 void
197 PLT_SyncMediaBrowser::OnGetSortCapabilitiesResult(NPT_Result res,
198 PLT_DeviceDataReference& device,
199 NPT_String sortCapabilities,
200 void* userdata)
202 NPT_COMPILER_UNUSED(device);
204 if (!userdata) return;
206 PLT_CapabilitiesDataReference* data = (PLT_CapabilitiesDataReference*) userdata;
207 (*data)->res = res;
208 if (NPT_SUCCEEDED(res)) {
209 (*data)->capabilities = sortCapabilities;
211 (*data)->shared_var.SetValue(1);
212 delete data;
215 /*----------------------------------------------------------------------
216 | PLT_SyncMediaBrowser::OnMSStateVariablesChanged
217 +---------------------------------------------------------------------*/
218 void
219 PLT_SyncMediaBrowser::OnMSStateVariablesChanged(PLT_Service* service,
220 NPT_List<PLT_StateVariable*>* vars)
222 NPT_AutoLock lock(m_MediaServers);
224 PLT_DeviceDataReference device;
225 const NPT_List<PLT_DeviceMapEntry*>::Iterator it =
226 m_MediaServers.GetEntries().Find(PLT_DeviceMapFinderByUUID(service->GetDevice()->GetUUID()));
227 if (!it) return; // device with this service has gone away
229 device = (*it)->GetValue();
230 PLT_StateVariable* var = PLT_StateVariable::Find(*vars, "ContainerUpdateIDs");
231 if (var) {
232 // variable found, parse value
233 NPT_String value = var->GetValue();
234 NPT_String item_id, update_id;
235 int index;
237 while (value.GetLength()) {
238 // look for container id
239 index = value.Find(',');
240 if (index < 0) break;
241 item_id = value.Left(index);
242 value = value.SubString(index+1);
244 // look for update id
245 if (value.GetLength()) {
246 index = value.Find(',');
247 update_id = (index<0)?value:value.Left(index);
248 value = (index < 0) ? "" : value.SubString(index + 1).GetChars();
250 // clear cache for that device
251 if (m_UseCache) m_Cache.Clear(device->GetUUID(), item_id);
253 // notify listener
254 if (m_ContainerListener) m_ContainerListener->OnContainerChanged(device, item_id, update_id);
260 /*----------------------------------------------------------------------
261 | PLT_SyncMediaBrowser::BrowseSync
262 +---------------------------------------------------------------------*/
263 NPT_Result
264 PLT_SyncMediaBrowser::BrowseSync(PLT_BrowseDataReference& browse_data,
265 PLT_DeviceDataReference& device,
266 const char* object_id,
267 NPT_Int32 index,
268 NPT_Int32 count,
269 bool browse_metadata,
270 const char* filter,
271 const char* sort)
273 NPT_Result res;
275 browse_data->shared_var.SetValue(0);
276 browse_data->info.si = index;
278 // send off the browse packet. Note that this will
279 // not block. There is a call to WaitForResponse in order
280 // to block until the response comes back.
281 res = PLT_MediaBrowser::Browse(device,
282 (const char*)object_id,
283 index,
284 count,
285 browse_metadata,
286 filter,
287 sort,
288 new PLT_BrowseDataReference(browse_data));
289 NPT_CHECK_SEVERE(res);
291 return WaitForResponse(browse_data->shared_var);
294 /*----------------------------------------------------------------------
295 | PLT_SyncMediaBrowser::SearchSync
296 +---------------------------------------------------------------------*/
297 NPT_Result
298 PLT_SyncMediaBrowser::SearchSync(PLT_BrowseDataReference& browse_data,
299 PLT_DeviceDataReference& device,
300 const char* container_id,
301 const char* search_criteria,
302 NPT_Int32 index,
303 NPT_Int32 count,
304 const char* filter)
306 NPT_Result res;
308 browse_data->shared_var.SetValue(0);
309 browse_data->info.si = index;
311 // send off the search packet. Note that this will
312 // not block. There is a call to WaitForResponse in order
313 // to block until the response comes back.
314 res = PLT_MediaBrowser::Search(device,
315 container_id,
316 search_criteria,
317 index,
318 count,
319 filter,
320 new PLT_BrowseDataReference(browse_data));
321 NPT_CHECK_SEVERE(res);
323 return WaitForResponse(browse_data->shared_var);
326 /*----------------------------------------------------------------------
327 | PLT_SyncMediaBrowser::GetSearchCapabilitiesSync
328 +---------------------------------------------------------------------*/
329 NPT_Result
330 PLT_SyncMediaBrowser::GetSearchCapabilitiesSync(PLT_DeviceDataReference& device,
331 NPT_String& searchCapabilities)
333 NPT_Result res;
335 PLT_CapabilitiesDataReference capabilities_data(new PLT_CapabilitiesData(), true);
336 capabilities_data->shared_var.SetValue(0);
338 // send of the GetSearchCapabilities packet. Note that this will
339 // not block. There is a call to WaitForResponse in order
340 // to block until the response comes back.
341 res = PLT_MediaBrowser::GetSearchCapabilities(device,
342 new PLT_CapabilitiesDataReference(capabilities_data));
343 NPT_CHECK_SEVERE(res);
345 res = WaitForResponse(capabilities_data->shared_var);
346 NPT_CHECK_LABEL_WARNING(res, done);
348 if (NPT_FAILED(capabilities_data->res)) {
349 res = capabilities_data->res;
350 NPT_CHECK_LABEL_WARNING(res, done);
353 searchCapabilities = capabilities_data->capabilities;
355 done:
356 return res;
359 /*----------------------------------------------------------------------
360 | PLT_SyncMediaBrowser::GetSortCapabilitiesSync
361 +---------------------------------------------------------------------*/
362 NPT_Result
363 PLT_SyncMediaBrowser::GetSortCapabilitiesSync(PLT_DeviceDataReference& device,
364 NPT_String& sortCapabilities)
366 NPT_Result res;
368 PLT_CapabilitiesDataReference capabilities_data(new PLT_CapabilitiesData(), true);
369 capabilities_data->shared_var.SetValue(0);
371 // send of the GetSortCapabilities packet. Note that this will
372 // not block. There is a call to WaitForResponse in order
373 // to block until the response comes back.
374 res = PLT_MediaBrowser::GetSortCapabilities(device,
375 new PLT_CapabilitiesDataReference(capabilities_data));
376 NPT_CHECK_SEVERE(res);
378 res = WaitForResponse(capabilities_data->shared_var);
379 NPT_CHECK_LABEL_WARNING(res, done);
381 if (NPT_FAILED(capabilities_data->res)) {
382 res = capabilities_data->res;
383 NPT_CHECK_LABEL_WARNING(res, done);
386 sortCapabilities = capabilities_data->capabilities;
388 done:
389 return res;
392 /*----------------------------------------------------------------------
393 | PLT_SyncMediaBrowser::BrowseSync
394 +---------------------------------------------------------------------*/
395 NPT_Result
396 PLT_SyncMediaBrowser::BrowseSync(PLT_DeviceDataReference& device,
397 const char* object_id,
398 PLT_MediaObjectListReference& list,
399 bool metadata, /* = false */
400 NPT_Int32 start, /* = 0 */
401 NPT_Cardinal max_results /* = 0 */)
403 NPT_Result res = NPT_FAILURE;
404 NPT_Int32 index = start;
405 NPT_UInt32 count = 0;
407 // only cache metadata or if starting from 0 and asking for maximum
408 bool cache = m_UseCache && (metadata || (start == 0 && max_results == 0));
410 // reset output params
411 list = NULL;
413 // look into cache first
414 if (cache && NPT_SUCCEEDED(m_Cache.Get(device->GetUUID(), object_id, list))) return NPT_SUCCESS;
416 do {
417 PLT_BrowseDataReference browse_data(new PLT_BrowseData());
419 // send off the browse packet. Note that this will
420 // not block. There is a call to WaitForResponse in order
421 // to block until the response comes back.
422 res = BrowseSync(
423 browse_data,
424 device,
425 (const char*)object_id,
426 index,
427 metadata?1:200, // DLNA recommendations for browsing children is no more than 30 at a time
428 metadata);
429 NPT_CHECK_LABEL_WARNING(res, done);
431 if (NPT_FAILED(browse_data->res)) {
432 res = browse_data->res;
433 NPT_CHECK_LABEL_WARNING(res, done);
436 // server returned no more, bail now
437 if (browse_data->info.nr == 0)
438 break;
440 if (browse_data->info.nr != browse_data->info.items->GetItemCount()) {
441 NPT_LOG_WARNING_2("Server returned unexpected number of items (%d vs %d)",
442 browse_data->info.nr, browse_data->info.items->GetItemCount());
444 count += std::max<NPT_UInt32>(browse_data->info.nr, browse_data->info.items->GetItemCount());
446 if (list.IsNull()) {
447 list = browse_data->info.items;
448 } else {
449 list->Add(*browse_data->info.items);
450 // clear the list items so that the data inside is not
451 // cleaned up by PLT_MediaItemList dtor since we copied
452 // each pointer into the new list.
453 browse_data->info.items->Clear();
456 // stop now if our list contains exactly what the server said it had.
457 // Note that the server could return 0 if it didn't know how many items were
458 // available. In this case we have to continue browsing until
459 // nothing is returned back by the server.
460 // Unless we were told to stop after reaching a certain amount to avoid
461 // length delays
462 // (some servers may return a total matches out of whack at some point too)
463 if ((browse_data->info.tm && browse_data->info.tm <= count) ||
464 (max_results && count >= max_results))
465 break;
467 // ask for the next chunk of entries
468 index = count;
469 } while(1);
471 done:
472 // cache the result
473 if (cache && NPT_SUCCEEDED(res) && !list.IsNull() && list->GetItemCount()) {
474 m_Cache.Put(device->GetUUID(), object_id, list);
477 // clear entire cache data for device if failed, the device could be gone
478 if (NPT_FAILED(res) && cache) m_Cache.Clear(device->GetUUID());
480 return res;
483 /*----------------------------------------------------------------------
484 | PLT_SyncMediaBrowser::SearchSync
485 +---------------------------------------------------------------------*/
486 NPT_Result
487 PLT_SyncMediaBrowser::SearchSync(PLT_DeviceDataReference& device,
488 const char* container_id,
489 const char* search_criteria,
490 PLT_MediaObjectListReference& list,
491 NPT_Int32 start, /* = 0 */
492 NPT_Cardinal max_results /* = 0 */)
494 NPT_Result res = NPT_FAILURE;
495 NPT_Int32 index = start;
496 NPT_UInt32 count = 0;
498 // reset output params
499 list = NULL;
501 do {
502 PLT_BrowseDataReference browse_data(new PLT_BrowseData(), true);
504 // send off the search packet. Note that this will
505 // not block. There is a call to WaitForResponse in order
506 // to block until the response comes back.
507 res = SearchSync(
508 browse_data,
509 device,
510 container_id,
511 search_criteria,
512 index,
513 200); // DLNA recommendations for browsing children is no more than 30 at a time
515 NPT_CHECK_LABEL_WARNING(res, done);
517 if (NPT_FAILED(browse_data->res)) {
518 res = browse_data->res;
519 NPT_CHECK_LABEL_WARNING(res, done);
522 // server returned no more, bail now
523 if (browse_data->info.nr == 0)
524 break;
526 if (browse_data->info.nr != browse_data->info.items->GetItemCount()) {
527 NPT_LOG_WARNING_2("Server returned unexpected number of items (%d vs %d)",
528 browse_data->info.nr, browse_data->info.items->GetItemCount());
530 count += std::max<NPT_UInt32>(browse_data->info.nr, browse_data->info.items->GetItemCount());
532 if (list.IsNull()) {
533 list = browse_data->info.items;
534 } else {
535 list->Add(*browse_data->info.items);
536 // clear the list items so that the data inside is not
537 // cleaned up by PLT_MediaItemList dtor since we copied
538 // each pointer into the new list.
539 browse_data->info.items->Clear();
542 // stop now if our list contains exactly what the server said it had.
543 // Note that the server could return 0 if it didn't know how many items were
544 // available. In this case we have to continue browsing until
545 // nothing is returned back by the server.
546 // Unless we were told to stop after reaching a certain amount to avoid
547 // length delays
548 // (some servers may return a total matches out of whack at some point too)
549 if ((browse_data->info.tm && browse_data->info.tm <= count) ||
550 (max_results && count >= max_results))
551 break;
553 // ask for the next chunk of entries
554 index = count;
555 } while(1);
557 done:
558 return res;
561 /*----------------------------------------------------------------------
562 | PLT_SyncMediaBrowser::IsCached
563 +---------------------------------------------------------------------*/
564 bool
565 PLT_SyncMediaBrowser::IsCached(const char* uuid, const char* object_id)
567 NPT_AutoLock lock(m_MediaServers);
568 const NPT_List<PLT_DeviceMapEntry*>::Iterator it =
569 m_MediaServers.GetEntries().Find(PLT_DeviceMapFinderByUUID(uuid));
570 if (!it) {
571 m_Cache.Clear(uuid);
572 return false; // device with this service has gone away
575 PLT_MediaObjectListReference list;
576 return NPT_SUCCEEDED(m_Cache.Get(uuid, object_id, list))?true:false;