1 /*****************************************************************************
2 * Upnp_intel.cpp : UPnP discovery module (Intel SDK)
3 *****************************************************************************
4 * Copyright (C) 2004-2008 the VideoLAN team
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 ???
37 #include <upnp/upnp.h>
38 #include <upnp/upnptools.h>
45 #include <vlc_common.h>
46 #include <vlc_plugin.h>
47 #include <vlc_services_discovery.h>
51 const char* MEDIA_SERVER_DEVICE_TYPE = "urn:schemas-upnp-org:device:MediaServer:1";
52 const char* CONTENT_DIRECTORY_SERVICE_TYPE = "urn:schemas-upnp-org:service:ContentDirectory:1";
57 class MediaServerList;
64 struct services_discovery_sys_t
66 UpnpClient_Handle clientHandle;
67 MediaServerList* serverList;
68 Lockable* callbackLock;
71 // Class definitions...
79 vlc_mutex_init( &_mutex );
84 vlc_mutex_destroy( &_mutex );
87 void lock() { vlc_mutex_lock( &_mutex ); }
88 void unlock() { vlc_mutex_unlock( &_mutex ); }
119 static void parseDeviceDescription( IXML_Document* doc,
120 const char* location,
121 services_discovery_t* p_sd );
123 MediaServer( const char* UDN,
124 const char* friendlyName,
125 services_discovery_t* p_sd );
129 const char* getUDN() const;
130 const char* getFriendlyName() const;
132 void setContentDirectoryEventURL( const char* url );
133 const char* getContentDirectoryEventURL() const;
135 void setContentDirectoryControlURL( const char* url );
136 const char* getContentDirectoryControlURL() const;
138 void subscribeToContentDirectory();
139 void fetchContents();
141 void setInputItem( input_item_t* p_input_item );
143 bool compareSID( const char* sid );
147 bool _fetchContents( Container* parent );
148 void _buildPlaylist( Container* container );
150 IXML_Document* _browseAction( const char*, const char*,
151 const char*, const char*, const char*, const char* );
153 services_discovery_t* _p_sd;
155 Container* _contents;
156 input_item_t* _inputItem;
159 std::string _friendlyName;
161 std::string _contentDirectoryEventURL;
162 std::string _contentDirectoryControlURL;
164 int _subscriptionTimeOut;
165 Upnp_SID _subscriptionID;
169 class MediaServerList
173 MediaServerList( services_discovery_t* p_sd );
176 bool addServer( MediaServer* s );
177 void removeServer( const char* UDN );
179 MediaServer* getServer( const char* UDN );
180 MediaServer* getServerBySID( const char* );
184 services_discovery_t* _p_sd;
186 std::vector<MediaServer*> _list;
194 Item( Container* parent,
195 const char* objectID,
197 const char* resource );
200 const char* getObjectID() const;
201 const char* getTitle() const;
202 const char* getResource() const;
204 void setInputItem( input_item_t* p_input_item );
205 input_item_t* getInputItem() const ;
209 input_item_t* _inputItem;
212 std::string _objectID;
214 std::string _resource;
222 Container( Container* parent, const char* objectID, const char* title );
225 void addItem( Item* item );
226 void addContainer( Container* container );
228 const char* getObjectID() const;
229 const char* getTitle() const;
231 unsigned int getNumItems() const;
232 unsigned int getNumContainers() const;
234 Item* getItem( unsigned int i ) const;
235 Container* getContainer( unsigned int i ) const;
236 Container* getParent();
238 void setInputItem( input_item_t* p_input_item );
239 input_item_t* getInputItem() const;
243 input_item_t* _inputItem;
247 std::string _objectID;
249 std::vector<Item*> _items;
250 std::vector<Container*> _containers;
253 // VLC callback prototypes
255 static int Open( vlc_object_t* );
256 static void Close( vlc_object_t* );
257 static void Run( services_discovery_t *p_sd );
262 set_shortname( "UPnP" );
263 set_description( N_( "Universal Plug'n'Play discovery ( Intel SDK )" ) );
264 set_category( CAT_PLAYLIST );
265 set_subcategory( SUBCAT_PLAYLIST_SD );
266 set_capability( "services_discovery", 0 );
267 set_callbacks( Open, Close );
271 // More prototypes...
273 static int Callback( Upnp_EventType eventType, void* event, void* user_data );
275 const char* xml_getChildElementValue( IXML_Element* parent,
276 const char* tagName );
278 IXML_Document* parseBrowseResult( IXML_Document* doc );
283 static int Open( vlc_object_t *p_this )
286 services_discovery_t *p_sd = ( services_discovery_t* )p_this;
287 services_discovery_sys_t *p_sys = ( services_discovery_sys_t * )
288 calloc( 1, sizeof( services_discovery_sys_t ) );
290 if(!(p_sd->p_sys = p_sys))
293 services_discovery_SetLocalizedName( p_sd, _("UPnP devices") );
295 res = UpnpInit( 0, 0 );
296 if( res != UPNP_E_SUCCESS )
298 msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
302 p_sys->serverList = new MediaServerList( p_sd );
303 p_sys->callbackLock = new Lockable();
305 res = UpnpRegisterClient( Callback, p_sd, &p_sys->clientHandle );
306 if( res != UPNP_E_SUCCESS )
308 msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
309 Close( (vlc_object_t*) p_sd );
313 res = UpnpSearchAsync( p_sys->clientHandle, 5,
314 MEDIA_SERVER_DEVICE_TYPE, p_sd );
316 if( res != UPNP_E_SUCCESS )
318 msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
319 Close( (vlc_object_t*) p_sd );
326 static void Close( vlc_object_t *p_this )
328 services_discovery_t *p_sd = ( services_discovery_t* )p_this;
331 delete p_sd->p_sys->serverList;
332 delete p_sd->p_sys->callbackLock;
337 static void Run( services_discovery_t* p_sd )
340 msg_Dbg( p_sd, "UPnP discovery started" );
341 while( vlc_object_alive (p_sd) )
346 msg_Dbg( p_sd, "UPnP discovery stopped" );
351 // XML utility functions:
353 // Returns the value of a child element, or 0 on error
354 const char* xml_getChildElementValue( IXML_Element* parent,
355 const char* tagName )
357 if ( !parent ) return 0;
358 if ( !tagName ) return 0;
360 char* s = strdup( tagName );
361 IXML_NodeList* nodeList = ixmlElement_getElementsByTagName( parent, s );
363 if ( !nodeList ) return 0;
365 IXML_Node* element = ixmlNodeList_item( nodeList, 0 );
366 ixmlNodeList_free( nodeList );
367 if ( !element ) return 0;
369 IXML_Node* textNode = ixmlNode_getFirstChild( element );
370 if ( !textNode ) return 0;
372 return ixmlNode_getNodeValue( textNode );
375 // Extracts the result document from a SOAP response
376 IXML_Document* parseBrowseResult( IXML_Document* doc )
380 if ( !doc ) return 0;
382 IXML_NodeList* resultList = ixmlDocument_getElementsByTagName( doc,
385 if ( !resultList ) return 0;
387 IXML_Node* resultNode = ixmlNodeList_item( resultList, 0 );
389 ixmlNodeList_free( resultList );
391 if ( !resultNode ) return 0;
393 IXML_Node* textNode = ixmlNode_getFirstChild( resultNode );
394 if ( !textNode ) return 0;
396 const char* resultString = ixmlNode_getNodeValue( textNode );
397 char* resultXML = strdup( resultString );
399 IXML_Document* browseDoc = ixmlParseBuffer( resultXML );
407 // Handles all UPnP events
408 static int Callback( Upnp_EventType eventType, void* event, void* user_data )
410 services_discovery_t *p_sd = ( services_discovery_t* ) user_data;
411 services_discovery_sys_t* p_sys = p_sd->p_sys;
412 Locker locker( p_sys->callbackLock );
414 switch( eventType ) {
416 case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
417 case UPNP_DISCOVERY_SEARCH_RESULT:
419 struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
421 IXML_Document *descriptionDoc = 0;
424 res = UpnpDownloadXmlDoc( discovery->Location, &descriptionDoc );
425 if ( res != UPNP_E_SUCCESS )
428 "%s:%d: Could not download device description!",
429 __FILE__, __LINE__ );
433 MediaServer::parseDeviceDescription( descriptionDoc,
434 discovery->Location, p_sd );
436 ixmlDocument_free( descriptionDoc );
440 case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
442 struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
444 p_sys->serverList->removeServer( discovery->DeviceId );
448 case UPNP_EVENT_RECEIVED:
450 Upnp_Event* e = ( Upnp_Event* )event;
452 MediaServer* server = p_sys->serverList->getServerBySID( e->Sid );
453 if ( server ) server->fetchContents();
457 case UPNP_EVENT_AUTORENEWAL_FAILED:
458 case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
462 Upnp_Event_Subscribe* s = ( Upnp_Event_Subscribe* )event;
464 MediaServer* server = p_sys->serverList->getServerBySID( s->Sid );
465 if ( server ) server->subscribeToContentDirectory();
469 case UPNP_EVENT_SUBSCRIBE_COMPLETE:
470 msg_Warn( p_sd, "subscription complete" );
473 case UPNP_DISCOVERY_SEARCH_TIMEOUT:
474 msg_Warn( p_sd, "search timeout" );
479 "%s:%d: DEBUG: UNHANDLED EVENT ( TYPE=%d )",
480 __FILE__, __LINE__, eventType );
484 return UPNP_E_SUCCESS;
488 // Class implementations...
492 void MediaServer::parseDeviceDescription( IXML_Document* doc,
493 const char* location,
494 services_discovery_t* p_sd )
498 msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ );
504 msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ );
508 const char* baseURL = location;
510 // Try to extract baseURL
512 IXML_NodeList* urlList = ixmlDocument_getElementsByTagName( doc, "baseURL" );
516 if ( IXML_Node* urlNode = ixmlNodeList_item( urlList, 0 ) )
518 IXML_Node* textNode = ixmlNode_getFirstChild( urlNode );
519 if ( textNode ) baseURL = ixmlNode_getNodeValue( textNode );
522 ixmlNodeList_free( urlList );
527 IXML_NodeList* deviceList =
528 ixmlDocument_getElementsByTagName( doc, "device" );
532 for ( unsigned int i = 0; i < ixmlNodeList_length( deviceList ); i++ )
534 IXML_Element* deviceElement =
535 ( IXML_Element* ) ixmlNodeList_item( deviceList, i );
537 const char* deviceType = xml_getChildElementValue( deviceElement,
542 "%s:%d: no deviceType!",
543 __FILE__, __LINE__ );
547 if ( strcmp( MEDIA_SERVER_DEVICE_TYPE, deviceType ) != 0 )
550 const char* UDN = xml_getChildElementValue( deviceElement, "UDN" );
553 msg_Dbg( p_sd, "%s:%d: no UDN!",
554 __FILE__, __LINE__ );
558 if ( p_sd->p_sys->serverList->getServer( UDN ) != 0 )
561 const char* friendlyName =
562 xml_getChildElementValue( deviceElement,
567 msg_Dbg( p_sd, "%s:%d: no friendlyName!", __FILE__, __LINE__ );
571 MediaServer* server = new MediaServer( UDN, friendlyName, p_sd );
573 if ( !p_sd->p_sys->serverList->addServer( server ) )
581 // Check for ContentDirectory service...
582 IXML_NodeList* serviceList =
583 ixmlElement_getElementsByTagName( deviceElement,
587 for ( unsigned int j = 0;
588 j < ixmlNodeList_length( serviceList ); j++ )
590 IXML_Element* serviceElement =
591 ( IXML_Element* ) ixmlNodeList_item( serviceList, j );
593 const char* serviceType =
594 xml_getChildElementValue( serviceElement,
599 if ( strcmp( CONTENT_DIRECTORY_SERVICE_TYPE,
603 const char* eventSubURL =
604 xml_getChildElementValue( serviceElement,
609 const char* controlURL =
610 xml_getChildElementValue( serviceElement,
615 // Try to subscribe to ContentDirectory service
617 char* url = ( char* ) malloc( strlen( baseURL ) +
618 strlen( eventSubURL ) + 1 );
621 char* s1 = strdup( baseURL );
622 char* s2 = strdup( eventSubURL );
624 if ( UpnpResolveURL( s1, s2, url ) ==
627 server->setContentDirectoryEventURL( url );
628 server->subscribeToContentDirectory();
636 // Try to browse content directory...
638 url = ( char* ) malloc( strlen( baseURL ) +
639 strlen( controlURL ) + 1 );
642 char* s1 = strdup( baseURL );
643 char* s2 = strdup( controlURL );
645 if ( UpnpResolveURL( s1, s2, url ) ==
648 server->setContentDirectoryControlURL( url );
649 server->fetchContents();
657 ixmlNodeList_free( serviceList );
660 ixmlNodeList_free( deviceList );
664 MediaServer::MediaServer( const char* UDN,
665 const char* friendlyName,
666 services_discovery_t* p_sd )
671 _friendlyName = friendlyName;
677 MediaServer::~MediaServer()
682 const char* MediaServer::getUDN() const
684 const char* s = _UDN.c_str();
688 const char* MediaServer::getFriendlyName() const
690 const char* s = _friendlyName.c_str();
694 void MediaServer::setContentDirectoryEventURL( const char* url )
696 _contentDirectoryEventURL = url;
699 const char* MediaServer::getContentDirectoryEventURL() const
701 const char* s = _contentDirectoryEventURL.c_str();
705 void MediaServer::setContentDirectoryControlURL( const char* url )
707 _contentDirectoryControlURL = url;
710 const char* MediaServer::getContentDirectoryControlURL() const
712 return _contentDirectoryControlURL.c_str();
715 void MediaServer::subscribeToContentDirectory()
717 const char* url = getContentDirectoryEventURL();
718 if ( !url || strcmp( url, "" ) == 0 )
720 msg_Dbg( _p_sd, "No subscription url set!" );
727 int res = UpnpSubscribe( _p_sd->p_sys->clientHandle, url, &timeOut, sid );
729 if ( res == UPNP_E_SUCCESS )
731 _subscriptionTimeOut = timeOut;
732 memcpy( _subscriptionID, sid, sizeof( Upnp_SID ) );
737 "%s:%d: WARNING: '%s': %s", __FILE__, __LINE__,
738 getFriendlyName(), UpnpGetErrorMessage( res ) );
742 IXML_Document* MediaServer::_browseAction( const char* pObjectID,
743 const char* pBrowseFlag,
745 const char* pStartingIndex,
746 const char* pRequestedCount,
747 const char* pSortCriteria )
749 IXML_Document* action = 0;
750 IXML_Document* response = 0;
751 const char* url = getContentDirectoryControlURL();
753 if ( !url || strcmp( url, "" ) == 0 )
755 msg_Dbg( _p_sd, "No subscription url set!" );
759 char* ObjectID = strdup( pObjectID );
760 char* BrowseFlag = strdup( pBrowseFlag );
761 char* Filter = strdup( pFilter );
762 char* StartingIndex = strdup( pStartingIndex );
763 char* RequestedCount = strdup( pRequestedCount );
764 char* SortCriteria = strdup( pSortCriteria );
765 char* serviceType = strdup( CONTENT_DIRECTORY_SERVICE_TYPE );
769 res = UpnpAddToAction( &action, "Browse",
770 serviceType, "ObjectID", ObjectID );
772 if ( res != UPNP_E_SUCCESS )
775 "%s:%d: ERROR: %s", __FILE__, __LINE__,
776 UpnpGetErrorMessage( res ) );
777 goto browseActionCleanup;
780 res = UpnpAddToAction( &action, "Browse",
781 serviceType, "BrowseFlag", BrowseFlag );
783 if ( res != UPNP_E_SUCCESS )
786 "%s:%d: ERROR: %s", __FILE__, __LINE__,
787 UpnpGetErrorMessage( res ) );
788 goto browseActionCleanup;
791 res = UpnpAddToAction( &action, "Browse",
792 serviceType, "Filter", Filter );
794 if ( res != UPNP_E_SUCCESS )
797 "%s:%d: ERROR: %s", __FILE__, __LINE__,
798 UpnpGetErrorMessage( res ) );
799 goto browseActionCleanup;
802 res = UpnpAddToAction( &action, "Browse",
803 serviceType, "StartingIndex", StartingIndex );
805 if ( res != UPNP_E_SUCCESS )
808 "%s:%d: ERROR: %s", __FILE__, __LINE__,
809 UpnpGetErrorMessage( res ) );
810 goto browseActionCleanup;
813 res = UpnpAddToAction( &action, "Browse",
814 serviceType, "RequestedCount", RequestedCount );
816 if ( res != UPNP_E_SUCCESS )
819 "%s:%d: ERROR: %s", __FILE__, __LINE__,
820 UpnpGetErrorMessage( res ) ); goto browseActionCleanup; }
822 res = UpnpAddToAction( &action, "Browse",
823 serviceType, "SortCriteria", SortCriteria );
825 if ( res != UPNP_E_SUCCESS )
828 "%s:%d: ERROR: %s", __FILE__, __LINE__,
829 UpnpGetErrorMessage( res ) );
830 goto browseActionCleanup;
833 res = UpnpSendAction( _p_sd->p_sys->clientHandle,
835 CONTENT_DIRECTORY_SERVICE_TYPE,
840 if ( res != UPNP_E_SUCCESS )
843 "%s:%d: ERROR: %s when trying the send() action with URL: %s",
845 UpnpGetErrorMessage( res ), url );
847 ixmlDocument_free( response );
856 free( StartingIndex );
857 free( RequestedCount );
858 free( SortCriteria );
862 ixmlDocument_free( action );
866 void MediaServer::fetchContents()
868 Container* root = new Container( 0, "0", getFriendlyName() );
869 _fetchContents( root );
874 // playlist_NodeEmpty( p_playlist, _playlistNode, true );
880 _contents->setInputItem( _inputItem );
882 _buildPlaylist( _contents );
885 bool MediaServer::_fetchContents( Container* parent )
890 "%s:%d: parent==NULL", __FILE__, __LINE__ );
894 IXML_Document* response = _browseAction( parent->getObjectID(),
895 "BrowseDirectChildren",
900 "%s:%d: ERROR! No response from browse() action",
901 __FILE__, __LINE__ );
905 IXML_Document* result = parseBrowseResult( response );
906 ixmlDocument_free( response );
911 "%s:%d: ERROR! browse() response parsing failed",
912 __FILE__, __LINE__ );
916 IXML_NodeList* containerNodeList =
917 ixmlDocument_getElementsByTagName( result, "container" );
919 if ( containerNodeList )
921 for ( unsigned int i = 0;
922 i < ixmlNodeList_length( containerNodeList ); i++ )
924 IXML_Element* containerElement =
925 ( IXML_Element* )ixmlNodeList_item( containerNodeList, i );
927 const char* objectID = ixmlElement_getAttribute( containerElement,
932 const char* childCountStr =
933 ixmlElement_getAttribute( containerElement, "childCount" );
935 if ( !childCountStr )
938 int childCount = atoi( childCountStr );
939 const char* title = xml_getChildElementValue( containerElement,
945 const char* resource = xml_getChildElementValue( containerElement,
948 if ( resource && childCount < 1 )
950 Item* item = new Item( parent, objectID, title, resource );
951 parent->addItem( item );
956 Container* container = new Container( parent, objectID, title );
957 parent->addContainer( container );
959 if ( childCount > 0 )
960 _fetchContents( container );
963 ixmlNodeList_free( containerNodeList );
966 IXML_NodeList* itemNodeList = ixmlDocument_getElementsByTagName( result,
970 for ( unsigned int i = 0; i < ixmlNodeList_length( itemNodeList ); i++ )
972 IXML_Element* itemElement =
973 ( IXML_Element* )ixmlNodeList_item( itemNodeList, i );
975 const char* objectID =
976 ixmlElement_getAttribute( itemElement, "id" );
982 xml_getChildElementValue( itemElement, "dc:title" );
987 const char* resource =
988 xml_getChildElementValue( itemElement, "res" );
993 Item* item = new Item( parent, objectID, title, resource );
994 parent->addItem( item );
996 ixmlNodeList_free( itemNodeList );
999 ixmlDocument_free( result );
1003 void MediaServer::_buildPlaylist( Container* parent )
1005 for ( unsigned int i = 0; i < parent->getNumContainers(); i++ )
1007 Container* container = parent->getContainer( i );
1009 input_item_t* p_input_item = input_item_New( _p_sd, "vlc://nop", parent->getTitle() );
1010 input_item_AddSubItem( parent->getInputItem(), p_input_item );
1012 container->setInputItem( p_input_item );
1013 _buildPlaylist( container );
1016 for ( unsigned int i = 0; i < parent->getNumItems(); i++ )
1018 Item* item = parent->getItem( i );
1020 input_item_t* p_input_item = input_item_New( _p_sd,
1021 item->getResource(),
1023 assert( p_input_item );
1024 input_item_AddSubItem( parent->getInputItem(), p_input_item );
1025 item->setInputItem( p_input_item );
1029 void MediaServer::setInputItem( input_item_t* p_input_item )
1031 if(_inputItem == p_input_item)
1035 vlc_gc_decref( _inputItem );
1037 vlc_gc_incref( p_input_item );
1038 _inputItem = p_input_item;
1041 bool MediaServer::compareSID( const char* sid )
1043 return ( strncmp( _subscriptionID, sid, sizeof( Upnp_SID ) ) == 0 );
1047 // MediaServerList...
1049 MediaServerList::MediaServerList( services_discovery_t* p_sd )
1054 MediaServerList::~MediaServerList()
1056 for ( unsigned int i = 0; i < _list.size(); i++ )
1062 bool MediaServerList::addServer( MediaServer* s )
1064 input_item_t* p_input_item = NULL;
1065 if ( getServer( s->getUDN() ) != 0 ) return false;
1067 msg_Dbg( _p_sd, "Adding server '%s'",
1068 s->getFriendlyName() );
1070 services_discovery_t* p_sd = _p_sd;
1072 p_input_item = input_item_New( p_sd, "vlc://nop", s->getFriendlyName() );
1073 s->setInputItem( p_input_item );
1075 services_discovery_AddItem( p_sd, p_input_item, NULL );
1077 _list.push_back( s );
1082 MediaServer* MediaServerList::getServer( const char* UDN )
1084 MediaServer* result = 0;
1086 for ( unsigned int i = 0; i < _list.size(); i++ )
1088 if( strcmp( UDN, _list[i]->getUDN() ) == 0 )
1098 MediaServer* MediaServerList::getServerBySID( const char* sid )
1100 MediaServer* server = 0;
1102 for ( unsigned int i = 0; i < _list.size(); i++ )
1104 if ( _list[i]->compareSID( sid ) )
1114 void MediaServerList::removeServer( const char* UDN )
1116 MediaServer* server = getServer( UDN );
1117 if ( !server ) return;
1120 "Removing server '%s'", server->getFriendlyName() );
1122 std::vector<MediaServer*>::iterator it;
1123 for ( it = _list.begin(); it != _list.end(); it++ )
1125 if ( *it == server )
1137 Item::Item( Container* parent, const char* objectID, const char* title, const char* resource )
1141 _objectID = objectID;
1143 _resource = resource;
1151 vlc_gc_decref( _inputItem );
1154 const char* Item::getObjectID() const
1156 return _objectID.c_str();
1159 const char* Item::getTitle() const
1161 return _title.c_str();
1164 const char* Item::getResource() const
1166 return _resource.c_str();
1169 void Item::setInputItem( input_item_t* p_input_item )
1171 if(_inputItem == p_input_item)
1175 vlc_gc_decref( _inputItem );
1177 vlc_gc_incref( p_input_item );
1178 _inputItem = p_input_item;
1181 input_item_t* Item::getInputItem() const
1189 Container::Container( Container* parent,
1190 const char* objectID,
1195 _objectID = objectID;
1201 Container::~Container()
1203 for ( unsigned int i = 0; i < _containers.size(); i++ )
1205 delete _containers[i];
1208 for ( unsigned int i = 0; i < _items.size(); i++ )
1214 vlc_gc_decref( _inputItem );
1217 void Container::addItem( Item* item )
1219 _items.push_back( item );
1222 void Container::addContainer( Container* container )
1224 _containers.push_back( container );
1227 const char* Container::getObjectID() const
1229 return _objectID.c_str();
1232 const char* Container::getTitle() const
1234 return _title.c_str();
1237 unsigned int Container::getNumItems() const
1239 return _items.size();
1242 unsigned int Container::getNumContainers() const
1244 return _containers.size();
1247 Item* Container::getItem( unsigned int i ) const
1249 if ( i < _items.size() ) return _items[i];
1253 Container* Container::getContainer( unsigned int i ) const
1255 if ( i < _containers.size() ) return _containers[i];
1259 Container* Container::getParent()
1264 void Container::setInputItem( input_item_t* p_input_item )
1266 if(_inputItem == p_input_item)
1270 vlc_gc_decref( _inputItem );
1272 vlc_gc_incref( p_input_item );
1273 _inputItem = p_input_item;
1276 input_item_t* Container::getInputItem() const