Upnp: update copyright dates according to git blame -C -C
[vlc/vlc-skelet.git] / modules / services_discovery / upnp.cpp
blob5666a8ac0133336d797365a50c9b70da17d2307e
1 /*****************************************************************************
2 * Upnp.cpp : UPnP discovery module (libupnp)
3 *****************************************************************************
4 * Copyright (C) 2004-2011 the VideoLAN team
5 * $Id$
7 * Authors: RĂ©mi Denis-Courmont <rem # videolan.org> (original plugin)
8 * Christian Henz <henz # c-lab.de>
9 * Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
11 * UPnP Plugin using the Intel SDK (libupnp) instead of CyberLink
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 #undef PACKAGE_NAME
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include "upnp.hpp"
35 #include <vlc_plugin.h>
36 #include <vlc_services_discovery.h>
38 #include <assert.h>
40 // Constants
41 const char* MEDIA_SERVER_DEVICE_TYPE = "urn:schemas-upnp-org:device:MediaServer:1";
42 const char* CONTENT_DIRECTORY_SERVICE_TYPE = "urn:schemas-upnp-org:service:ContentDirectory:1";
44 // VLC handle
45 struct services_discovery_sys_t
47 UpnpClient_Handle client_handle;
48 MediaServerList* p_server_list;
49 vlc_mutex_t callback_lock;
52 // VLC callback prototypes
53 static int Open( vlc_object_t* );
54 static void Close( vlc_object_t* );
55 VLC_SD_PROBE_HELPER("upnp", "Universal Plug'n'Play", SD_CAT_LAN)
57 // Module descriptor
59 vlc_module_begin();
60 set_shortname( "UPnP" );
61 set_description( N_( "Universal Plug'n'Play" ) );
62 set_category( CAT_PLAYLIST );
63 set_subcategory( SUBCAT_PLAYLIST_SD );
64 set_capability( "services_discovery", 0 );
65 set_callbacks( Open, Close );
67 VLC_SD_PROBE_SUBMODULE
68 vlc_module_end();
71 // More prototypes...
73 static int Callback( Upnp_EventType event_type, void* p_event, void* p_user_data );
75 const char* xml_getChildElementValue( IXML_Element* p_parent,
76 const char* psz_tag_name );
78 IXML_Document* parseBrowseResult( IXML_Document* p_doc );
81 // VLC callbacks...
83 static int Open( vlc_object_t *p_this )
85 int i_res;
86 services_discovery_t *p_sd = ( services_discovery_t* )p_this;
87 services_discovery_sys_t *p_sys = ( services_discovery_sys_t * )
88 calloc( 1, sizeof( services_discovery_sys_t ) );
90 if(!(p_sd->p_sys = p_sys))
91 return VLC_ENOMEM;
93 i_res = UpnpInit( 0, 0 );
94 if( i_res != UPNP_E_SUCCESS )
96 msg_Err( p_sd, "%s", UpnpGetErrorMessage( i_res ) );
97 free( p_sys );
98 return VLC_EGENERIC;
101 p_sys->p_server_list = new MediaServerList( p_sd );
102 vlc_mutex_init( &p_sys->callback_lock );
104 i_res = UpnpRegisterClient( Callback, p_sd, &p_sys->client_handle );
105 if( i_res != UPNP_E_SUCCESS )
107 msg_Err( p_sd, "%s", UpnpGetErrorMessage( i_res ) );
108 Close( (vlc_object_t*) p_sd );
109 return VLC_EGENERIC;
112 i_res = UpnpSearchAsync( p_sys->client_handle, 5,
113 MEDIA_SERVER_DEVICE_TYPE, p_sd );
114 if( i_res != UPNP_E_SUCCESS )
116 msg_Err( p_sd, "Search failed: %s", UpnpGetErrorMessage( i_res ) );
117 Close( (vlc_object_t*) p_sd );
118 return VLC_EGENERIC;
121 i_res = UpnpSetMaxContentLength( 262144 );
122 if( i_res != UPNP_E_SUCCESS )
124 msg_Err( p_sd, "Failed to set maximum content length: %s", UpnpGetErrorMessage( i_res ) );
125 Close( (vlc_object_t*) p_sd );
126 return VLC_EGENERIC;
129 return VLC_SUCCESS;
132 static void Close( vlc_object_t *p_this )
134 services_discovery_t *p_sd = ( services_discovery_t* )p_this;
136 UpnpUnRegisterClient( p_sd->p_sys->client_handle );
137 UpnpFinish();
139 delete p_sd->p_sys->p_server_list;
140 vlc_mutex_destroy( &p_sd->p_sys->callback_lock );
142 free( p_sd->p_sys );
145 // XML utility functions:
147 // Returns the value of a child element, or 0 on error
148 const char* xml_getChildElementValue( IXML_Element* p_parent,
149 const char* psz_tag_name_ )
151 if ( !p_parent ) return 0;
152 if ( !psz_tag_name_ ) return 0;
154 char* psz_tag_name = strdup( psz_tag_name_ );
155 IXML_NodeList* p_node_list = ixmlElement_getElementsByTagName( p_parent, psz_tag_name );
156 free( psz_tag_name );
157 if ( !p_node_list ) return 0;
159 IXML_Node* p_element = ixmlNodeList_item( p_node_list, 0 );
160 ixmlNodeList_free( p_node_list );
161 if ( !p_element ) return 0;
163 IXML_Node* p_text_node = ixmlNode_getFirstChild( p_element );
164 if ( !p_text_node ) return 0;
166 return ixmlNode_getNodeValue( p_text_node );
169 // Extracts the result document from a SOAP response
170 IXML_Document* parseBrowseResult( IXML_Document* p_doc )
172 ixmlRelaxParser(1);
174 if ( !p_doc ) return 0;
176 IXML_NodeList* p_result_list = ixmlDocument_getElementsByTagName( p_doc,
177 "Result" );
179 if ( !p_result_list ) return 0;
181 IXML_Node* p_result_node = ixmlNodeList_item( p_result_list, 0 );
183 ixmlNodeList_free( p_result_list );
185 if ( !p_result_node ) return 0;
187 IXML_Node* p_text_node = ixmlNode_getFirstChild( p_result_node );
188 if ( !p_text_node ) return 0;
190 const char* psz_result_string = ixmlNode_getNodeValue( p_text_node );
191 char* psz_result_xml = strdup( psz_result_string );
193 IXML_Document* p_browse_doc = ixmlParseBuffer( psz_result_xml );
195 free( psz_result_xml );
197 return p_browse_doc;
201 // Handles all UPnP events
202 static int Callback( Upnp_EventType event_type, void* p_event, void* p_user_data )
204 services_discovery_t* p_sd = ( services_discovery_t* ) p_user_data;
205 services_discovery_sys_t* p_sys = p_sd->p_sys;
206 vlc_mutex_locker locker( &p_sys->callback_lock );
208 switch( event_type )
210 case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
211 case UPNP_DISCOVERY_SEARCH_RESULT:
213 struct Upnp_Discovery* p_discovery = ( struct Upnp_Discovery* )p_event;
215 IXML_Document *p_description_doc = 0;
217 int i_res;
218 i_res = UpnpDownloadXmlDoc( p_discovery->Location, &p_description_doc );
219 if ( i_res != UPNP_E_SUCCESS )
221 msg_Warn( p_sd, "Could not download device description! "
222 "Fetching data from %s failed: %s",
223 p_discovery->Location, UpnpGetErrorMessage( i_res ) );
224 return i_res;
227 MediaServer::parseDeviceDescription( p_description_doc,
228 p_discovery->Location, p_sd );
230 ixmlDocument_free( p_description_doc );
232 break;
234 case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
236 struct Upnp_Discovery* p_discovery = ( struct Upnp_Discovery* )p_event;
238 p_sys->p_server_list->removeServer( p_discovery->DeviceId );
240 break;
242 case UPNP_EVENT_RECEIVED:
244 Upnp_Event* p_e = ( Upnp_Event* )p_event;
246 MediaServer* p_server = p_sys->p_server_list->getServerBySID( p_e->Sid );
247 if ( p_server ) p_server->fetchContents();
249 break;
251 case UPNP_EVENT_AUTORENEWAL_FAILED:
252 case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
254 // Re-subscribe...
256 Upnp_Event_Subscribe* p_s = ( Upnp_Event_Subscribe* )p_event;
258 MediaServer* p_server = p_sys->p_server_list->getServerBySID( p_s->Sid );
259 if ( p_server ) p_server->subscribeToContentDirectory();
261 break;
263 case UPNP_EVENT_SUBSCRIBE_COMPLETE:
264 msg_Warn( p_sd, "subscription complete" );
265 break;
267 case UPNP_DISCOVERY_SEARCH_TIMEOUT:
268 msg_Warn( p_sd, "search timeout" );
269 break;
271 default:
272 msg_Err( p_sd, "Unhandled event, please report ( type=%d )", event_type );
273 break;
276 return UPNP_E_SUCCESS;
280 // Class implementations...
282 // MediaServer...
284 void MediaServer::parseDeviceDescription( IXML_Document* p_doc,
285 const char* p_location,
286 services_discovery_t* p_sd )
288 if ( !p_doc )
290 msg_Err( p_sd, "Null IXML_Document" );
291 return;
294 if ( !p_location )
296 msg_Err( p_sd, "Null location" );
297 return;
300 const char* psz_base_url = p_location;
302 // Try to extract baseURL
303 IXML_NodeList* p_url_list = ixmlDocument_getElementsByTagName( p_doc, "baseURL" );
304 if ( p_url_list )
307 if ( IXML_Node* p_url_node = ixmlNodeList_item( p_url_list, 0 ) )
309 IXML_Node* p_text_node = ixmlNode_getFirstChild( p_url_node );
310 if ( p_text_node ) psz_base_url = ixmlNode_getNodeValue( p_text_node );
313 ixmlNodeList_free( p_url_list );
316 // Get devices
317 IXML_NodeList* p_device_list =
318 ixmlDocument_getElementsByTagName( p_doc, "device" );
320 if ( p_device_list )
322 for ( unsigned int i = 0; i < ixmlNodeList_length( p_device_list ); i++ )
324 IXML_Element* p_device_element =
325 ( IXML_Element* ) ixmlNodeList_item( p_device_list, i );
327 const char* psz_device_type = xml_getChildElementValue( p_device_element,
328 "deviceType" );
329 if ( !psz_device_type )
331 msg_Warn( p_sd, "No deviceType found!" );
332 continue;
335 if ( strcmp( MEDIA_SERVER_DEVICE_TYPE, psz_device_type ) != 0 )
336 continue;
338 const char* psz_udn = xml_getChildElementValue( p_device_element, "UDN" );
339 if ( !psz_udn )
341 msg_Warn( p_sd, "No UDN!" );
342 continue;
345 // Check if server is already added
346 if ( p_sd->p_sys->p_server_list->getServer( psz_udn ) != 0 )
348 msg_Warn( p_sd, "Server with uuid '%s' already exists.", psz_udn );
349 continue;
352 const char* psz_friendly_name =
353 xml_getChildElementValue( p_device_element,
354 "friendlyName" );
356 if ( !psz_friendly_name )
358 msg_Dbg( p_sd, "No friendlyName!" );
359 continue;
362 MediaServer* p_server = new MediaServer( psz_udn, psz_friendly_name, p_sd );
364 if ( !p_sd->p_sys->p_server_list->addServer( p_server ) )
366 delete p_server;
367 p_server = 0;
368 continue;
371 // Check for ContentDirectory service...
372 IXML_NodeList* p_service_list =
373 ixmlElement_getElementsByTagName( p_device_element,
374 "service" );
375 if ( p_service_list )
377 for ( unsigned int j = 0;
378 j < ixmlNodeList_length( p_service_list ); j++ )
380 IXML_Element* p_service_element =
381 ( IXML_Element* ) ixmlNodeList_item( p_service_list, j );
383 const char* psz_service_type =
384 xml_getChildElementValue( p_service_element,
385 "serviceType" );
386 if ( !psz_service_type )
387 continue;
389 if ( strcmp( CONTENT_DIRECTORY_SERVICE_TYPE,
390 psz_service_type ) != 0 )
391 continue;
393 const char* psz_event_sub_url =
394 xml_getChildElementValue( p_service_element,
395 "eventSubURL" );
396 if ( !psz_event_sub_url )
397 continue;
399 const char* psz_control_url =
400 xml_getChildElementValue( p_service_element,
401 "controlURL" );
402 if ( !psz_control_url )
403 continue;
405 // Try to subscribe to ContentDirectory service
407 char* psz_url = ( char* ) malloc( strlen( psz_base_url ) +
408 strlen( psz_event_sub_url ) + 1 );
409 if ( psz_url )
411 char* psz_s1 = strdup( psz_base_url );
412 char* psz_s2 = strdup( psz_event_sub_url );
414 if ( UpnpResolveURL( psz_s1, psz_s2, psz_url ) ==
415 UPNP_E_SUCCESS )
417 p_server->setContentDirectoryEventURL( psz_url );
418 p_server->subscribeToContentDirectory();
421 free( psz_s1 );
422 free( psz_s2 );
423 free( psz_url );
426 // Try to browse content directory...
428 psz_url = ( char* ) malloc( strlen( psz_base_url ) +
429 strlen( psz_control_url ) + 1 );
430 if ( psz_url )
432 char* psz_s1 = strdup( psz_base_url );
433 char* psz_s2 = strdup( psz_control_url );
435 if ( UpnpResolveURL( psz_s1, psz_s2, psz_url ) ==
436 UPNP_E_SUCCESS )
438 p_server->setContentDirectoryControlURL( psz_url );
439 p_server->fetchContents();
442 free( psz_s1 );
443 free( psz_s2 );
444 free( psz_url );
447 ixmlNodeList_free( p_service_list );
450 ixmlNodeList_free( p_device_list );
454 MediaServer::MediaServer( const char* psz_udn,
455 const char* psz_friendly_name,
456 services_discovery_t* p_sd )
458 _p_sd = p_sd;
460 _UDN = psz_udn;
461 _friendly_name = psz_friendly_name;
463 _p_contents = NULL;
464 _p_input_item = NULL;
467 MediaServer::~MediaServer()
469 delete _p_contents;
472 const char* MediaServer::getUDN() const
474 return _UDN.c_str();
477 const char* MediaServer::getFriendlyName() const
479 return _friendly_name.c_str();
482 void MediaServer::setContentDirectoryEventURL( const char* psz_url )
484 _content_directory_event_url = psz_url;
487 const char* MediaServer::getContentDirectoryEventURL() const
489 return _content_directory_event_url.c_str();
492 void MediaServer::setContentDirectoryControlURL( const char* psz_url )
494 _content_directory_control_url = psz_url;
497 const char* MediaServer::getContentDirectoryControlURL() const
499 return _content_directory_control_url.c_str();
502 void MediaServer::subscribeToContentDirectory()
504 const char* psz_url = getContentDirectoryEventURL();
505 if ( !psz_url )
507 msg_Dbg( _p_sd, "No subscription url set!" );
508 return;
511 int i_timeout = 1810;
512 Upnp_SID sid;
514 int i_res = UpnpSubscribe( _p_sd->p_sys->client_handle, psz_url, &i_timeout, sid );
516 if ( i_res == UPNP_E_SUCCESS )
518 _i_subscription_timeout = i_timeout;
519 memcpy( _subscription_id, sid, sizeof( Upnp_SID ) );
521 else
523 msg_Dbg( _p_sd, "Subscribe failed: '%s': %s",
524 getFriendlyName(), UpnpGetErrorMessage( i_res ) );
528 IXML_Document* MediaServer::_browseAction( const char* psz_object_id_,
529 const char* psz_browser_flag_,
530 const char* psz_filter_,
531 const char* psz_starting_index_,
532 const char* psz_requested_count_,
533 const char* psz_sort_criteria_ )
535 IXML_Document* p_action = 0;
536 IXML_Document* p_response = 0;
537 const char* psz_url = getContentDirectoryControlURL();
539 if ( !psz_url )
541 msg_Dbg( _p_sd, "No subscription url set!" );
542 return 0;
545 char* psz_object_id = strdup( psz_object_id_ );
546 char* psz_browse_flag = strdup( psz_browser_flag_ );
547 char* psz_filter = strdup( psz_filter_ );
548 char* psz_starting_index = strdup( psz_starting_index_ );
549 char* psz_requested_count = strdup( psz_requested_count_ );
550 char* psz_sort_criteria = strdup( psz_sort_criteria_ );
551 char* psz_service_type = strdup( CONTENT_DIRECTORY_SERVICE_TYPE );
553 int i_res;
555 i_res = UpnpAddToAction( &p_action, "Browse",
556 psz_service_type, "ObjectID", psz_object_id );
558 if ( i_res != UPNP_E_SUCCESS )
560 msg_Dbg( _p_sd, "AddToAction 'ObjectID' failed: %s",
561 UpnpGetErrorMessage( i_res ) );
562 goto browseActionCleanup;
565 i_res = UpnpAddToAction( &p_action, "Browse",
566 psz_service_type, "BrowseFlag", psz_browse_flag );
568 if ( i_res != UPNP_E_SUCCESS )
570 msg_Dbg( _p_sd, "AddToAction 'BrowseFlag' failed: %s",
571 UpnpGetErrorMessage( i_res ) );
572 goto browseActionCleanup;
575 i_res = UpnpAddToAction( &p_action, "Browse",
576 psz_service_type, "Filter", psz_filter );
578 if ( i_res != UPNP_E_SUCCESS )
580 msg_Dbg( _p_sd, "AddToAction 'Filter' failed: %s",
581 UpnpGetErrorMessage( i_res ) );
582 goto browseActionCleanup;
585 i_res = UpnpAddToAction( &p_action, "Browse",
586 psz_service_type, "StartingIndex", psz_starting_index );
588 if ( i_res != UPNP_E_SUCCESS )
590 msg_Dbg( _p_sd, "AddToAction 'StartingIndex' failed: %s",
591 UpnpGetErrorMessage( i_res ) );
592 goto browseActionCleanup;
595 i_res = UpnpAddToAction( &p_action, "Browse",
596 psz_service_type, "RequestedCount", psz_requested_count );
598 if ( i_res != UPNP_E_SUCCESS )
600 msg_Dbg( _p_sd, "AddToAction 'RequestedCount' failed: %s",
601 UpnpGetErrorMessage( i_res ) );
602 goto browseActionCleanup;
605 i_res = UpnpAddToAction( &p_action, "Browse",
606 psz_service_type, "SortCriteria", psz_sort_criteria );
608 if ( i_res != UPNP_E_SUCCESS )
610 msg_Dbg( _p_sd, "AddToAction 'SortCriteria' failed: %s",
611 UpnpGetErrorMessage( i_res ) );
612 goto browseActionCleanup;
615 i_res = UpnpSendAction( _p_sd->p_sys->client_handle,
616 psz_url,
617 CONTENT_DIRECTORY_SERVICE_TYPE,
619 p_action,
620 &p_response );
622 if ( i_res != UPNP_E_SUCCESS )
624 msg_Err( _p_sd, "%s when trying the send() action with URL: %s",
625 UpnpGetErrorMessage( i_res ), psz_url );
627 ixmlDocument_free( p_response );
628 p_response = 0;
631 browseActionCleanup:
633 free( psz_object_id );
634 free( psz_browse_flag );
635 free( psz_filter );
636 free( psz_starting_index );
637 free( psz_requested_count );
638 free( psz_sort_criteria );
640 free( psz_service_type );
642 ixmlDocument_free( p_action );
643 return p_response;
646 void MediaServer::fetchContents()
648 // Delete previous contents to prevent duplicate entries
649 if ( _p_contents )
651 delete _p_contents;
652 services_discovery_RemoveItem( _p_sd, _p_input_item );
653 services_discovery_AddItem( _p_sd, _p_input_item, NULL );
656 Container* root = new Container( 0, "0", getFriendlyName() );
658 _fetchContents( root );
660 _p_contents = root;
661 _p_contents->setInputItem( _p_input_item );
663 _buildPlaylist( _p_contents, NULL );
666 bool MediaServer::_fetchContents( Container* p_parent )
668 if (!p_parent)
670 msg_Err( _p_sd, "No parent" );
671 return false;
674 IXML_Document* p_response = _browseAction( p_parent->getObjectID(),
675 "BrowseDirectChildren",
676 "*", "0", "0", "" );
677 if ( !p_response )
679 msg_Err( _p_sd, "No response from browse() action" );
680 return false;
683 IXML_Document* p_result = parseBrowseResult( p_response );
684 ixmlDocument_free( p_response );
686 if ( !p_result )
688 msg_Err( _p_sd, "browse() response parsing failed" );
689 return false;
692 IXML_NodeList* containerNodeList =
693 ixmlDocument_getElementsByTagName( p_result, "container" );
695 if ( containerNodeList )
697 for ( unsigned int i = 0;
698 i < ixmlNodeList_length( containerNodeList ); i++ )
700 IXML_Element* containerElement =
701 ( IXML_Element* )ixmlNodeList_item( containerNodeList, i );
703 const char* objectID = ixmlElement_getAttribute( containerElement,
704 "id" );
705 if ( !objectID )
706 continue;
708 const char* childCountStr =
709 ixmlElement_getAttribute( containerElement, "childCount" );
711 if ( !childCountStr )
712 continue;
714 int childCount = atoi( childCountStr );
715 const char* title = xml_getChildElementValue( containerElement,
716 "dc:title" );
718 if ( !title )
719 continue;
721 const char* resource = xml_getChildElementValue( containerElement,
722 "res" );
724 if ( resource && childCount < 1 )
726 Item* item = new Item( p_parent, objectID, title, resource );
727 p_parent->addItem( item );
730 else
732 Container* container = new Container( p_parent, objectID, title );
733 p_parent->addContainer( container );
735 if ( childCount > 0 )
736 _fetchContents( container );
739 ixmlNodeList_free( containerNodeList );
742 IXML_NodeList* itemNodeList = ixmlDocument_getElementsByTagName( p_result,
743 "item" );
744 if ( itemNodeList )
746 for ( unsigned int i = 0; i < ixmlNodeList_length( itemNodeList ); i++ )
748 IXML_Element* itemElement =
749 ( IXML_Element* )ixmlNodeList_item( itemNodeList, i );
751 const char* objectID =
752 ixmlElement_getAttribute( itemElement, "id" );
754 if ( !objectID )
755 continue;
757 const char* title =
758 xml_getChildElementValue( itemElement, "dc:title" );
760 if ( !title )
761 continue;
763 const char* resource =
764 xml_getChildElementValue( itemElement, "res" );
766 if ( !resource )
767 continue;
769 Item* item = new Item( p_parent, objectID, title, resource );
770 p_parent->addItem( item );
772 ixmlNodeList_free( itemNodeList );
775 ixmlDocument_free( p_result );
776 return true;
779 void MediaServer::_buildPlaylist( Container* p_parent, input_item_node_t *p_input_node )
781 bool b_send = p_input_node == NULL;
782 if( b_send )
783 p_input_node = input_item_node_Create( p_parent->getInputItem() );
785 for ( unsigned int i = 0; i < p_parent->getNumContainers(); i++ )
787 Container* p_container = p_parent->getContainer( i );
789 input_item_t* p_input_item = input_item_New( _p_sd, "vlc://nop",
790 p_container->getTitle() );
791 input_item_node_t *p_new_node =
792 input_item_node_AppendItem( p_input_node, p_input_item );
794 p_container->setInputItem( p_input_item );
795 _buildPlaylist( p_container, p_new_node );
798 for ( unsigned int i = 0; i < p_parent->getNumItems(); i++ )
800 Item* p_item = p_parent->getItem( i );
802 input_item_t* p_input_item = input_item_New( _p_sd,
803 p_item->getResource(),
804 p_item->getTitle() );
805 assert( p_input_item );
806 input_item_node_AppendItem( p_input_node, p_input_item );
807 p_item->setInputItem( p_input_item );
810 if( b_send )
811 input_item_node_PostAndDelete( p_input_node );
814 void MediaServer::setInputItem( input_item_t* p_input_item )
816 if(_p_input_item == p_input_item)
817 return;
819 if(_p_input_item)
820 vlc_gc_decref( _p_input_item );
822 vlc_gc_incref( p_input_item );
823 _p_input_item = p_input_item;
826 bool MediaServer::compareSID( const char* psz_sid )
828 return ( strncmp( _subscription_id, psz_sid, sizeof( Upnp_SID ) ) == 0 );
832 // MediaServerList...
834 MediaServerList::MediaServerList( services_discovery_t* p_sd )
836 _p_sd = p_sd;
839 MediaServerList::~MediaServerList()
841 for ( unsigned int i = 0; i < _list.size(); i++ )
843 delete _list[i];
847 bool MediaServerList::addServer( MediaServer* p_server )
849 input_item_t* p_input_item = NULL;
850 if ( getServer( p_server->getUDN() ) != 0 ) return false;
852 msg_Dbg( _p_sd, "Adding server '%s' with uuid '%s'", p_server->getFriendlyName(), p_server->getUDN() );
854 p_input_item = input_item_New( _p_sd, "vlc://nop",
855 p_server->getFriendlyName() );
856 p_server->setInputItem( p_input_item );
858 services_discovery_AddItem( _p_sd, p_input_item, NULL );
860 _list.push_back( p_server );
862 return true;
865 MediaServer* MediaServerList::getServer( const char* psz_udn )
867 MediaServer* p_result = 0;
869 for ( unsigned int i = 0; i < _list.size(); i++ )
871 if( strcmp( psz_udn, _list[i]->getUDN() ) == 0 )
873 p_result = _list[i];
874 break;
878 return p_result;
881 MediaServer* MediaServerList::getServerBySID( const char* psz_sid )
883 MediaServer* p_server = 0;
885 for ( unsigned int i = 0; i < _list.size(); i++ )
887 if ( _list[i]->compareSID( psz_sid ) )
889 p_server = _list[i];
890 break;
894 return p_server;
897 void MediaServerList::removeServer( const char* psz_udn )
899 MediaServer* p_server = getServer( psz_udn );
900 if ( !p_server ) return;
902 msg_Dbg( _p_sd, "Removing server '%s'", p_server->getFriendlyName() );
904 std::vector<MediaServer*>::iterator it;
905 for ( it = _list.begin(); it != _list.end(); ++it )
907 if ( *it == p_server )
909 _list.erase( it );
910 delete p_server;
911 break;
917 // Item...
919 Item::Item( Container* p_parent, const char* psz_object_id, const char* psz_title,
920 const char* psz_resource )
922 _parent = p_parent;
924 _objectID = psz_object_id;
925 _title = psz_title;
926 _resource = psz_resource;
928 _p_input_item = NULL;
931 Item::~Item()
933 if(_p_input_item)
934 vlc_gc_decref( _p_input_item );
937 const char* Item::getObjectID() const
939 return _objectID.c_str();
942 const char* Item::getTitle() const
944 return _title.c_str();
947 const char* Item::getResource() const
949 return _resource.c_str();
952 void Item::setInputItem( input_item_t* p_input_item )
954 if(_p_input_item == p_input_item)
955 return;
957 if(_p_input_item)
958 vlc_gc_decref( _p_input_item );
960 vlc_gc_incref( p_input_item );
961 _p_input_item = p_input_item;
964 input_item_t* Item::getInputItem() const
966 return _p_input_item;
970 // Container...
972 Container::Container( Container* p_parent,
973 const char* psz_object_id,
974 const char* psz_title )
976 _parent = p_parent;
978 _objectID = psz_object_id;
979 _title = psz_title;
981 _p_input_item = NULL;
984 Container::~Container()
986 for ( unsigned int i = 0; i < _containers.size(); i++ )
988 delete _containers[i];
991 for ( unsigned int i = 0; i < _items.size(); i++ )
993 delete _items[i];
996 if(_p_input_item )
997 vlc_gc_decref( _p_input_item );
1000 void Container::addItem( Item* item )
1002 _items.push_back( item );
1005 void Container::addContainer( Container* p_container )
1007 _containers.push_back( p_container );
1010 const char* Container::getObjectID() const
1012 return _objectID.c_str();
1015 const char* Container::getTitle() const
1017 return _title.c_str();
1020 unsigned int Container::getNumItems() const
1022 return _items.size();
1025 unsigned int Container::getNumContainers() const
1027 return _containers.size();
1030 Item* Container::getItem( unsigned int i_index ) const
1032 if ( i_index < _items.size() ) return _items[i_index];
1033 return 0;
1036 Container* Container::getContainer( unsigned int i_index ) const
1038 if ( i_index < _containers.size() ) return _containers[i_index];
1039 return 0;
1042 Container* Container::getParent()
1044 return _parent;
1047 void Container::setInputItem( input_item_t* p_input_item )
1049 if(_p_input_item == p_input_item)
1050 return;
1052 if(_p_input_item)
1053 vlc_gc_decref( _p_input_item );
1055 vlc_gc_incref( p_input_item );
1056 _p_input_item = p_input_item;
1059 input_item_t* Container::getInputItem() const
1061 return _p_input_item;