X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fservices_discovery%2Fupnp_intel.cpp;h=dec8f8db7157b5ea8322ae407498d3ec9a16b9a5;hb=c60652e38ac6afd74bd8225e9dae5406f13aaa4f;hp=7e0c247294f91fda7344c11a6324bd22a353a371;hpb=f452c11004a9eddf5fa3c9342b44590c936018a1;p=vlc diff --git a/modules/services_discovery/upnp_intel.cpp b/modules/services_discovery/upnp_intel.cpp index 7e0c247294..dec8f8db71 100644 --- a/modules/services_discovery/upnp_intel.cpp +++ b/modules/services_discovery/upnp_intel.cpp @@ -1,11 +1,12 @@ /***************************************************************************** - * Upnp_intell.cpp : UPnP discovery module (Intel SDK) + * Upnp_intel.cpp : UPnP discovery module (Intel SDK) ***************************************************************************** - * Copyright (C) 2004-2006 the VideoLAN team + * Copyright (C) 2004-2008 the VideoLAN team * $Id$ * * Authors: Rémi Denis-Courmont (original plugin) * Christian Henz + * Mirsal Ennaime * * UPnP Plugin using the Intel SDK (libupnp) instead of CyberLink * @@ -26,427 +27,225 @@ /* \TODO: Debug messages: "__FILE__, __LINE__" ok ???, Wrn/Err ??? - \TODO: Change names to VLC standard ??? */ - - -#include -#include - -#include -#include - #undef PACKAGE_NAME -#include -#include -#include "vlc_strings.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include "upnp_intel.hpp" -// VLC handle - -struct services_discovery_sys_t -{ - playlist_item_t *p_node_cat; - playlist_item_t *p_node_one; -}; +#include +#include // Constants - const char* MEDIA_SERVER_DEVICE_TYPE = "urn:schemas-upnp-org:device:MediaServer:1"; const char* CONTENT_DIRECTORY_SERVICE_TYPE = "urn:schemas-upnp-org:service:ContentDirectory:1"; - -// Classes - -class MediaServer; -class MediaServerList; -class Item; -class Container; - -// Cookie that is passed to the callback - -typedef struct -{ - services_discovery_t* serviceDiscovery; - UpnpClient_Handle clientHandle; - MediaServerList* serverList; -} Cookie; - - -// Class definitions... - -class Lockable -{ -public: - - Lockable( Cookie* c ) - { - vlc_mutex_init( c->serviceDiscovery, &_mutex ); - } - - ~Lockable() - { - vlc_mutex_destroy( &_mutex ); - } - - void lock() { vlc_mutex_lock( &_mutex ); } - void unlock() { vlc_mutex_unlock( &_mutex ); } - -private: - - vlc_mutex_t _mutex; -}; - - -class Locker -{ -public: - Locker( Lockable* l ) - { - _lockable = l; - _lockable->lock(); - } - - ~Locker() - { - _lockable->unlock(); - } - -private: - Lockable* _lockable; -}; - - -class MediaServer -{ -public: - - static void parseDeviceDescription( IXML_Document* doc, const char* location, Cookie* cookie ); - - MediaServer( const char* UDN, const char* friendlyName, Cookie* cookie ); - ~MediaServer(); - - const char* getUDN() const; - const char* getFriendlyName() const; - - void setContentDirectoryEventURL( const char* url ); - const char* getContentDirectoryEventURL() const; - - void setContentDirectoryControlURL( const char* url ); - const char* getContentDirectoryControlURL() const; - - void subscribeToContentDirectory(); - void fetchContents(); - - void setPlaylistNode( playlist_item_t* node ); - - bool compareSID( const char* sid ); - -private: - - bool _fetchContents( Container* parent ); - void _buildPlaylist( Container* container ); - IXML_Document* _browseAction( const char*, const char*, const char*, const char*, const char*, const char* ); - - Cookie* _cookie; - - Container* _contents; - playlist_item_t* _playlistNode; - - std::string _UDN; - std::string _friendlyName; - - std::string _contentDirectoryEventURL; - std::string _contentDirectoryControlURL; - - int _subscriptionTimeOut; - Upnp_SID _subscriptionID; -}; - - -class MediaServerList -{ -public: - - MediaServerList( Cookie* cookie ); - ~MediaServerList(); - - bool addServer( MediaServer* s ); - void removeServer( const char* UDN ); - - MediaServer* getServer( const char* UDN ); - MediaServer* getServerBySID( const char* ); - -private: - - Cookie* _cookie; - - std::vector _list; -}; - - -class Item -{ -public: - - Item( Container* parent, const char* objectID, const char* title, const char* resource ); - - const char* getObjectID() const; - const char* getTitle() const; - const char* getResource() const; - - void setPlaylistNode( playlist_item_t* node ); - playlist_item_t* getPlaylistNode() const ; - -private: - - playlist_item_t* _playlistNode; - - Container* _parent; - std::string _objectID; - std::string _title; - std::string _resource; -}; - - -class Container +// VLC handle +struct services_discovery_sys_t { -public: - - Container( Container* parent, const char* objectID, const char* title ); - ~Container(); - - void addItem( Item* item ); - void addContainer( Container* container ); - - const char* getObjectID() const; - const char* getTitle() const; - - unsigned int getNumItems() const; - unsigned int getNumContainers() const; - - Item* getItem( unsigned int i ) const; - Container* getContainer( unsigned int i ) const; - - void setPlaylistNode( playlist_item_t* node ); - playlist_item_t* getPlaylistNode() const; - -private: - - playlist_item_t* _playlistNode; - - Container* _parent; - - std::string _objectID; - std::string _title; - std::vector _items; - std::vector _containers; + UpnpClient_Handle client_handle; + MediaServerList* p_server_list; + vlc_mutex_t callback_lock; }; - // VLC callback prototypes - static int Open( vlc_object_t* ); static void Close( vlc_object_t* ); -static void Run( services_discovery_t *p_sd ); +VLC_SD_PROBE_HELPER("upnp_intel", "Universal Plug'n'Play", SD_CAT_LAN) // Module descriptor vlc_module_begin(); -set_shortname( "UPnP" ); -set_description( _( "Universal Plug'n'Play discovery ( Intel SDK )" ) ); -set_category( CAT_PLAYLIST ); -set_subcategory( SUBCAT_PLAYLIST_SD ); -set_capability( "services_discovery", 0 ); -set_callbacks( Open, Close ); + set_shortname( "UPnP" ); + set_description( N_( "Universal Plug'n'Play" ) ); + set_category( CAT_PLAYLIST ); + set_subcategory( SUBCAT_PLAYLIST_SD ); + set_capability( "services_discovery", 0 ); + set_callbacks( Open, Close ); + + VLC_SD_PROBE_SUBMODULE vlc_module_end(); // More prototypes... -static Lockable* CallbackLock; -static int Callback( Upnp_EventType eventType, void* event, void* pCookie ); +static int Callback( Upnp_EventType event_type, void* p_event, void* p_user_data ); -const char* xml_getChildElementValue( IXML_Element* parent, const char* tagName ); -IXML_Document* parseBrowseResult( IXML_Document* doc ); +const char* xml_getChildElementValue( IXML_Element* p_parent, + const char* psz_tag_name ); + +IXML_Document* parseBrowseResult( IXML_Document* p_doc ); // VLC callbacks... static int Open( vlc_object_t *p_this ) { + int i_res; services_discovery_t *p_sd = ( services_discovery_t* )p_this; services_discovery_sys_t *p_sys = ( services_discovery_sys_t * ) - malloc( sizeof( services_discovery_sys_t ) ); - - p_sd->pf_run = Run; - p_sd->p_sys = p_sys; + calloc( 1, sizeof( services_discovery_sys_t ) ); - /* Create our playlist node */ - playlist_NodesPairCreate( pl_Get( p_sd ), _("Devices"), - &p_sys->p_node_cat, &p_sys->p_node_one, - VLC_TRUE ); + if(!(p_sd->p_sys = p_sys)) + return VLC_ENOMEM; - return VLC_SUCCESS; -} - -static void Close( vlc_object_t *p_this ) -{ - services_discovery_t *p_sd = ( services_discovery_t* )p_this; - services_discovery_sys_t *p_sys = p_sd->p_sys; - - playlist_NodeDelete( pl_Get( p_sd ), p_sys->p_node_one, VLC_TRUE, - VLC_TRUE ); - playlist_NodeDelete( pl_Get( p_sd ), p_sys->p_node_cat, VLC_TRUE, - VLC_TRUE ); - - free( p_sys ); -} - -static void Run( services_discovery_t* p_sd ) -{ - int res; - - res = UpnpInit( 0, 0 ); - if( res != UPNP_E_SUCCESS ) + i_res = UpnpInit( 0, 0 ); + if( i_res != UPNP_E_SUCCESS ) { - msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) ); - return; + msg_Err( p_sd, "%s", UpnpGetErrorMessage( i_res ) ); + free( p_sys ); + return VLC_EGENERIC; } - Cookie cookie; - cookie.serviceDiscovery = p_sd; - cookie.serverList = new MediaServerList( &cookie ); - - CallbackLock = new Lockable( &cookie ); + p_sys->p_server_list = new MediaServerList( p_sd ); + vlc_mutex_init( &p_sys->callback_lock ); - res = UpnpRegisterClient( Callback, &cookie, &cookie.clientHandle ); - if( res != UPNP_E_SUCCESS ) + i_res = UpnpRegisterClient( Callback, p_sd, &p_sys->client_handle ); + if( i_res != UPNP_E_SUCCESS ) { - msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) ); - goto shutDown; + msg_Err( p_sd, "%s", UpnpGetErrorMessage( i_res ) ); + Close( (vlc_object_t*) p_sd ); + return VLC_EGENERIC; } - res = UpnpSearchAsync( cookie.clientHandle, 5, MEDIA_SERVER_DEVICE_TYPE, &cookie ); - if( res != UPNP_E_SUCCESS ) + i_res = UpnpSearchAsync( p_sys->client_handle, 5, + MEDIA_SERVER_DEVICE_TYPE, p_sd ); + + if( i_res != UPNP_E_SUCCESS ) { - msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) ); - goto shutDown; + msg_Err( p_sd, "%s", UpnpGetErrorMessage( i_res ) ); + Close( (vlc_object_t*) p_sd ); + return VLC_EGENERIC; } - msg_Dbg( p_sd, "UPnP discovery started" ); - while( !p_sd->b_die ) + i_res = UpnpSetMaxContentLength( 262144 ); + if( i_res != UPNP_E_SUCCESS ) { - msleep( 500 ); + msg_Err( p_sd, "%s", UpnpGetErrorMessage( i_res ) ); + Close( (vlc_object_t*) p_sd ); + return VLC_EGENERIC; } - msg_Dbg( p_sd, "UPnP discovery stopped" ); + return VLC_SUCCESS; +} + +static void Close( vlc_object_t *p_this ) +{ + services_discovery_t *p_sd = ( services_discovery_t* )p_this; - shutDown: UpnpFinish(); - delete cookie.serverList; - delete CallbackLock; -} + delete p_sd->p_sys->p_server_list; + vlc_mutex_destroy( &p_sd->p_sys->callback_lock ); + free( p_sd->p_sys ); +} // XML utility functions: // Returns the value of a child element, or 0 on error -const char* xml_getChildElementValue( IXML_Element* parent, const char* tagName ) +const char* xml_getChildElementValue( IXML_Element* p_parent, + const char* psz_tag_name_ ) { - if ( !parent ) return 0; - if ( !tagName ) return 0; + if ( !p_parent ) return 0; + if ( !psz_tag_name_ ) return 0; - char* s = strdup( tagName ); - IXML_NodeList* nodeList = ixmlElement_getElementsByTagName( parent, s ); - free( s ); - if ( !nodeList ) return 0; + char* psz_tag_name = strdup( psz_tag_name_ ); + IXML_NodeList* p_node_list = ixmlElement_getElementsByTagName( p_parent, psz_tag_name ); + free( psz_tag_name ); + if ( !p_node_list ) return 0; - IXML_Node* element = ixmlNodeList_item( nodeList, 0 ); - ixmlNodeList_free( nodeList ); - if ( !element ) return 0; + IXML_Node* p_element = ixmlNodeList_item( p_node_list, 0 ); + ixmlNodeList_free( p_node_list ); + if ( !p_element ) return 0; - IXML_Node* textNode = ixmlNode_getFirstChild( element ); - if ( !textNode ) return 0; + IXML_Node* p_text_node = ixmlNode_getFirstChild( p_element ); + if ( !p_text_node ) return 0; - return ixmlNode_getNodeValue( textNode ); + return ixmlNode_getNodeValue( p_text_node ); } // Extracts the result document from a SOAP response -IXML_Document* parseBrowseResult( IXML_Document* doc ) +IXML_Document* parseBrowseResult( IXML_Document* p_doc ) { - if ( !doc ) return 0; + ixmlRelaxParser(1); + + if ( !p_doc ) return 0; - IXML_NodeList* resultList = ixmlDocument_getElementsByTagName( doc, "Result" ); - if ( !resultList ) return 0; + IXML_NodeList* p_result_list = ixmlDocument_getElementsByTagName( p_doc, + "Result" ); - IXML_Node* resultNode = ixmlNodeList_item( resultList, 0 ); + if ( !p_result_list ) return 0; - ixmlNodeList_free( resultList ); + IXML_Node* p_result_node = ixmlNodeList_item( p_result_list, 0 ); - if ( !resultNode ) return 0; + ixmlNodeList_free( p_result_list ); - IXML_Node* textNode = ixmlNode_getFirstChild( resultNode ); - if ( !textNode ) return 0; + if ( !p_result_node ) return 0; - const char* resultString = ixmlNode_getNodeValue( textNode ); - char* resultXML = strdup( resultString ); + IXML_Node* p_text_node = ixmlNode_getFirstChild( p_result_node ); + if ( !p_text_node ) return 0; - resolve_xml_special_chars( resultXML ); + const char* psz_result_string = ixmlNode_getNodeValue( p_text_node ); + char* psz_result_xml = strdup( psz_result_string ); - IXML_Document* browseDoc = ixmlParseBuffer( resultXML ); + IXML_Document* p_browse_doc = ixmlParseBuffer( psz_result_xml ); - free( resultXML ); + free( psz_result_xml ); - return browseDoc; + return p_browse_doc; } // Handles all UPnP events -static int Callback( Upnp_EventType eventType, void* event, void* pCookie ) +static int Callback( Upnp_EventType event_type, void* p_event, void* p_user_data ) { - Locker locker( CallbackLock ); - - Cookie* cookie = ( Cookie* )pCookie; - - switch( eventType ) { + services_discovery_t* p_sd = ( services_discovery_t* ) p_user_data; + services_discovery_sys_t* p_sys = p_sd->p_sys; + vlc_mutex_locker locker( &p_sys->callback_lock ); + switch( event_type ) + { case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_SEARCH_RESULT: { - struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event; + struct Upnp_Discovery* p_discovery = ( struct Upnp_Discovery* )p_event; - IXML_Document *descriptionDoc = 0; + IXML_Document *p_description_doc = 0; - int res; - res = UpnpDownloadXmlDoc( discovery->Location, &descriptionDoc ); - if ( res != UPNP_E_SUCCESS ) + int i_res; + i_res = UpnpDownloadXmlDoc( p_discovery->Location, &p_description_doc ); + if ( i_res != UPNP_E_SUCCESS ) { - msg_Dbg( cookie->serviceDiscovery, "%s:%d: Could not download device description!", __FILE__, __LINE__ ); - return res; + msg_Dbg( p_sd, + "%s:%d: Could not download device description!", + __FILE__, __LINE__ ); + return i_res; } - MediaServer::parseDeviceDescription( descriptionDoc, discovery->Location, cookie ); + MediaServer::parseDeviceDescription( p_description_doc, + p_discovery->Location, p_sd ); - ixmlDocument_free( descriptionDoc ); + ixmlDocument_free( p_description_doc ); } break; case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: { - struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event; + struct Upnp_Discovery* p_discovery = ( struct Upnp_Discovery* )p_event; - cookie->serverList->removeServer( discovery->DeviceId ); + p_sys->p_server_list->removeServer( p_discovery->DeviceId ); } break; case UPNP_EVENT_RECEIVED: { - Upnp_Event* e = ( Upnp_Event* )event; + Upnp_Event* p_e = ( Upnp_Event* )p_event; - MediaServer* server = cookie->serverList->getServerBySID( e->Sid ); - if ( server ) server->fetchContents(); + MediaServer* p_server = p_sys->p_server_list->getServerBySID( p_e->Sid ); + if ( p_server ) p_server->fetchContents(); } break; @@ -455,23 +254,25 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie ) { // Re-subscribe... - Upnp_Event_Subscribe* s = ( Upnp_Event_Subscribe* )event; + Upnp_Event_Subscribe* p_s = ( Upnp_Event_Subscribe* )p_event; - MediaServer* server = cookie->serverList->getServerBySID( s->Sid ); - if ( server ) server->subscribeToContentDirectory(); + MediaServer* p_server = p_sys->p_server_list->getServerBySID( p_s->Sid ); + if ( p_server ) p_server->subscribeToContentDirectory(); } break; case UPNP_EVENT_SUBSCRIBE_COMPLETE: - msg_Warn( cookie->serviceDiscovery, "subscription complete" ); + msg_Warn( p_sd, "subscription complete" ); break; - + case UPNP_DISCOVERY_SEARCH_TIMEOUT: - msg_Warn( cookie->serviceDiscovery, "search timeout" ); + msg_Warn( p_sd, "search timeout" ); break; - + default: - msg_Dbg( cookie->serviceDiscovery, "%s:%d: DEBUG: UNHANDLED EVENT ( TYPE=%d )", __FILE__, __LINE__, eventType ); + msg_Dbg( p_sd, + "%s:%d: DEBUG: UNHANDLED EVENT ( TYPE=%d )", + __FILE__, __LINE__, event_type ); break; } @@ -483,145 +284,193 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie ) // MediaServer... -void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* location, Cookie* cookie ) +void MediaServer::parseDeviceDescription( IXML_Document* p_doc, + const char* p_location, + services_discovery_t* p_sd ) { - if ( !doc ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: NULL", __FILE__, __LINE__ ); return; } - if ( !location ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: NULL", __FILE__, __LINE__ ); return; } - - const char* baseURL = location; - - // Try to extract baseURL - - IXML_NodeList* urlList = ixmlDocument_getElementsByTagName( doc, "baseURL" ); - if ( urlList ) - { - if ( IXML_Node* urlNode = ixmlNodeList_item( urlList, 0 ) ) + if ( !p_doc ) { - IXML_Node* textNode = ixmlNode_getFirstChild( urlNode ); - if ( textNode ) baseURL = ixmlNode_getNodeValue( textNode ); + msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ ); + return; } - ixmlNodeList_free( urlList ); + if ( !p_location ) + { + msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ ); + return; } - // Get devices + const char* psz_base_url = p_location; - IXML_NodeList* deviceList = ixmlDocument_getElementsByTagName( doc, "device" ); - if ( deviceList ) - { + // Try to extract baseURL - for ( unsigned int i = 0; i < ixmlNodeList_length( deviceList ); i++ ) + IXML_NodeList* p_url_list = ixmlDocument_getElementsByTagName( p_doc, "baseURL" ); + if ( !p_url_list ) { - IXML_Element* deviceElement = ( IXML_Element* )ixmlNodeList_item( deviceList, i ); - const char* deviceType = xml_getChildElementValue( deviceElement, "deviceType" ); - if ( !deviceType ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: no deviceType!", __FILE__, __LINE__ ); continue; } - if ( strcmp( MEDIA_SERVER_DEVICE_TYPE, deviceType ) != 0 ) continue; - - const char* UDN = xml_getChildElementValue( deviceElement, "UDN" ); - if ( !UDN ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: no UDN!", __FILE__, __LINE__ ); continue; } - if ( cookie->serverList->getServer( UDN ) != 0 ) continue; - - const char* friendlyName = xml_getChildElementValue( deviceElement, "friendlyName" ); - if ( !friendlyName ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: no friendlyName!", __FILE__, __LINE__ ); continue; } - - MediaServer* server = new MediaServer( UDN, friendlyName, cookie ); - if ( !cookie->serverList->addServer( server ) ) { - - delete server; - server = 0; - continue; + if ( IXML_Node* p_url_node = ixmlNodeList_item( p_url_list, 0 ) ) + { + IXML_Node* p_text_node = ixmlNode_getFirstChild( p_url_node ); + if ( p_text_node ) psz_base_url = ixmlNode_getNodeValue( p_text_node ); } - // Check for ContentDirectory service... + ixmlNodeList_free( p_url_list ); + } - IXML_NodeList* serviceList = ixmlElement_getElementsByTagName( deviceElement, "service" ); - if ( serviceList ) - { - for ( unsigned int j = 0; j < ixmlNodeList_length( serviceList ); j++ ) - { - IXML_Element* serviceElement = ( IXML_Element* )ixmlNodeList_item( serviceList, j ); + // Get devices - const char* serviceType = xml_getChildElementValue( serviceElement, "serviceType" ); - if ( !serviceType ) continue; - if ( strcmp( CONTENT_DIRECTORY_SERVICE_TYPE, serviceType ) != 0 ) continue; + IXML_NodeList* p_device_list = + ixmlDocument_getElementsByTagName( p_doc, "device" ); - const char* eventSubURL = xml_getChildElementValue( serviceElement, "eventSubURL" ); - if ( !eventSubURL ) continue; + if ( p_device_list ) + { + for ( unsigned int i = 0; i < ixmlNodeList_length( p_device_list ); i++ ) + { + IXML_Element* p_device_element = + ( IXML_Element* ) ixmlNodeList_item( p_device_list, i ); - const char* controlURL = xml_getChildElementValue( serviceElement, "controlURL" ); - if ( !controlURL ) continue; + const char* psz_device_type = xml_getChildElementValue( p_device_element, + "deviceType" ); + if ( !psz_device_type ) + { + msg_Dbg( p_sd, + "%s:%d: no deviceType!", + __FILE__, __LINE__ ); + continue; + } - // Try to subscribe to ContentDirectory service + if ( strcmp( MEDIA_SERVER_DEVICE_TYPE, psz_device_type ) != 0 ) + continue; - char* url = ( char* )malloc( strlen( baseURL ) + strlen( eventSubURL ) + 1 ); - if ( url ) + const char* psz_udn = xml_getChildElementValue( p_device_element, "UDN" ); + if ( !psz_udn ) { - char* s1 = strdup( baseURL ); - char* s2 = strdup( eventSubURL ); + msg_Dbg( p_sd, "%s:%d: no UDN!", + __FILE__, __LINE__ ); + continue; + } - if ( UpnpResolveURL( s1, s2, url ) == UPNP_E_SUCCESS ) - { - // msg_Dbg( cookie->serviceDiscovery, "CDS EVENT URL: %s", url ); + if ( p_sd->p_sys->p_server_list->getServer( psz_udn ) != 0 ) + continue; - server->setContentDirectoryEventURL( url ); - server->subscribeToContentDirectory(); - } + const char* psz_friendly_name = + xml_getChildElementValue( p_device_element, + "friendlyName" ); - free( s1 ); - free( s2 ); - free( url ); + if ( !psz_friendly_name ) + { + msg_Dbg( p_sd, "%s:%d: no friendlyName!", __FILE__, __LINE__ ); + continue; } - // Try to browse content directory... + MediaServer* p_server = new MediaServer( psz_udn, psz_friendly_name, p_sd ); - url = ( char* )malloc( strlen( baseURL ) + strlen( controlURL ) + 1 ); - if ( url ) + if ( !p_sd->p_sys->p_server_list->addServer( p_server ) ) { - char* s1 = strdup( baseURL ); - char* s2 = strdup( controlURL ); - if ( UpnpResolveURL( s1, s2, url ) == UPNP_E_SUCCESS ) - { - // msg_Dbg( cookie->serviceDiscovery, "CDS CTRL URL: %s", url ); - - server->setContentDirectoryControlURL( url ); - server->fetchContents(); - } - - free( s1 ); - free( s2 ); - free( url ); + delete p_server; + p_server = 0; + continue; } - } - - ixmlNodeList_free( serviceList ); - } - } - ixmlNodeList_free( deviceList ); + // Check for ContentDirectory service... + IXML_NodeList* p_service_list = + ixmlElement_getElementsByTagName( p_device_element, + "service" ); + if ( p_service_list ) + { + for ( unsigned int j = 0; + j < ixmlNodeList_length( p_service_list ); j++ ) + { + IXML_Element* p_service_element = + ( IXML_Element* ) ixmlNodeList_item( p_service_list, j ); + + const char* psz_service_type = + xml_getChildElementValue( p_service_element, + "serviceType" ); + if ( !psz_service_type ) + continue; + + if ( strcmp( CONTENT_DIRECTORY_SERVICE_TYPE, + psz_service_type ) != 0 ) + continue; + + const char* psz_event_sub_url = + xml_getChildElementValue( p_service_element, + "eventSubURL" ); + if ( !psz_event_sub_url ) + continue; + + const char* psz_control_url = + xml_getChildElementValue( p_service_element, + "controlURL" ); + if ( !psz_control_url ) + continue; + + // Try to subscribe to ContentDirectory service + + char* psz_url = ( char* ) malloc( strlen( psz_base_url ) + + strlen( psz_event_sub_url ) + 1 ); + if ( psz_url ) + { + char* psz_s1 = strdup( psz_base_url ); + char* psz_s2 = strdup( psz_event_sub_url ); + + if ( UpnpResolveURL( psz_s1, psz_s2, psz_url ) == + UPNP_E_SUCCESS ) + { + p_server->setContentDirectoryEventURL( psz_url ); + p_server->subscribeToContentDirectory(); + } + + free( psz_s1 ); + free( psz_s2 ); + free( psz_url ); + } + + // Try to browse content directory... + + psz_url = ( char* ) malloc( strlen( psz_base_url ) + + strlen( psz_control_url ) + 1 ); + if ( psz_url ) + { + char* psz_s1 = strdup( psz_base_url ); + char* psz_s2 = strdup( psz_control_url ); + + if ( UpnpResolveURL( psz_s1, psz_s2, psz_url ) == + UPNP_E_SUCCESS ) + { + p_server->setContentDirectoryControlURL( psz_url ); + p_server->fetchContents(); + } + + free( psz_s1 ); + free( psz_s2 ); + free( psz_url ); + } + } + ixmlNodeList_free( p_service_list ); + } + } + ixmlNodeList_free( p_device_list ); } } -MediaServer::MediaServer( const char* UDN, const char* friendlyName, Cookie* cookie ) +MediaServer::MediaServer( const char* psz_udn, + const char* psz_friendly_name, + services_discovery_t* p_sd ) { - _cookie = cookie; + _p_sd = p_sd; - _UDN = UDN; - _friendlyName = friendlyName; + _UDN = psz_udn; + _friendlyName = psz_friendly_name; - _contents = 0; - _playlistNode = 0; + _contents = NULL; + _inputItem = NULL; } MediaServer::~MediaServer() { - if ( _contents ) - { - playlist_NodeDelete( pl_Get( _cookie->serviceDiscovery ) , - _playlistNode, VLC_TRUE, VLC_TRUE ); - } - delete _contents; } @@ -637,9 +486,9 @@ const char* MediaServer::getFriendlyName() const return s; } -void MediaServer::setContentDirectoryEventURL( const char* url ) +void MediaServer::setContentDirectoryEventURL( const char* psz_url ) { - _contentDirectoryEventURL = url; + _contentDirectoryEventURL = psz_url; } const char* MediaServer::getContentDirectoryEventURL() const @@ -648,9 +497,9 @@ const char* MediaServer::getContentDirectoryEventURL() const return s; } -void MediaServer::setContentDirectoryControlURL( const char* url ) +void MediaServer::setContentDirectoryControlURL( const char* psz_url ) { - _contentDirectoryControlURL = url; + _contentDirectoryControlURL = psz_url; } const char* MediaServer::getContentDirectoryControlURL() const @@ -660,228 +509,328 @@ const char* MediaServer::getContentDirectoryControlURL() const void MediaServer::subscribeToContentDirectory() { - const char* url = getContentDirectoryEventURL(); - if ( !url || strcmp( url, "" ) == 0 ) + const char* psz_url = getContentDirectoryEventURL(); + if ( !psz_url || strcmp( psz_url, "" ) == 0 ) { - msg_Dbg( _cookie->serviceDiscovery, "No subscription url set!" ); - return; + msg_Dbg( _p_sd, "No subscription url set!" ); + return; } - int timeOut = 1810; + int i_timeout = 1810; Upnp_SID sid; - int res = UpnpSubscribe( _cookie->clientHandle, url, &timeOut, sid ); + int i_res = UpnpSubscribe( _p_sd->p_sys->client_handle, psz_url, &i_timeout, sid ); - if ( res == UPNP_E_SUCCESS ) + if ( i_res == UPNP_E_SUCCESS ) { - _subscriptionTimeOut = timeOut; - memcpy( _subscriptionID, sid, sizeof( Upnp_SID ) ); + _subscriptionTimeOut = i_timeout; + memcpy( _subscriptionID, sid, sizeof( Upnp_SID ) ); } else { - msg_Dbg( _cookie->serviceDiscovery, "%s:%d: WARNING: '%s': %s", __FILE__, __LINE__, getFriendlyName(), UpnpGetErrorMessage( res ) ); + msg_Dbg( _p_sd, + "%s:%d: WARNING: '%s': %s", __FILE__, __LINE__, + getFriendlyName(), UpnpGetErrorMessage( i_res ) ); } } -IXML_Document* MediaServer::_browseAction( const char* pObjectID, const char* pBrowseFlag, const char* pFilter, - const char* pStartingIndex, const char* pRequestedCount, const char* pSortCriteria ) +IXML_Document* MediaServer::_browseAction( const char* psz_object_id_, + const char* psz_browser_flag_, + const char* psz_filter_, + const char* psz_starting_index_, + const char* psz_requested_count_, + const char* psz_sort_criteria_ ) { - IXML_Document* action = 0; - IXML_Document* response = 0; + IXML_Document* p_action = 0; + IXML_Document* p_response = 0; + const char* psz_url = getContentDirectoryControlURL(); + + if ( !psz_url || strcmp( psz_url, "" ) == 0 ) + { + msg_Dbg( _p_sd, "No subscription url set!" ); + return 0; + } + + char* psz_object_id = strdup( psz_object_id_ ); + char* psz_browse_flag = strdup( psz_browser_flag_ ); + char* psz_filter = strdup( psz_filter_ ); + char* psz_starting_index = strdup( psz_starting_index_ ); + char* psz_requested_count = strdup( psz_requested_count_ ); + char* psz_sort_criteria = strdup( psz_sort_criteria_ ); + char* psz_service_type = strdup( CONTENT_DIRECTORY_SERVICE_TYPE ); + + int i_res; + + i_res = UpnpAddToAction( &p_action, "Browse", + psz_service_type, "ObjectID", psz_object_id ); - const char* url = getContentDirectoryControlURL(); - if ( !url || strcmp( url, "" ) == 0 ) { msg_Dbg( _cookie->serviceDiscovery, "No subscription url set!" ); return 0; } + if ( i_res != UPNP_E_SUCCESS ) + { + msg_Dbg( _p_sd, + "%s:%d: ERROR: %s", __FILE__, __LINE__, + UpnpGetErrorMessage( i_res ) ); + goto browseActionCleanup; + } - char* ObjectID = strdup( pObjectID ); - char* BrowseFlag = strdup( pBrowseFlag ); - char* Filter = strdup( pFilter ); - char* StartingIndex = strdup( pStartingIndex ); - char* RequestedCount = strdup( pRequestedCount ); - char* SortCriteria = strdup( pSortCriteria ); + i_res = UpnpAddToAction( &p_action, "Browse", + psz_service_type, "BrowseFlag", psz_browse_flag ); + + if ( i_res != UPNP_E_SUCCESS ) + { + msg_Dbg( _p_sd, + "%s:%d: ERROR: %s", __FILE__, __LINE__, + UpnpGetErrorMessage( i_res ) ); + goto browseActionCleanup; + } - char* serviceType = strdup( CONTENT_DIRECTORY_SERVICE_TYPE ); + i_res = UpnpAddToAction( &p_action, "Browse", + psz_service_type, "Filter", psz_filter ); - int res; + if ( i_res != UPNP_E_SUCCESS ) + { + msg_Dbg( _p_sd, + "%s:%d: ERROR: %s", __FILE__, __LINE__, + UpnpGetErrorMessage( i_res ) ); + goto browseActionCleanup; + } - res = UpnpAddToAction( &action, "Browse", serviceType, "ObjectID", ObjectID ); - if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } + i_res = UpnpAddToAction( &p_action, "Browse", + psz_service_type, "StartingIndex", psz_starting_index ); - res = UpnpAddToAction( &action, "Browse", serviceType, "BrowseFlag", BrowseFlag ); - if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } + if ( i_res != UPNP_E_SUCCESS ) + { + msg_Dbg( _p_sd, + "%s:%d: ERROR: %s", __FILE__, __LINE__, + UpnpGetErrorMessage( i_res ) ); + goto browseActionCleanup; + } - res = UpnpAddToAction( &action, "Browse", serviceType, "Filter", Filter ); - if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } + i_res = UpnpAddToAction( &p_action, "Browse", + psz_service_type, "RequestedCount", psz_requested_count ); - res = UpnpAddToAction( &action, "Browse", serviceType, "StartingIndex", StartingIndex ); - if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } + if ( i_res != UPNP_E_SUCCESS ) + { + msg_Dbg( _p_sd, + "%s:%d: ERROR: %s", __FILE__, __LINE__, + UpnpGetErrorMessage( i_res ) ); goto browseActionCleanup; } - res = UpnpAddToAction( &action, "Browse", serviceType, "RequestedCount", RequestedCount ); - if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } + i_res = UpnpAddToAction( &p_action, "Browse", + psz_service_type, "SortCriteria", psz_sort_criteria ); - res = UpnpAddToAction( &action, "Browse", serviceType, "SortCriteria", SortCriteria ); - if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } + if ( i_res != UPNP_E_SUCCESS ) + { + msg_Dbg( _p_sd, + "%s:%d: ERROR: %s", __FILE__, __LINE__, + UpnpGetErrorMessage( i_res ) ); + goto browseActionCleanup; + } - res = UpnpSendAction( _cookie->clientHandle, - url, + i_res = UpnpSendAction( _p_sd->p_sys->client_handle, + psz_url, CONTENT_DIRECTORY_SERVICE_TYPE, 0, - action, - &response ); - if ( res != UPNP_E_SUCCESS ) + p_action, + &p_response ); + + if ( i_res != UPNP_E_SUCCESS ) { - msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); - ixmlDocument_free( response ); - response = 0; + msg_Dbg( _p_sd, + "%s:%d: ERROR: %s when trying the send() action with URL: %s", + __FILE__, __LINE__, + UpnpGetErrorMessage( i_res ), psz_url ); + + ixmlDocument_free( p_response ); + p_response = 0; } browseActionCleanup: - free( ObjectID ); - free( BrowseFlag ); - free( Filter ); - free( StartingIndex ); - free( RequestedCount ); - free( SortCriteria ); + free( psz_object_id ); + free( psz_browse_flag ); + free( psz_filter ); + free( psz_starting_index ); + free( psz_requested_count ); + free( psz_sort_criteria ); - free( serviceType ); + free( psz_service_type ); - ixmlDocument_free( action ); - return response; + ixmlDocument_free( p_action ); + return p_response; } void MediaServer::fetchContents() { Container* root = new Container( 0, "0", getFriendlyName() ); - playlist_t * p_playlist = pl_Get( _cookie->serviceDiscovery ); _fetchContents( root ); - if ( _contents ) - { - PL_LOCK; - playlist_NodeEmpty( p_playlist, _playlistNode, VLC_TRUE ); - PL_UNLOCK; - delete _contents; - } - _contents = root; - _contents->setPlaylistNode( _playlistNode ); + _contents->setInputItem( _inputItem ); - _buildPlaylist( _contents ); + _buildPlaylist( _contents, NULL ); } -bool MediaServer::_fetchContents( Container* parent ) +bool MediaServer::_fetchContents( Container* p_parent ) { - if (!parent) { msg_Dbg( _cookie->serviceDiscovery, "%s:%d: parent==NULL", __FILE__, __LINE__ ); return false; } + if (!p_parent) + { + msg_Dbg( _p_sd, + "%s:%d: parent==NULL", __FILE__, __LINE__ ); + return false; + } - IXML_Document* response = _browseAction( parent->getObjectID(), "BrowseDirectChildren", "*", "0", "0", "" ); - if ( !response ) { msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR!", __FILE__, __LINE__ ); return false; } + IXML_Document* p_response = _browseAction( p_parent->getObjectID(), + "BrowseDirectChildren", + "*", "0", "0", "" ); + if ( !p_response ) + { + msg_Dbg( _p_sd, + "%s:%d: ERROR! No response from browse() action", + __FILE__, __LINE__ ); + return false; + } - IXML_Document* result = parseBrowseResult( response ); - ixmlDocument_free( response ); - if ( !result ) { msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR!", __FILE__, __LINE__ ); return false; } + IXML_Document* result = parseBrowseResult( p_response ); + ixmlDocument_free( p_response ); - IXML_NodeList* containerNodeList = ixmlDocument_getElementsByTagName( result, "container" ); - if ( containerNodeList ) + if ( !result ) { - for ( unsigned int i = 0; i < ixmlNodeList_length( containerNodeList ); i++ ) + msg_Dbg( _p_sd, + "%s:%d: ERROR! browse() response parsing failed", + __FILE__, __LINE__ ); + return false; + } + + IXML_NodeList* containerNodeList = + ixmlDocument_getElementsByTagName( result, "container" ); + + if ( containerNodeList ) { - IXML_Element* containerElement = ( IXML_Element* )ixmlNodeList_item( containerNodeList, i ); + for ( unsigned int i = 0; + i < ixmlNodeList_length( containerNodeList ); i++ ) + { + IXML_Element* containerElement = + ( IXML_Element* )ixmlNodeList_item( containerNodeList, i ); - const char* objectID = ixmlElement_getAttribute( containerElement, "id" ); - if ( !objectID ) continue; + const char* objectID = ixmlElement_getAttribute( containerElement, + "id" ); + if ( !objectID ) + continue; - const char* childCountStr = ixmlElement_getAttribute( containerElement, "childCount" ); - if ( !childCountStr ) continue; - int childCount = atoi( childCountStr ); + const char* childCountStr = + ixmlElement_getAttribute( containerElement, "childCount" ); - const char* title = xml_getChildElementValue( containerElement, "dc:title" ); - if ( !title ) continue; + if ( !childCountStr ) + continue; - const char* resource = xml_getChildElementValue( containerElement, "res" ); + int childCount = atoi( childCountStr ); + const char* title = xml_getChildElementValue( containerElement, + "dc:title" ); - if ( resource && childCount < 1 ) - { - Item* item = new Item( parent, objectID, title, resource ); - parent->addItem( item ); - } - else - { - Container* container = new Container( parent, objectID, title ); - parent->addContainer( container ); + if ( !title ) + continue; - if ( childCount > 0 ) _fetchContents( container ); - } - } + const char* resource = xml_getChildElementValue( containerElement, + "res" ); + + if ( resource && childCount < 1 ) + { + Item* item = new Item( p_parent, objectID, title, resource ); + p_parent->addItem( item ); + } + + else + { + Container* container = new Container( p_parent, objectID, title ); + p_parent->addContainer( container ); - ixmlNodeList_free( containerNodeList ); + if ( childCount > 0 ) + _fetchContents( container ); + } + } + ixmlNodeList_free( containerNodeList ); } - IXML_NodeList* itemNodeList = ixmlDocument_getElementsByTagName( result, "item" ); + IXML_NodeList* itemNodeList = ixmlDocument_getElementsByTagName( result, + "item" ); if ( itemNodeList ) { for ( unsigned int i = 0; i < ixmlNodeList_length( itemNodeList ); i++ ) - { - IXML_Element* itemElement = ( IXML_Element* )ixmlNodeList_item( itemNodeList, i ); + { + IXML_Element* itemElement = + ( IXML_Element* )ixmlNodeList_item( itemNodeList, i ); - const char* objectID = ixmlElement_getAttribute( itemElement, "id" ); - if ( !objectID ) continue; + const char* objectID = + ixmlElement_getAttribute( itemElement, "id" ); - const char* title = xml_getChildElementValue( itemElement, "dc:title" ); - if ( !title ) continue; + if ( !objectID ) + continue; - const char* resource = xml_getChildElementValue( itemElement, "res" ); - if ( !resource ) continue; + const char* title = + xml_getChildElementValue( itemElement, "dc:title" ); - Item* item = new Item( parent, objectID, title, resource ); - parent->addItem( item ); - } + if ( !title ) + continue; + + const char* resource = + xml_getChildElementValue( itemElement, "res" ); + + if ( !resource ) + continue; - ixmlNodeList_free( itemNodeList ); + Item* item = new Item( p_parent, objectID, title, resource ); + p_parent->addItem( item ); + } + ixmlNodeList_free( itemNodeList ); } ixmlDocument_free( result ); - return true; } -void MediaServer::_buildPlaylist( Container* parent ) +void MediaServer::_buildPlaylist( Container* p_parent, input_item_node_t *p_input_node ) { - playlist_t *p_playlist = pl_Get( _cookie->serviceDiscovery ); - for ( unsigned int i = 0; i < parent->getNumContainers(); i++ ) + bool send = p_input_node == NULL; + if( send ) + p_input_node = input_item_node_Create( p_parent->getInputItem() ); + + for ( unsigned int i = 0; i < p_parent->getNumContainers(); i++ ) { - Container* container = parent->getContainer( i ); - playlist_item_t* parentNode = parent->getPlaylistNode(); + Container* container = p_parent->getContainer( i ); - char* title = strdup( container->getTitle() ); - playlist_item_t* node = playlist_NodeCreate( p_playlist, title, parentNode, 0, NULL ); - free( title ); + input_item_t* p_input_item = input_item_New( _p_sd, "vlc://nop", container->getTitle() ); + input_item_node_t *p_new_node = + input_item_node_AppendItem( p_input_node, p_input_item ); - container->setPlaylistNode( node ); - _buildPlaylist( container ); + container->setInputItem( p_input_item ); + _buildPlaylist( container, p_new_node ); } - for ( unsigned int i = 0; i < parent->getNumItems(); i++ ) + for ( unsigned int i = 0; i < p_parent->getNumItems(); i++ ) { - Item* item = parent->getItem( i ); - playlist_item_t* parentNode = parent->getPlaylistNode(); + Item* item = p_parent->getItem( i ); - input_item_t* p_input = input_ItemNew( _cookie->serviceDiscovery, + input_item_t* p_input_item = input_item_New( _p_sd, item->getResource(), item->getTitle() ); - int i_cat; - playlist_BothAddInput( p_playlist, p_input, parentNode, - PLAYLIST_APPEND, PLAYLIST_END, &i_cat, NULL, - VLC_FALSE ); - /* TODO: do this better by storing ids */ - playlist_item_t *p_node = playlist_ItemGetById( p_playlist, i_cat, VLC_FALSE ); - assert( p_node ); - item->setPlaylistNode( p_node ); + assert( p_input_item ); + input_item_node_AppendItem( p_input_node, p_input_item ); + item->setInputItem( p_input_item ); } + + if( send ) + input_item_node_PostAndDelete( p_input_node ); } -void MediaServer::setPlaylistNode( playlist_item_t* playlistNode ) +void MediaServer::setInputItem( input_item_t* p_input_item ) { - _playlistNode = playlistNode; + if(_inputItem == p_input_item) + return; + + if(_inputItem) + vlc_gc_decref( _inputItem ); + + vlc_gc_incref( p_input_item ); + _inputItem = p_input_item; } bool MediaServer::compareSID( const char* sid ) @@ -892,48 +841,50 @@ bool MediaServer::compareSID( const char* sid ) // MediaServerList... -MediaServerList::MediaServerList( Cookie* cookie ) +MediaServerList::MediaServerList( services_discovery_t* p_sd ) { - _cookie = cookie; + _p_sd = p_sd; } MediaServerList::~MediaServerList() { for ( unsigned int i = 0; i < _list.size(); i++ ) { - delete _list[i]; + delete _list[i]; } } bool MediaServerList::addServer( MediaServer* s ) { + input_item_t* p_input_item = NULL; if ( getServer( s->getUDN() ) != 0 ) return false; - msg_Dbg( _cookie->serviceDiscovery, "Adding server '%s'", s->getFriendlyName() ); + msg_Dbg( _p_sd, "Adding server '%s'", + s->getFriendlyName() ); - _list.push_back( s ); + services_discovery_t* p_sd = _p_sd; - char* name = strdup( s->getFriendlyName() ); - playlist_item_t* node = playlist_NodeCreate( pl_Get( _cookie->serviceDiscovery ), - name, - _cookie->serviceDiscovery->p_sys->p_node_cat, 0, NULL ); - free( name ); - s->setPlaylistNode( node ); + p_input_item = input_item_New( p_sd, "vlc://nop", s->getFriendlyName() ); + s->setInputItem( p_input_item ); + + services_discovery_AddItem( p_sd, p_input_item, NULL ); + + _list.push_back( s ); return true; } -MediaServer* MediaServerList::getServer( const char* UDN ) +MediaServer* MediaServerList::getServer( const char* psz_udn ) { MediaServer* result = 0; for ( unsigned int i = 0; i < _list.size(); i++ ) { - if( strcmp( UDN, _list[i]->getUDN() ) == 0 ) - { - result = _list[i]; - break; - } + if( strcmp( psz_udn, _list[i]->getUDN() ) == 0 ) + { + result = _list[i]; + break; + } } return result; @@ -941,51 +892,59 @@ MediaServer* MediaServerList::getServer( const char* UDN ) MediaServer* MediaServerList::getServerBySID( const char* sid ) { - MediaServer* server = 0; + MediaServer* p_server = 0; for ( unsigned int i = 0; i < _list.size(); i++ ) { - if ( _list[i]->compareSID( sid ) ) - { - server = _list[i]; - break; - } + if ( _list[i]->compareSID( sid ) ) + { + p_server = _list[i]; + break; + } } - return server; + return p_server; } -void MediaServerList::removeServer( const char* UDN ) +void MediaServerList::removeServer( const char* psz_udn ) { - MediaServer* server = getServer( UDN ); - if ( !server ) return; + MediaServer* p_server = getServer( psz_udn ); + if ( !p_server ) return; - msg_Dbg( _cookie->serviceDiscovery, "Removing server '%s'", server->getFriendlyName() ); + msg_Dbg( _p_sd, + "Removing server '%s'", p_server->getFriendlyName() ); std::vector::iterator it; for ( it = _list.begin(); it != _list.end(); it++ ) { - if ( *it == server ) - { - _list.erase( it ); - delete server; - break; - } + if ( *it == p_server ) + { + _list.erase( it ); + delete p_server; + break; + } } } // Item... -Item::Item( Container* parent, const char* objectID, const char* title, const char* resource ) +Item::Item( Container* p_parent, const char* psz_object_id, const char* psz_title, + const char* psz_resource ) { - _parent = parent; + _parent = p_parent; - _objectID = objectID; - _title = title; - _resource = resource; + _objectID = psz_object_id; + _title = psz_title; + _resource = psz_resource; + + _inputItem = NULL; +} - _playlistNode = 0; +Item::~Item() +{ + if(_inputItem) + vlc_gc_decref( _inputItem ); } const char* Item::getObjectID() const @@ -1003,40 +962,52 @@ const char* Item::getResource() const return _resource.c_str(); } -void Item::setPlaylistNode( playlist_item_t* node ) +void Item::setInputItem( input_item_t* p_input_item ) { - _playlistNode = node; + if(_inputItem == p_input_item) + return; + + if(_inputItem) + vlc_gc_decref( _inputItem ); + + vlc_gc_incref( p_input_item ); + _inputItem = p_input_item; } -playlist_item_t* Item::getPlaylistNode() const +input_item_t* Item::getInputItem() const { - return _playlistNode; + return _inputItem; } // Container... -Container::Container( Container* parent, const char* objectID, const char* title ) +Container::Container( Container* p_parent, + const char* psz_object_id, + const char* psz_title ) { - _parent = parent; + _parent = p_parent; - _objectID = objectID; - _title = title; + _objectID = psz_object_id; + _title = psz_title; - _playlistNode = 0; + _inputItem = NULL; } Container::~Container() { for ( unsigned int i = 0; i < _containers.size(); i++ ) { - delete _containers[i]; + delete _containers[i]; } for ( unsigned int i = 0; i < _items.size(); i++ ) { - delete _items[i]; + delete _items[i]; } + + if(_inputItem ) + vlc_gc_decref( _inputItem ); } void Container::addItem( Item* item ) @@ -1044,9 +1015,9 @@ void Container::addItem( Item* item ) _items.push_back( item ); } -void Container::addContainer( Container* container ) +void Container::addContainer( Container* p_container ) { - _containers.push_back( container ); + _containers.push_back( p_container ); } const char* Container::getObjectID() const @@ -1069,24 +1040,36 @@ unsigned int Container::getNumContainers() const return _containers.size(); } -Item* Container::getItem( unsigned int i ) const +Item* Container::getItem( unsigned int i_index ) const { - if ( i < _items.size() ) return _items[i]; + if ( i_index < _items.size() ) return _items[i_index]; return 0; } -Container* Container::getContainer( unsigned int i ) const +Container* Container::getContainer( unsigned int i_index ) const { - if ( i < _containers.size() ) return _containers[i]; + if ( i_index < _containers.size() ) return _containers[i_index]; return 0; } -void Container::setPlaylistNode( playlist_item_t* node ) +Container* Container::getParent() +{ + return _parent; +} + +void Container::setInputItem( input_item_t* p_input_item ) { - _playlistNode = node; + if(_inputItem == p_input_item) + return; + + if(_inputItem) + vlc_gc_decref( _inputItem ); + + vlc_gc_incref( p_input_item ); + _inputItem = p_input_item; } -playlist_item_t* Container::getPlaylistNode() const +input_item_t* Container::getInputItem() const { - return _playlistNode; + return _inputItem; }