X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fservices_discovery%2Fupnp_intel.cpp;h=a936de2ee93e6a84c29810470d62f53e7597e178;hb=2a2dd55119a03f4e410fca67cc07c7a4e990ed95;hp=297221bc101c482e75443ce9054f17206225b987;hpb=0e45933d1f30183c9b796d4f965be84ce118e228;p=vlc diff --git a/modules/services_discovery/upnp_intel.cpp b/modules/services_discovery/upnp_intel.cpp index 297221bc10..a936de2ee9 100644 --- a/modules/services_discovery/upnp_intel.cpp +++ b/modules/services_discovery/upnp_intel.cpp @@ -28,248 +28,51 @@ /* \TODO: Debug messages: "__FILE__, __LINE__" ok ???, Wrn/Err ??? \TODO: Change names to VLC standard ??? - \TODO: Rewrite this using the new service discovery API (see sap.c, shout.c). */ - - -#include -#include - -#include -#include - #undef PACKAGE_NAME #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include +#include "upnp_intel.hpp" + #include -#include +#include -// Constants +// 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; - // VLC handle - struct services_discovery_sys_t { UpnpClient_Handle clientHandle; MediaServerList* serverList; + vlc_mutex_t callbackLock; }; -// Class definitions... - -class Lockable -{ -public: - - Lockable() - { - vlc_mutex_init( &_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, - services_discovery_t* p_sd ); - - MediaServer( const char* UDN, - const char* friendlyName, - services_discovery_t* p_sd ); - - ~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* ); - - services_discovery_t* _p_sd; - - 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( services_discovery_t* p_sd ); - ~MediaServerList(); - - bool addServer( MediaServer* s ); - void removeServer( const char* UDN ); - - MediaServer* getServer( const char* UDN ); - MediaServer* getServerBySID( const char* ); - -private: - - services_discovery_t* _p_sd; - - 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 -{ -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; -}; - - // 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", N_("Universal Plug'n'Play"), SD_CAT_LAN) // Module descriptor vlc_module_begin(); -set_shortname( "UPnP" ); -set_description( N_( "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* user_data ); const char* xml_getChildElementValue( IXML_Element* parent, @@ -287,21 +90,21 @@ static int Open( vlc_object_t *p_this ) services_discovery_sys_t *p_sys = ( services_discovery_sys_t * ) calloc( 1, sizeof( services_discovery_sys_t ) ); - p_sd->p_sys = p_sys; - - services_discovery_SetLocalizedName( p_sd, _("UPnP devices") ); + if(!(p_sd->p_sys = p_sys)) + return VLC_ENOMEM; res = UpnpInit( 0, 0 ); if( res != UPNP_E_SUCCESS ) { msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) ); + free( p_sys ); return VLC_EGENERIC; } p_sys->serverList = new MediaServerList( p_sd ); - CallbackLock = new Lockable(); + vlc_mutex_init( &p_sys->callbackLock ); - res = UpnpRegisterClient( Callback, p_sys, &p_sys->clientHandle ); + res = UpnpRegisterClient( Callback, p_sd, &p_sys->clientHandle ); if( res != UPNP_E_SUCCESS ) { msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) ); @@ -311,7 +114,7 @@ static int Open( vlc_object_t *p_this ) res = UpnpSearchAsync( p_sys->clientHandle, 5, MEDIA_SERVER_DEVICE_TYPE, p_sd ); - + if( res != UPNP_E_SUCCESS ) { msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) ); @@ -328,25 +131,11 @@ static void Close( vlc_object_t *p_this ) UpnpFinish(); delete p_sd->p_sys->serverList; - delete CallbackLock; + vlc_mutex_destroy( &p_sd->p_sys->callbackLock ); free( p_sd->p_sys ); } -static void Run( services_discovery_t* p_sd ) -{ - - msg_Dbg( p_sd, "UPnP discovery started" ); - while( vlc_object_alive (p_sd) ) - { - msleep( 500 ); - } - - msg_Dbg( p_sd, "UPnP discovery stopped" ); - -} - - // XML utility functions: // Returns the value of a child element, or 0 on error @@ -406,10 +195,9 @@ IXML_Document* parseBrowseResult( IXML_Document* doc ) // Handles all UPnP events static int Callback( Upnp_EventType eventType, void* event, void* user_data ) { - Locker locker( CallbackLock ); - services_discovery_t *p_sd = ( services_discovery_t* ) user_data; services_discovery_sys_t* p_sys = p_sd->p_sys; + vlc_mutex_locker locker( &p_sys->callbackLock ); switch( eventType ) { @@ -469,11 +257,11 @@ static int Callback( Upnp_EventType eventType, void* event, void* user_data ) case UPNP_EVENT_SUBSCRIBE_COMPLETE: msg_Warn( p_sd, "subscription complete" ); break; - + case UPNP_DISCOVERY_SEARCH_TIMEOUT: msg_Warn( p_sd, "search timeout" ); break; - + default: msg_Dbg( p_sd, "%s:%d: DEBUG: UNHANDLED EVENT ( TYPE=%d )", @@ -494,14 +282,14 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, services_discovery_t* p_sd ) { if ( !doc ) - { - msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ ); + { + msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ ); return; } - + if ( !location ) { - msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ ); + msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ ); return; } @@ -526,7 +314,7 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, IXML_NodeList* deviceList = ixmlDocument_getElementsByTagName( doc, "device" ); - + if ( deviceList ) { for ( unsigned int i = 0; i < ixmlNodeList_length( deviceList ); i++ ) @@ -554,14 +342,14 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, __FILE__, __LINE__ ); continue; } - + if ( p_sd->p_sys->serverList->getServer( UDN ) != 0 ) continue; const char* friendlyName = - xml_getChildElementValue( deviceElement, + xml_getChildElementValue( deviceElement, "friendlyName" ); - + if ( !friendlyName ) { msg_Dbg( p_sd, "%s:%d: no friendlyName!", __FILE__, __LINE__ ); @@ -569,7 +357,7 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, } MediaServer* server = new MediaServer( UDN, friendlyName, p_sd ); - + if ( !p_sd->p_sys->serverList->addServer( server ) ) { @@ -670,8 +458,8 @@ MediaServer::MediaServer( const char* UDN, _UDN = UDN; _friendlyName = friendlyName; - _contents = 0; - _playlistNode = 0; + _contents = NULL; + _inputItem = NULL; } MediaServer::~MediaServer() @@ -749,7 +537,7 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, IXML_Document* action = 0; IXML_Document* response = 0; const char* url = getContentDirectoryControlURL(); - + if ( !url || strcmp( url, "" ) == 0 ) { msg_Dbg( _p_sd, "No subscription url set!" ); @@ -768,8 +556,8 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, res = UpnpAddToAction( &action, "Browse", serviceType, "ObjectID", ObjectID ); - - if ( res != UPNP_E_SUCCESS ) + + if ( res != UPNP_E_SUCCESS ) { msg_Dbg( _p_sd, "%s:%d: ERROR: %s", __FILE__, __LINE__, @@ -779,7 +567,7 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, res = UpnpAddToAction( &action, "Browse", serviceType, "BrowseFlag", BrowseFlag ); - + if ( res != UPNP_E_SUCCESS ) { msg_Dbg( _p_sd, @@ -790,7 +578,7 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, res = UpnpAddToAction( &action, "Browse", serviceType, "Filter", Filter ); - + if ( res != UPNP_E_SUCCESS ) { msg_Dbg( _p_sd, @@ -821,7 +609,7 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, res = UpnpAddToAction( &action, "Browse", serviceType, "SortCriteria", SortCriteria ); - + if ( res != UPNP_E_SUCCESS ) { msg_Dbg( _p_sd, @@ -836,7 +624,7 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, 0, action, &response ); - + if ( res != UPNP_E_SUCCESS ) { msg_Dbg( _p_sd, @@ -866,22 +654,12 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, void MediaServer::fetchContents() { Container* root = new Container( 0, "0", getFriendlyName() ); - playlist_t * p_playlist = pl_Hold( _p_sd ); _fetchContents( root ); - if ( _contents ) - { - PL_LOCK; - playlist_NodeEmpty( p_playlist, _playlistNode, true ); - PL_UNLOCK; - delete _contents; - } - _contents = root; - _contents->setPlaylistNode( _playlistNode ); + _contents->setInputItem( _inputItem ); - _buildPlaylist( _contents ); - pl_Release ( _p_sd ); + _buildPlaylist( _contents, NULL ); } bool MediaServer::_fetchContents( Container* parent ) @@ -906,7 +684,7 @@ bool MediaServer::_fetchContents( Container* parent ) IXML_Document* result = parseBrowseResult( response ); ixmlDocument_free( response ); - + if ( !result ) { msg_Dbg( _p_sd, @@ -917,7 +695,7 @@ bool MediaServer::_fetchContents( Container* parent ) IXML_NodeList* containerNodeList = ixmlDocument_getElementsByTagName( result, "container" ); - + if ( containerNodeList ) { for ( unsigned int i = 0; @@ -933,17 +711,17 @@ bool MediaServer::_fetchContents( Container* parent ) const char* childCountStr = ixmlElement_getAttribute( containerElement, "childCount" ); - + if ( !childCountStr ) continue; - + int childCount = atoi( childCountStr ); const char* title = xml_getChildElementValue( containerElement, "dc:title" ); - + if ( !title ) continue; - + const char* resource = xml_getChildElementValue( containerElement, "res" ); @@ -976,19 +754,19 @@ bool MediaServer::_fetchContents( Container* parent ) const char* objectID = ixmlElement_getAttribute( itemElement, "id" ); - + if ( !objectID ) continue; const char* title = xml_getChildElementValue( itemElement, "dc:title" ); - + if ( !title ) continue; const char* resource = xml_getChildElementValue( itemElement, "res" ); - + if ( !resource ) continue; @@ -1002,51 +780,50 @@ bool MediaServer::_fetchContents( Container* parent ) return true; } -void MediaServer::_buildPlaylist( Container* parent ) +void MediaServer::_buildPlaylist( Container* parent, input_item_node_t *p_input_node ) { - playlist_t *p_playlist = pl_Hold( _p_sd ); + bool send = p_input_node == NULL; + if( send ) + p_input_node = input_item_node_Create( parent->getInputItem() ); + for ( unsigned int i = 0; i < parent->getNumContainers(); i++ ) { Container* container = parent->getContainer( i ); - playlist_item_t* parentNode = parent->getPlaylistNode(); - char* title = strdup( container->getTitle() ); - PL_LOCK; - playlist_item_t* node = playlist_NodeCreate( p_playlist, - title, parentNode, 0, NULL ); - PL_UNLOCK; - free( title ); + input_item_t* p_input_item = input_item_New( _p_sd, "vlc://nop", parent->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++ ) { Item* item = parent->getItem( i ); - playlist_item_t* parentNode = parent->getPlaylistNode(); - input_item_t* p_input = input_item_New( _p_sd, + input_item_t* p_input_item = input_item_New( _p_sd, item->getResource(), item->getTitle() ); - int i_cat; - /* FIXME: playlist_AddInput() can fail */ - playlist_BothAddInput( p_playlist, p_input, parentNode, - PLAYLIST_APPEND, PLAYLIST_END, &i_cat, NULL, - pl_Unlocked ); - vlc_gc_decref( p_input ); - /* TODO: do this better by storing ids */ - playlist_item_t *p_node = - playlist_ItemGetById( p_playlist, i_cat, 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 ); } - pl_Release( _p_sd ); + + 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 ) @@ -1072,41 +849,20 @@ MediaServerList::~MediaServerList() bool MediaServerList::addServer( MediaServer* s ) { + input_item_t* p_input_item = NULL; if ( getServer( s->getUDN() ) != 0 ) return false; msg_Dbg( _p_sd, "Adding server '%s'", s->getFriendlyName() ); services_discovery_t* p_sd = _p_sd; - services_discovery_sys_t* p_sys = p_sd->p_sys; - playlist_item_t *p_node_cat; - playlist_item_t *p_node_one; - playlist_t* p_playlist = pl_Hold( _p_sd ); + p_input_item = input_item_New( p_sd, "vlc://nop", s->getFriendlyName() ); + s->setInputItem( p_input_item ); - for(int i = 0; i < p_playlist->i_sds; i++ ) - { - if(p_playlist->pp_sds[i]->p_sd == p_sd ) - { - p_node_cat = p_playlist->pp_sds[i]->p_cat; - p_node_one = p_playlist->pp_sds[i]->p_one; - break; - } - } - - assert (p_node_cat); - assert (p_node_one); + services_discovery_AddItem( p_sd, p_input_item, NULL ); _list.push_back( s ); - - char* name = strdup( s->getFriendlyName() ); - PL_LOCK; - playlist_item_t* node = - playlist_NodeCreate( p_playlist, name, p_node_cat, 0, NULL ); - PL_UNLOCK; - pl_Release( _p_sd ); - free( name ); - s->setPlaylistNode( node ); return true; } @@ -1174,7 +930,13 @@ Item::Item( Container* parent, const char* objectID, const char* title, const ch _title = title; _resource = resource; - _playlistNode = 0; + _inputItem = NULL; +} + +Item::~Item() +{ + if(_inputItem) + vlc_gc_decref( _inputItem ); } const char* Item::getObjectID() const @@ -1192,14 +954,21 @@ 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; } @@ -1214,7 +983,7 @@ Container::Container( Container* parent, _objectID = objectID; _title = title; - _playlistNode = 0; + _inputItem = NULL; } Container::~Container() @@ -1228,6 +997,9 @@ Container::~Container() { delete _items[i]; } + + if(_inputItem ) + vlc_gc_decref( _inputItem ); } void Container::addItem( Item* item ) @@ -1272,12 +1044,24 @@ Container* Container::getContainer( unsigned int i ) const return 0; } -void Container::setPlaylistNode( playlist_item_t* node ) +Container* Container::getParent() { - _playlistNode = node; + return _parent; +} + +void Container::setInputItem( input_item_t* p_input_item ) +{ + 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; }