Fix compilation
[vlc.git] / modules / services_discovery / upnp_intel.cpp
blob452264386c42e8b4cef0333beac124e1d9a59c91
1 /*****************************************************************************
2 * Upnp_intel.cpp : UPnP discovery module (Intel SDK)
3 *****************************************************************************
4 * Copyright (C) 2004-2008 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 *****************************************************************************/
29 \TODO: Debug messages: "__FILE__, __LINE__" ok ???, Wrn/Err ???
30 \TODO: Change names to VLC standard ???
32 #undef PACKAGE_NAME
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
37 #include "upnp_intel.hpp"
39 #include <vlc_plugin.h>
40 #include <vlc_services_discovery.h>
43 // Constants
44 const char* MEDIA_SERVER_DEVICE_TYPE = "urn:schemas-upnp-org:device:MediaServer:1";
45 const char* CONTENT_DIRECTORY_SERVICE_TYPE = "urn:schemas-upnp-org:service:ContentDirectory:1";
47 // VLC handle
48 struct services_discovery_sys_t
50 UpnpClient_Handle clientHandle;
51 MediaServerList* serverList;
52 vlc_mutex_t callbackLock;
55 // VLC callback prototypes
56 static int Open( vlc_object_t* );
57 static void Close( vlc_object_t* );
58 VLC_SD_PROBE_HELPER("upnp", "Universal Plug'n'Play", SD_CAT_LAN)
60 // Module descriptor
62 vlc_module_begin();
63 set_shortname( "UPnP" );
64 set_description( N_( "Universal Plug'n'Play" ) );
65 set_category( CAT_PLAYLIST );
66 set_subcategory( SUBCAT_PLAYLIST_SD );
67 set_capability( "services_discovery", 0 );
68 set_callbacks( Open, Close );
70 VLC_SD_PROBE_SUBMODULE
71 vlc_module_end();
74 // More prototypes...
76 static int Callback( Upnp_EventType eventType, void* event, void* user_data );
78 const char* xml_getChildElementValue( IXML_Element* parent,
79 const char* tagName );
81 IXML_Document* parseBrowseResult( IXML_Document* doc );
84 // VLC callbacks...
86 static int Open( vlc_object_t *p_this )
88 int res;
89 services_discovery_t *p_sd = ( services_discovery_t* )p_this;
90 services_discovery_sys_t *p_sys = ( services_discovery_sys_t * )
91 calloc( 1, sizeof( services_discovery_sys_t ) );
93 if(!(p_sd->p_sys = p_sys))
94 return VLC_ENOMEM;
96 res = UpnpInit( 0, 0 );
97 if( res != UPNP_E_SUCCESS )
99 msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
100 free( p_sys );
101 return VLC_EGENERIC;
104 p_sys->serverList = new MediaServerList( p_sd );
105 vlc_mutex_init( &p_sys->callbackLock );
107 res = UpnpRegisterClient( Callback, p_sd, &p_sys->clientHandle );
108 if( res != UPNP_E_SUCCESS )
110 msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
111 Close( (vlc_object_t*) p_sd );
112 return VLC_EGENERIC;
115 res = UpnpSearchAsync( p_sys->clientHandle, 5,
116 MEDIA_SERVER_DEVICE_TYPE, p_sd );
118 if( res != UPNP_E_SUCCESS )
120 msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
121 Close( (vlc_object_t*) p_sd );
122 return VLC_EGENERIC;
125 return VLC_SUCCESS;
128 static void Close( vlc_object_t *p_this )
130 services_discovery_t *p_sd = ( services_discovery_t* )p_this;
132 UpnpFinish();
133 delete p_sd->p_sys->serverList;
134 vlc_mutex_destroy( &p_sd->p_sys->callbackLock );
136 free( p_sd->p_sys );
139 // XML utility functions:
141 // Returns the value of a child element, or 0 on error
142 const char* xml_getChildElementValue( IXML_Element* parent,
143 const char* tagName )
145 if ( !parent ) return 0;
146 if ( !tagName ) return 0;
148 char* s = strdup( tagName );
149 IXML_NodeList* nodeList = ixmlElement_getElementsByTagName( parent, s );
150 free( s );
151 if ( !nodeList ) return 0;
153 IXML_Node* element = ixmlNodeList_item( nodeList, 0 );
154 ixmlNodeList_free( nodeList );
155 if ( !element ) return 0;
157 IXML_Node* textNode = ixmlNode_getFirstChild( element );
158 if ( !textNode ) return 0;
160 return ixmlNode_getNodeValue( textNode );
163 // Extracts the result document from a SOAP response
164 IXML_Document* parseBrowseResult( IXML_Document* doc )
166 ixmlRelaxParser(1);
168 if ( !doc ) return 0;
170 IXML_NodeList* resultList = ixmlDocument_getElementsByTagName( doc,
171 "Result" );
173 if ( !resultList ) return 0;
175 IXML_Node* resultNode = ixmlNodeList_item( resultList, 0 );
177 ixmlNodeList_free( resultList );
179 if ( !resultNode ) return 0;
181 IXML_Node* textNode = ixmlNode_getFirstChild( resultNode );
182 if ( !textNode ) return 0;
184 const char* resultString = ixmlNode_getNodeValue( textNode );
185 char* resultXML = strdup( resultString );
187 IXML_Document* browseDoc = ixmlParseBuffer( resultXML );
189 free( resultXML );
191 return browseDoc;
195 // Handles all UPnP events
196 static int Callback( Upnp_EventType eventType, void* event, void* user_data )
198 services_discovery_t *p_sd = ( services_discovery_t* ) user_data;
199 services_discovery_sys_t* p_sys = p_sd->p_sys;
200 vlc_mutex_locker locker( &p_sys->callbackLock );
202 switch( eventType ) {
204 case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
205 case UPNP_DISCOVERY_SEARCH_RESULT:
207 struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
209 IXML_Document *descriptionDoc = 0;
211 int res;
212 res = UpnpDownloadXmlDoc( discovery->Location, &descriptionDoc );
213 if ( res != UPNP_E_SUCCESS )
215 msg_Dbg( p_sd,
216 "%s:%d: Could not download device description!",
217 __FILE__, __LINE__ );
218 return res;
221 MediaServer::parseDeviceDescription( descriptionDoc,
222 discovery->Location, p_sd );
224 ixmlDocument_free( descriptionDoc );
226 break;
228 case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
230 struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
232 p_sys->serverList->removeServer( discovery->DeviceId );
234 break;
236 case UPNP_EVENT_RECEIVED:
238 Upnp_Event* e = ( Upnp_Event* )event;
240 MediaServer* server = p_sys->serverList->getServerBySID( e->Sid );
241 if ( server ) server->fetchContents();
243 break;
245 case UPNP_EVENT_AUTORENEWAL_FAILED:
246 case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
248 // Re-subscribe...
250 Upnp_Event_Subscribe* s = ( Upnp_Event_Subscribe* )event;
252 MediaServer* server = p_sys->serverList->getServerBySID( s->Sid );
253 if ( server ) server->subscribeToContentDirectory();
255 break;
257 case UPNP_EVENT_SUBSCRIBE_COMPLETE:
258 msg_Warn( p_sd, "subscription complete" );
259 break;
261 case UPNP_DISCOVERY_SEARCH_TIMEOUT:
262 msg_Warn( p_sd, "search timeout" );
263 break;
265 default:
266 msg_Dbg( p_sd,
267 "%s:%d: DEBUG: UNHANDLED EVENT ( TYPE=%d )",
268 __FILE__, __LINE__, eventType );
269 break;
272 return UPNP_E_SUCCESS;
276 // Class implementations...
278 // MediaServer...
280 void MediaServer::parseDeviceDescription( IXML_Document* doc,
281 const char* location,
282 services_discovery_t* p_sd )
284 if ( !doc )
286 msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ );
287 return;
290 if ( !location )
292 msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ );
293 return;
296 const char* baseURL = location;
298 // Try to extract baseURL
300 IXML_NodeList* urlList = ixmlDocument_getElementsByTagName( doc, "baseURL" );
301 if ( !urlList )
304 if ( IXML_Node* urlNode = ixmlNodeList_item( urlList, 0 ) )
306 IXML_Node* textNode = ixmlNode_getFirstChild( urlNode );
307 if ( textNode ) baseURL = ixmlNode_getNodeValue( textNode );
310 ixmlNodeList_free( urlList );
313 // Get devices
315 IXML_NodeList* deviceList =
316 ixmlDocument_getElementsByTagName( doc, "device" );
318 if ( deviceList )
320 for ( unsigned int i = 0; i < ixmlNodeList_length( deviceList ); i++ )
322 IXML_Element* deviceElement =
323 ( IXML_Element* ) ixmlNodeList_item( deviceList, i );
325 const char* deviceType = xml_getChildElementValue( deviceElement,
326 "deviceType" );
327 if ( !deviceType )
329 msg_Dbg( p_sd,
330 "%s:%d: no deviceType!",
331 __FILE__, __LINE__ );
332 continue;
335 if ( strcmp( MEDIA_SERVER_DEVICE_TYPE, deviceType ) != 0 )
336 continue;
338 const char* UDN = xml_getChildElementValue( deviceElement, "UDN" );
339 if ( !UDN )
341 msg_Dbg( p_sd, "%s:%d: no UDN!",
342 __FILE__, __LINE__ );
343 continue;
346 if ( p_sd->p_sys->serverList->getServer( UDN ) != 0 )
347 continue;
349 const char* friendlyName =
350 xml_getChildElementValue( deviceElement,
351 "friendlyName" );
353 if ( !friendlyName )
355 msg_Dbg( p_sd, "%s:%d: no friendlyName!", __FILE__, __LINE__ );
356 continue;
359 MediaServer* server = new MediaServer( UDN, friendlyName, p_sd );
361 if ( !p_sd->p_sys->serverList->addServer( server ) )
364 delete server;
365 server = 0;
366 continue;
369 // Check for ContentDirectory service...
370 IXML_NodeList* serviceList =
371 ixmlElement_getElementsByTagName( deviceElement,
372 "service" );
373 if ( serviceList )
375 for ( unsigned int j = 0;
376 j < ixmlNodeList_length( serviceList ); j++ )
378 IXML_Element* serviceElement =
379 ( IXML_Element* ) ixmlNodeList_item( serviceList, j );
381 const char* serviceType =
382 xml_getChildElementValue( serviceElement,
383 "serviceType" );
384 if ( !serviceType )
385 continue;
387 if ( strcmp( CONTENT_DIRECTORY_SERVICE_TYPE,
388 serviceType ) != 0 )
389 continue;
391 const char* eventSubURL =
392 xml_getChildElementValue( serviceElement,
393 "eventSubURL" );
394 if ( !eventSubURL )
395 continue;
397 const char* controlURL =
398 xml_getChildElementValue( serviceElement,
399 "controlURL" );
400 if ( !controlURL )
401 continue;
403 // Try to subscribe to ContentDirectory service
405 char* url = ( char* ) malloc( strlen( baseURL ) +
406 strlen( eventSubURL ) + 1 );
407 if ( url )
409 char* s1 = strdup( baseURL );
410 char* s2 = strdup( eventSubURL );
412 if ( UpnpResolveURL( s1, s2, url ) ==
413 UPNP_E_SUCCESS )
415 server->setContentDirectoryEventURL( url );
416 server->subscribeToContentDirectory();
419 free( s1 );
420 free( s2 );
421 free( url );
424 // Try to browse content directory...
426 url = ( char* ) malloc( strlen( baseURL ) +
427 strlen( controlURL ) + 1 );
428 if ( url )
430 char* s1 = strdup( baseURL );
431 char* s2 = strdup( controlURL );
433 if ( UpnpResolveURL( s1, s2, url ) ==
434 UPNP_E_SUCCESS )
436 server->setContentDirectoryControlURL( url );
437 server->fetchContents();
440 free( s1 );
441 free( s2 );
442 free( url );
445 ixmlNodeList_free( serviceList );
448 ixmlNodeList_free( deviceList );
452 MediaServer::MediaServer( const char* UDN,
453 const char* friendlyName,
454 services_discovery_t* p_sd )
456 _p_sd = p_sd;
458 _UDN = UDN;
459 _friendlyName = friendlyName;
461 _contents = NULL;
462 _inputItem = NULL;
465 MediaServer::~MediaServer()
467 delete _contents;
470 const char* MediaServer::getUDN() const
472 const char* s = _UDN.c_str();
473 return s;
476 const char* MediaServer::getFriendlyName() const
478 const char* s = _friendlyName.c_str();
479 return s;
482 void MediaServer::setContentDirectoryEventURL( const char* url )
484 _contentDirectoryEventURL = url;
487 const char* MediaServer::getContentDirectoryEventURL() const
489 const char* s = _contentDirectoryEventURL.c_str();
490 return s;
493 void MediaServer::setContentDirectoryControlURL( const char* url )
495 _contentDirectoryControlURL = url;
498 const char* MediaServer::getContentDirectoryControlURL() const
500 return _contentDirectoryControlURL.c_str();
503 void MediaServer::subscribeToContentDirectory()
505 const char* url = getContentDirectoryEventURL();
506 if ( !url || strcmp( url, "" ) == 0 )
508 msg_Dbg( _p_sd, "No subscription url set!" );
509 return;
512 int timeOut = 1810;
513 Upnp_SID sid;
515 int res = UpnpSubscribe( _p_sd->p_sys->clientHandle, url, &timeOut, sid );
517 if ( res == UPNP_E_SUCCESS )
519 _subscriptionTimeOut = timeOut;
520 memcpy( _subscriptionID, sid, sizeof( Upnp_SID ) );
522 else
524 msg_Dbg( _p_sd,
525 "%s:%d: WARNING: '%s': %s", __FILE__, __LINE__,
526 getFriendlyName(), UpnpGetErrorMessage( res ) );
530 IXML_Document* MediaServer::_browseAction( const char* pObjectID,
531 const char* pBrowseFlag,
532 const char* pFilter,
533 const char* pStartingIndex,
534 const char* pRequestedCount,
535 const char* pSortCriteria )
537 IXML_Document* action = 0;
538 IXML_Document* response = 0;
539 const char* url = getContentDirectoryControlURL();
541 if ( !url || strcmp( url, "" ) == 0 )
543 msg_Dbg( _p_sd, "No subscription url set!" );
544 return 0;
547 char* ObjectID = strdup( pObjectID );
548 char* BrowseFlag = strdup( pBrowseFlag );
549 char* Filter = strdup( pFilter );
550 char* StartingIndex = strdup( pStartingIndex );
551 char* RequestedCount = strdup( pRequestedCount );
552 char* SortCriteria = strdup( pSortCriteria );
553 char* serviceType = strdup( CONTENT_DIRECTORY_SERVICE_TYPE );
555 int res;
557 res = UpnpAddToAction( &action, "Browse",
558 serviceType, "ObjectID", ObjectID );
560 if ( res != UPNP_E_SUCCESS )
562 msg_Dbg( _p_sd,
563 "%s:%d: ERROR: %s", __FILE__, __LINE__,
564 UpnpGetErrorMessage( res ) );
565 goto browseActionCleanup;
568 res = UpnpAddToAction( &action, "Browse",
569 serviceType, "BrowseFlag", BrowseFlag );
571 if ( res != UPNP_E_SUCCESS )
573 msg_Dbg( _p_sd,
574 "%s:%d: ERROR: %s", __FILE__, __LINE__,
575 UpnpGetErrorMessage( res ) );
576 goto browseActionCleanup;
579 res = UpnpAddToAction( &action, "Browse",
580 serviceType, "Filter", Filter );
582 if ( res != UPNP_E_SUCCESS )
584 msg_Dbg( _p_sd,
585 "%s:%d: ERROR: %s", __FILE__, __LINE__,
586 UpnpGetErrorMessage( res ) );
587 goto browseActionCleanup;
590 res = UpnpAddToAction( &action, "Browse",
591 serviceType, "StartingIndex", StartingIndex );
593 if ( res != UPNP_E_SUCCESS )
595 msg_Dbg( _p_sd,
596 "%s:%d: ERROR: %s", __FILE__, __LINE__,
597 UpnpGetErrorMessage( res ) );
598 goto browseActionCleanup;
601 res = UpnpAddToAction( &action, "Browse",
602 serviceType, "RequestedCount", RequestedCount );
604 if ( res != UPNP_E_SUCCESS )
606 msg_Dbg( _p_sd,
607 "%s:%d: ERROR: %s", __FILE__, __LINE__,
608 UpnpGetErrorMessage( res ) ); goto browseActionCleanup; }
610 res = UpnpAddToAction( &action, "Browse",
611 serviceType, "SortCriteria", SortCriteria );
613 if ( res != UPNP_E_SUCCESS )
615 msg_Dbg( _p_sd,
616 "%s:%d: ERROR: %s", __FILE__, __LINE__,
617 UpnpGetErrorMessage( res ) );
618 goto browseActionCleanup;
621 res = UpnpSendAction( _p_sd->p_sys->clientHandle,
622 url,
623 CONTENT_DIRECTORY_SERVICE_TYPE,
625 action,
626 &response );
628 if ( res != UPNP_E_SUCCESS )
630 msg_Dbg( _p_sd,
631 "%s:%d: ERROR: %s when trying the send() action with URL: %s",
632 __FILE__, __LINE__,
633 UpnpGetErrorMessage( res ), url );
635 ixmlDocument_free( response );
636 response = 0;
639 browseActionCleanup:
641 free( ObjectID );
642 free( BrowseFlag );
643 free( Filter );
644 free( StartingIndex );
645 free( RequestedCount );
646 free( SortCriteria );
648 free( serviceType );
650 ixmlDocument_free( action );
651 return response;
654 void MediaServer::fetchContents()
656 Container* root = new Container( 0, "0", getFriendlyName() );
657 _fetchContents( root );
659 _contents = root;
660 _contents->setInputItem( _inputItem );
662 _buildPlaylist( _contents, NULL );
665 bool MediaServer::_fetchContents( Container* parent )
667 if (!parent)
669 msg_Dbg( _p_sd,
670 "%s:%d: parent==NULL", __FILE__, __LINE__ );
671 return false;
674 IXML_Document* response = _browseAction( parent->getObjectID(),
675 "BrowseDirectChildren",
676 "*", "0", "0", "" );
677 if ( !response )
679 msg_Dbg( _p_sd,
680 "%s:%d: ERROR! No response from browse() action",
681 __FILE__, __LINE__ );
682 return false;
685 IXML_Document* result = parseBrowseResult( response );
686 ixmlDocument_free( response );
688 if ( !result )
690 msg_Dbg( _p_sd,
691 "%s:%d: ERROR! browse() response parsing failed",
692 __FILE__, __LINE__ );
693 return false;
696 IXML_NodeList* containerNodeList =
697 ixmlDocument_getElementsByTagName( result, "container" );
699 if ( containerNodeList )
701 for ( unsigned int i = 0;
702 i < ixmlNodeList_length( containerNodeList ); i++ )
704 IXML_Element* containerElement =
705 ( IXML_Element* )ixmlNodeList_item( containerNodeList, i );
707 const char* objectID = ixmlElement_getAttribute( containerElement,
708 "id" );
709 if ( !objectID )
710 continue;
712 const char* childCountStr =
713 ixmlElement_getAttribute( containerElement, "childCount" );
715 if ( !childCountStr )
716 continue;
718 int childCount = atoi( childCountStr );
719 const char* title = xml_getChildElementValue( containerElement,
720 "dc:title" );
722 if ( !title )
723 continue;
725 const char* resource = xml_getChildElementValue( containerElement,
726 "res" );
728 if ( resource && childCount < 1 )
730 Item* item = new Item( parent, objectID, title, resource );
731 parent->addItem( item );
734 else
736 Container* container = new Container( parent, objectID, title );
737 parent->addContainer( container );
739 if ( childCount > 0 )
740 _fetchContents( container );
743 ixmlNodeList_free( containerNodeList );
746 IXML_NodeList* itemNodeList = ixmlDocument_getElementsByTagName( result,
747 "item" );
748 if ( itemNodeList )
750 for ( unsigned int i = 0; i < ixmlNodeList_length( itemNodeList ); i++ )
752 IXML_Element* itemElement =
753 ( IXML_Element* )ixmlNodeList_item( itemNodeList, i );
755 const char* objectID =
756 ixmlElement_getAttribute( itemElement, "id" );
758 if ( !objectID )
759 continue;
761 const char* title =
762 xml_getChildElementValue( itemElement, "dc:title" );
764 if ( !title )
765 continue;
767 const char* resource =
768 xml_getChildElementValue( itemElement, "res" );
770 if ( !resource )
771 continue;
773 Item* item = new Item( parent, objectID, title, resource );
774 parent->addItem( item );
776 ixmlNodeList_free( itemNodeList );
779 ixmlDocument_free( result );
780 return true;
783 void MediaServer::_buildPlaylist( Container* parent, input_item_node_t *p_input_node )
785 bool send = p_input_node == NULL;
786 if( send )
787 p_input_node = input_item_node_Create( parent->getInputItem() );
789 for ( unsigned int i = 0; i < parent->getNumContainers(); i++ )
791 Container* container = parent->getContainer( i );
793 input_item_t* p_input_item = input_item_New( _p_sd, "vlc://nop", parent->getTitle() );
794 input_item_node_t *p_new_node =
795 input_item_node_AppendItem( p_input_node, p_input_item );
797 container->setInputItem( p_input_item );
798 _buildPlaylist( container, p_new_node );
801 for ( unsigned int i = 0; i < parent->getNumItems(); i++ )
803 Item* item = parent->getItem( i );
805 input_item_t* p_input_item = input_item_New( _p_sd,
806 item->getResource(),
807 item->getTitle() );
808 assert( p_input_item );
809 input_item_node_AppendItem( p_input_node, p_input_item );
810 item->setInputItem( p_input_item );
813 if( send )
814 input_item_node_PostAndDelete( p_input_node );
817 void MediaServer::setInputItem( input_item_t* p_input_item )
819 if(_inputItem == p_input_item)
820 return;
822 if(_inputItem)
823 vlc_gc_decref( _inputItem );
825 vlc_gc_incref( p_input_item );
826 _inputItem = p_input_item;
829 bool MediaServer::compareSID( const char* sid )
831 return ( strncmp( _subscriptionID, sid, sizeof( Upnp_SID ) ) == 0 );
835 // MediaServerList...
837 MediaServerList::MediaServerList( services_discovery_t* p_sd )
839 _p_sd = p_sd;
842 MediaServerList::~MediaServerList()
844 for ( unsigned int i = 0; i < _list.size(); i++ )
846 delete _list[i];
850 bool MediaServerList::addServer( MediaServer* s )
852 input_item_t* p_input_item = NULL;
853 if ( getServer( s->getUDN() ) != 0 ) return false;
855 msg_Dbg( _p_sd, "Adding server '%s'",
856 s->getFriendlyName() );
858 services_discovery_t* p_sd = _p_sd;
860 p_input_item = input_item_New( p_sd, "vlc://nop", s->getFriendlyName() );
861 s->setInputItem( p_input_item );
863 services_discovery_AddItem( p_sd, p_input_item, NULL );
865 _list.push_back( s );
867 return true;
870 MediaServer* MediaServerList::getServer( const char* UDN )
872 MediaServer* result = 0;
874 for ( unsigned int i = 0; i < _list.size(); i++ )
876 if( strcmp( UDN, _list[i]->getUDN() ) == 0 )
878 result = _list[i];
879 break;
883 return result;
886 MediaServer* MediaServerList::getServerBySID( const char* sid )
888 MediaServer* server = 0;
890 for ( unsigned int i = 0; i < _list.size(); i++ )
892 if ( _list[i]->compareSID( sid ) )
894 server = _list[i];
895 break;
899 return server;
902 void MediaServerList::removeServer( const char* UDN )
904 MediaServer* server = getServer( UDN );
905 if ( !server ) return;
907 msg_Dbg( _p_sd,
908 "Removing server '%s'", server->getFriendlyName() );
910 std::vector<MediaServer*>::iterator it;
911 for ( it = _list.begin(); it != _list.end(); it++ )
913 if ( *it == server )
915 _list.erase( it );
916 delete server;
917 break;
923 // Item...
925 Item::Item( Container* parent, const char* objectID, const char* title, const char* resource )
927 _parent = parent;
929 _objectID = objectID;
930 _title = title;
931 _resource = resource;
933 _inputItem = NULL;
936 Item::~Item()
938 if(_inputItem)
939 vlc_gc_decref( _inputItem );
942 const char* Item::getObjectID() const
944 return _objectID.c_str();
947 const char* Item::getTitle() const
949 return _title.c_str();
952 const char* Item::getResource() const
954 return _resource.c_str();
957 void Item::setInputItem( input_item_t* p_input_item )
959 if(_inputItem == p_input_item)
960 return;
962 if(_inputItem)
963 vlc_gc_decref( _inputItem );
965 vlc_gc_incref( p_input_item );
966 _inputItem = p_input_item;
969 input_item_t* Item::getInputItem() const
971 return _inputItem;
975 // Container...
977 Container::Container( Container* parent,
978 const char* objectID,
979 const char* title )
981 _parent = parent;
983 _objectID = objectID;
984 _title = title;
986 _inputItem = NULL;
989 Container::~Container()
991 for ( unsigned int i = 0; i < _containers.size(); i++ )
993 delete _containers[i];
996 for ( unsigned int i = 0; i < _items.size(); i++ )
998 delete _items[i];
1001 if(_inputItem )
1002 vlc_gc_decref( _inputItem );
1005 void Container::addItem( Item* item )
1007 _items.push_back( item );
1010 void Container::addContainer( Container* container )
1012 _containers.push_back( container );
1015 const char* Container::getObjectID() const
1017 return _objectID.c_str();
1020 const char* Container::getTitle() const
1022 return _title.c_str();
1025 unsigned int Container::getNumItems() const
1027 return _items.size();
1030 unsigned int Container::getNumContainers() const
1032 return _containers.size();
1035 Item* Container::getItem( unsigned int i ) const
1037 if ( i < _items.size() ) return _items[i];
1038 return 0;
1041 Container* Container::getContainer( unsigned int i ) const
1043 if ( i < _containers.size() ) return _containers[i];
1044 return 0;
1047 Container* Container::getParent()
1049 return _parent;
1052 void Container::setInputItem( input_item_t* p_input_item )
1054 if(_inputItem == p_input_item)
1055 return;
1057 if(_inputItem)
1058 vlc_gc_decref( _inputItem );
1060 vlc_gc_incref( p_input_item );
1061 _inputItem = p_input_item;
1064 input_item_t* Container::getInputItem() const
1066 return _inputItem;