Commit 0e45933d authored by Mirsal Ennaime's avatar Mirsal Ennaime

UPnP services discovery: Merge the SoC 2008 fixes, remove the Cookie class and...

UPnP services discovery: Merge the SoC 2008 fixes, remove the Cookie class and use the ordinary mechanisms instead
parent 120c15e5
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* *
* Authors: Rémi Denis-Courmont <rem # videolan.org> (original plugin) * Authors: Rémi Denis-Courmont <rem # videolan.org> (original plugin)
* Christian Henz <henz # c-lab.de> * Christian Henz <henz # c-lab.de>
* Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
* *
* UPnP Plugin using the Intel SDK (libupnp) instead of CyberLink * UPnP Plugin using the Intel SDK (libupnp) instead of CyberLink
* *
...@@ -46,26 +47,6 @@ ...@@ -46,26 +47,6 @@
#include <vlc_plugin.h> #include <vlc_plugin.h>
#include <vlc_playlist.h> #include <vlc_playlist.h>
/*****************************************************************************
* Module descriptor
*****************************************************************************/
static int Open( vlc_object_t* );
static void Close( vlc_object_t* );
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 )
vlc_module_end ()
/*****************************************************************************
* Local prototypes
*****************************************************************************/
// Constants // Constants
const char* MEDIA_SERVER_DEVICE_TYPE = "urn:schemas-upnp-org:device:MediaServer:1"; const char* MEDIA_SERVER_DEVICE_TYPE = "urn:schemas-upnp-org:device:MediaServer:1";
...@@ -78,24 +59,21 @@ class MediaServer; ...@@ -78,24 +59,21 @@ class MediaServer;
class MediaServerList; class MediaServerList;
class Item; class Item;
class Container; class Container;
class Lockable;
// Cookie that is passed to the callback // VLC handle
typedef struct struct services_discovery_sys_t
{ {
services_discovery_t* serviceDiscovery;
UpnpClient_Handle clientHandle; UpnpClient_Handle clientHandle;
MediaServerList* serverList; MediaServerList* serverList;
Lockable* lock; };
} Cookie;
// Class definitions... // Class definitions...
class Lockable class Lockable
{ {
public: public:
Lockable() Lockable()
{ {
vlc_mutex_init( &_mutex ); vlc_mutex_init( &_mutex );
...@@ -110,6 +88,7 @@ public: ...@@ -110,6 +88,7 @@ public:
void unlock() { vlc_mutex_unlock( &_mutex ); } void unlock() { vlc_mutex_unlock( &_mutex ); }
private: private:
vlc_mutex_t _mutex; vlc_mutex_t _mutex;
}; };
...@@ -137,9 +116,14 @@ class MediaServer ...@@ -137,9 +116,14 @@ class MediaServer
{ {
public: public:
static void parseDeviceDescription( IXML_Document* doc, const char* location, Cookie* cookie ); 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* UDN, const char* friendlyName, Cookie* cookie );
~MediaServer(); ~MediaServer();
const char* getUDN() const; const char* getUDN() const;
...@@ -162,9 +146,11 @@ private: ...@@ -162,9 +146,11 @@ private:
bool _fetchContents( Container* parent ); bool _fetchContents( Container* parent );
void _buildPlaylist( Container* container ); void _buildPlaylist( Container* container );
IXML_Document* _browseAction( const char*, const char*, const char*, const char*, const char*, const char* );
Cookie* _cookie; IXML_Document* _browseAction( const char*, const char*,
const char*, const char*, const char*, const char* );
services_discovery_t* _p_sd;
Container* _contents; Container* _contents;
playlist_item_t* _playlistNode; playlist_item_t* _playlistNode;
...@@ -184,7 +170,7 @@ class MediaServerList ...@@ -184,7 +170,7 @@ class MediaServerList
{ {
public: public:
MediaServerList( Cookie* cookie ); MediaServerList( services_discovery_t* p_sd );
~MediaServerList(); ~MediaServerList();
bool addServer( MediaServer* s ); bool addServer( MediaServer* s );
...@@ -195,7 +181,7 @@ public: ...@@ -195,7 +181,7 @@ public:
private: private:
Cookie* _cookie; services_discovery_t* _p_sd;
std::vector<MediaServer*> _list; std::vector<MediaServer*> _list;
}; };
...@@ -205,7 +191,10 @@ class Item ...@@ -205,7 +191,10 @@ class Item
{ {
public: public:
Item( Container* parent, const char* objectID, const char* title, const char* resource ); Item( Container* parent,
const char* objectID,
const char* title,
const char* resource );
const char* getObjectID() const; const char* getObjectID() const;
const char* getTitle() const; const char* getTitle() const;
...@@ -260,112 +249,109 @@ private: ...@@ -260,112 +249,109 @@ private:
}; };
// VLC handle
struct services_discovery_sys_t
{
playlist_t *p_playlist;
playlist_item_t *p_node_cat;
playlist_item_t *p_node_one;
Cookie cookie;
};
// VLC callback prototypes // VLC callback prototypes
static playlist_t *pl_Get( services_discovery_t *p_sd ) static int Open( vlc_object_t* );
{ static void Close( vlc_object_t* );
return p_sd->p_sys->p_playlist; static void Run( services_discovery_t *p_sd );
}
// 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 );
vlc_module_end();
// More prototypes... // More prototypes...
static int Callback( Upnp_EventType eventType, void* event, void* pCookie ); static Lockable* CallbackLock;
static int Callback( Upnp_EventType eventType, void* event, void* user_data );
const char* xml_getChildElementValue( IXML_Element* parent, const char* tagName ); const char* xml_getChildElementValue( IXML_Element* parent,
IXML_Document* parseBrowseResult( IXML_Document* doc ); const char* tagName );
IXML_Document* parseBrowseResult( IXML_Document* doc );
// VLC callbacks... // VLC callbacks...
static int Open( vlc_object_t *p_this ) static int Open( vlc_object_t *p_this )
{ {
int res;
services_discovery_t *p_sd = ( services_discovery_t* )p_this; services_discovery_t *p_sd = ( services_discovery_t* )p_this;
services_discovery_sys_t *p_sys = ( services_discovery_sys_t * ) services_discovery_sys_t *p_sys = ( services_discovery_sys_t * )
malloc( sizeof( services_discovery_sys_t ) ); calloc( 1, sizeof( services_discovery_sys_t ) );
playlist_t *p_playlist = pl_Hold( p_sd );
p_sd->p_sys = p_sys; p_sd->p_sys = p_sys;
p_sys->p_playlist = p_playlist;
Cookie *cookie = &p_sys->cookie;
/* Create our playlist node */
PL_LOCK;
playlist_NodesPairCreate( p_playlist, _("Devices"),
&p_sys->p_node_cat, &p_sys->p_node_one,
true );
PL_UNLOCK;
cookie->serviceDiscovery = p_sd; services_discovery_SetLocalizedName( p_sd, _("UPnP devices") );
cookie->lock = new Lockable();
cookie->serverList = new MediaServerList( cookie );
int res = UpnpInit( 0, 0 ); res = UpnpInit( 0, 0 );
if( res != UPNP_E_SUCCESS ) if( res != UPNP_E_SUCCESS )
{ {
msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) ); msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
goto shutDown; return VLC_EGENERIC;
} }
res = UpnpRegisterClient( Callback, cookie, &cookie->clientHandle ); p_sys->serverList = new MediaServerList( p_sd );
CallbackLock = new Lockable();
res = UpnpRegisterClient( Callback, p_sys, &p_sys->clientHandle );
if( res != UPNP_E_SUCCESS ) if( res != UPNP_E_SUCCESS )
{ {
msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) ); msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
goto shutDown; Close( (vlc_object_t*) p_sd );
return VLC_EGENERIC;
} }
res = UpnpSearchAsync( cookie->clientHandle, 5, MEDIA_SERVER_DEVICE_TYPE, res = UpnpSearchAsync( p_sys->clientHandle, 5,
cookie ); MEDIA_SERVER_DEVICE_TYPE, p_sd );
if( res != UPNP_E_SUCCESS ) if( res != UPNP_E_SUCCESS )
{ {
msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) ); msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
goto shutDown; Close( (vlc_object_t*) p_sd );
return VLC_EGENERIC;
} }
return VLC_SUCCESS; return VLC_SUCCESS;
shutDown:
Close( p_this );
return VLC_EGENERIC;
} }
static void Close( vlc_object_t *p_this ) static void Close( vlc_object_t *p_this )
{ {
services_discovery_t *p_sd = ( services_discovery_t* )p_this; services_discovery_t *p_sd = ( services_discovery_t* )p_this;
services_discovery_sys_t *p_sys = p_sd->p_sys;
playlist_t *p_playlist = p_sys->p_playlist;
UpnpFinish(); UpnpFinish();
delete p_sys->cookie.serverList; delete p_sd->p_sys->serverList;
delete p_sys->cookie.lock; delete CallbackLock;
PL_LOCK; free( p_sd->p_sys );
playlist_NodeDelete( p_playlist, p_sys->p_node_one, true, true );
playlist_NodeDelete( p_playlist, p_sys->p_node_cat, true, true );
PL_UNLOCK;
pl_Release( p_sd );
free( 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: // XML utility functions:
// Returns the value of a child element, or 0 on error // 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* parent,
const char* tagName )
{ {
if ( !parent ) return 0; if ( !parent ) return 0;
if ( !tagName ) return 0; if ( !tagName ) return 0;
...@@ -388,9 +374,13 @@ const char* xml_getChildElementValue( IXML_Element* parent, const char* tagName ...@@ -388,9 +374,13 @@ const char* xml_getChildElementValue( IXML_Element* parent, const char* tagName
// Extracts the result document from a SOAP response // Extracts the result document from a SOAP response
IXML_Document* parseBrowseResult( IXML_Document* doc ) IXML_Document* parseBrowseResult( IXML_Document* doc )
{ {
ixmlRelaxParser(1);
if ( !doc ) return 0; if ( !doc ) return 0;
IXML_NodeList* resultList = ixmlDocument_getElementsByTagName( doc, "Result" ); IXML_NodeList* resultList = ixmlDocument_getElementsByTagName( doc,
"Result" );
if ( !resultList ) return 0; if ( !resultList ) return 0;
IXML_Node* resultNode = ixmlNodeList_item( resultList, 0 ); IXML_Node* resultNode = ixmlNodeList_item( resultList, 0 );
...@@ -414,11 +404,12 @@ IXML_Document* parseBrowseResult( IXML_Document* doc ) ...@@ -414,11 +404,12 @@ IXML_Document* parseBrowseResult( IXML_Document* doc )
// Handles all UPnP events // Handles all UPnP events
static int Callback( Upnp_EventType eventType, void* event, void* pCookie ) static int Callback( Upnp_EventType eventType, void* event, void* user_data )
{ {
Cookie* cookie = ( Cookie* )pCookie; Locker locker( CallbackLock );
Locker locker( cookie->lock ); services_discovery_t *p_sd = ( services_discovery_t* ) user_data;
services_discovery_sys_t* p_sys = p_sd->p_sys;
switch( eventType ) { switch( eventType ) {
...@@ -433,11 +424,14 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie ) ...@@ -433,11 +424,14 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
res = UpnpDownloadXmlDoc( discovery->Location, &descriptionDoc ); res = UpnpDownloadXmlDoc( discovery->Location, &descriptionDoc );
if ( res != UPNP_E_SUCCESS ) if ( res != UPNP_E_SUCCESS )
{ {
msg_Dbg( cookie->serviceDiscovery, "%s:%d: Could not download device description!", __FILE__, __LINE__ ); msg_Dbg( p_sd,
"%s:%d: Could not download device description!",
__FILE__, __LINE__ );
return res; return res;
} }
MediaServer::parseDeviceDescription( descriptionDoc, discovery->Location, cookie ); MediaServer::parseDeviceDescription( descriptionDoc,
discovery->Location, p_sd );
ixmlDocument_free( descriptionDoc ); ixmlDocument_free( descriptionDoc );
} }
...@@ -447,7 +441,7 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie ) ...@@ -447,7 +441,7 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
{ {
struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event; struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
cookie->serverList->removeServer( discovery->DeviceId ); p_sys->serverList->removeServer( discovery->DeviceId );
} }
break; break;
...@@ -455,7 +449,7 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie ) ...@@ -455,7 +449,7 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
{ {
Upnp_Event* e = ( Upnp_Event* )event; Upnp_Event* e = ( Upnp_Event* )event;
MediaServer* server = cookie->serverList->getServerBySID( e->Sid ); MediaServer* server = p_sys->serverList->getServerBySID( e->Sid );
if ( server ) server->fetchContents(); if ( server ) server->fetchContents();
} }
break; break;
...@@ -467,21 +461,23 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie ) ...@@ -467,21 +461,23 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
Upnp_Event_Subscribe* s = ( Upnp_Event_Subscribe* )event; Upnp_Event_Subscribe* s = ( Upnp_Event_Subscribe* )event;
MediaServer* server = cookie->serverList->getServerBySID( s->Sid ); MediaServer* server = p_sys->serverList->getServerBySID( s->Sid );
if ( server ) server->subscribeToContentDirectory(); if ( server ) server->subscribeToContentDirectory();
} }
break; break;
case UPNP_EVENT_SUBSCRIBE_COMPLETE: case UPNP_EVENT_SUBSCRIBE_COMPLETE:
msg_Warn( cookie->serviceDiscovery, "subscription complete" ); msg_Warn( p_sd, "subscription complete" );
break; break;
case UPNP_DISCOVERY_SEARCH_TIMEOUT: case UPNP_DISCOVERY_SEARCH_TIMEOUT:
msg_Warn( cookie->serviceDiscovery, "search timeout" ); msg_Warn( p_sd, "search timeout" );
break; break;
default: 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__, eventType );
break; break;
} }
...@@ -493,18 +489,30 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie ) ...@@ -493,18 +489,30 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
// MediaServer... // MediaServer...
void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* location, Cookie* cookie ) void MediaServer::parseDeviceDescription( IXML_Document* doc,
const char* location,
services_discovery_t* p_sd )
{ {
if ( !doc ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: NULL", __FILE__, __LINE__ ); return; } if ( !doc )
if ( !location ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: NULL", __FILE__, __LINE__ ); return; } {
msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ );
return;
}
if ( !location )
{
msg_Dbg( p_sd, "%s:%d: NULL", __FILE__, __LINE__ );
return;
}
const char* baseURL = location; const char* baseURL = location;
// Try to extract baseURL // Try to extract baseURL
IXML_NodeList* urlList = ixmlDocument_getElementsByTagName( doc, "baseURL" ); IXML_NodeList* urlList = ixmlDocument_getElementsByTagName( doc, "baseURL" );
if ( urlList ) if ( !urlList )
{ {
if ( IXML_Node* urlNode = ixmlNodeList_item( urlList, 0 ) ) if ( IXML_Node* urlNode = ixmlNodeList_item( urlList, 0 ) )
{ {
IXML_Node* textNode = ixmlNode_getFirstChild( urlNode ); IXML_Node* textNode = ixmlNode_getFirstChild( urlNode );
...@@ -516,27 +524,54 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* locati ...@@ -516,27 +524,54 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* locati
// Get devices // Get devices
IXML_NodeList* deviceList = ixmlDocument_getElementsByTagName( doc, "device" ); IXML_NodeList* deviceList =
ixmlDocument_getElementsByTagName( doc, "device" );
if ( deviceList ) if ( deviceList )
{ {
for ( unsigned int i = 0; i < ixmlNodeList_length( deviceList ); i++ ) for ( unsigned int i = 0; i < ixmlNodeList_length( deviceList ); i++ )
{ {
IXML_Element* deviceElement = ( IXML_Element* )ixmlNodeList_item( deviceList, i ); IXML_Element* deviceElement =
( IXML_Element* ) ixmlNodeList_item( deviceList, i );
const char* deviceType = xml_getChildElementValue( deviceElement, "deviceType" ); const char* deviceType = xml_getChildElementValue( deviceElement,
if ( !deviceType ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: no deviceType!", __FILE__, __LINE__ ); continue; } "deviceType" );
if ( strcmp( MEDIA_SERVER_DEVICE_TYPE, deviceType ) != 0 ) continue; if ( !deviceType )
{
msg_Dbg( p_sd,
"%s:%d: no deviceType!",
__FILE__, __LINE__ );
continue;
}
if ( strcmp( MEDIA_SERVER_DEVICE_TYPE, deviceType ) != 0 )
continue;
const char* UDN = xml_getChildElementValue( deviceElement, "UDN" ); const char* UDN = xml_getChildElementValue( deviceElement, "UDN" );
if ( !UDN ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: no UDN!", __FILE__, __LINE__ ); continue; } if ( !UDN )
if ( cookie->serverList->getServer( UDN ) != 0 ) continue; {
msg_Dbg( p_sd, "%s:%d: no UDN!",
__FILE__, __LINE__ );
continue;
}
if ( p_sd->p_sys->serverList->getServer( UDN ) != 0 )
continue;
const char* friendlyName =
xml_getChildElementValue( deviceElement,
"friendlyName" );
if ( !friendlyName )
{
msg_Dbg( p_sd, "%s:%d: no friendlyName!", __FILE__, __LINE__ );
continue;
}
const char* friendlyName = xml_getChildElementValue( deviceElement, "friendlyName" ); MediaServer* server = new MediaServer( UDN, friendlyName, p_sd );
if ( !friendlyName ) { msg_Dbg( cookie->serviceDiscovery, "%s:%d: no friendlyName!", __FILE__, __LINE__ ); continue; }
MediaServer* server = new MediaServer( UDN, friendlyName, cookie ); if ( !p_sd->p_sys->serverList->addServer( server ) )
if ( !cookie->serverList->addServer( server ) ) { {
delete server; delete server;
server = 0; server = 0;
...@@ -544,36 +579,51 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* locati ...@@ -544,36 +579,51 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* locati
} }
// Check for ContentDirectory service... // Check for ContentDirectory service...
IXML_NodeList* serviceList =
IXML_NodeList* serviceList = ixmlElement_getElementsByTagName( deviceElement, "service" ); ixmlElement_getElementsByTagName( deviceElement,
"service" );
if ( serviceList ) if ( serviceList )
{ {
for ( unsigned int j = 0; j < ixmlNodeList_length( serviceList ); j++ ) for ( unsigned int j = 0;
j < ixmlNodeList_length( serviceList ); j++ )
{ {
IXML_Element* serviceElement = ( IXML_Element* )ixmlNodeList_item( serviceList, j ); IXML_Element* serviceElement =
( IXML_Element* ) ixmlNodeList_item( serviceList, j );
const char* serviceType = xml_getChildElementValue( serviceElement, "serviceType" ); const char* serviceType =
if ( !serviceType ) continue; xml_getChildElementValue( serviceElement,
if ( strcmp( CONTENT_DIRECTORY_SERVICE_TYPE, serviceType ) != 0 ) continue; "serviceType" );
if ( !serviceType )
continue;
const char* eventSubURL = xml_getChildElementValue( serviceElement, "eventSubURL" ); if ( strcmp( CONTENT_DIRECTORY_SERVICE_TYPE,
if ( !eventSubURL ) continue; serviceType ) != 0 )
continue;
const char* controlURL = xml_getChildElementValue( serviceElement, "controlURL" ); const char* eventSubURL =
if ( !controlURL ) continue; xml_getChildElementValue( serviceElement,
"eventSubURL" );
if ( !eventSubURL )
continue;
const char* controlURL =
xml_getChildElementValue( serviceElement,
"controlURL" );
if ( !controlURL )
continue;
// Try to subscribe to ContentDirectory service // Try to subscribe to ContentDirectory service
char* url = ( char* )malloc( strlen( baseURL ) + strlen( eventSubURL ) + 1 ); char* url = ( char* ) malloc( strlen( baseURL ) +
strlen( eventSubURL ) + 1 );
if ( url ) if ( url )
{ {
char* s1 = strdup( baseURL ); char* s1 = strdup( baseURL );
char* s2 = strdup( eventSubURL ); char* s2 = strdup( eventSubURL );
if ( UpnpResolveURL( s1, s2, url ) == UPNP_E_SUCCESS ) if ( UpnpResolveURL( s1, s2, url ) ==
UPNP_E_SUCCESS )
{ {
// msg_Dbg( cookie->serviceDiscovery, "CDS EVENT URL: %s", url );
server->setContentDirectoryEventURL( url ); server->setContentDirectoryEventURL( url );
server->subscribeToContentDirectory(); server->subscribeToContentDirectory();
} }
...@@ -585,16 +635,16 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* locati ...@@ -585,16 +635,16 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* locati
// Try to browse content directory... // Try to browse content directory...
url = ( char* )malloc( strlen( baseURL ) + strlen( controlURL ) + 1 ); url = ( char* ) malloc( strlen( baseURL ) +
strlen( controlURL ) + 1 );
if ( url ) if ( url )
{ {
char* s1 = strdup( baseURL ); char* s1 = strdup( baseURL );
char* s2 = strdup( controlURL ); char* s2 = strdup( controlURL );
if ( UpnpResolveURL( s1, s2, url ) == UPNP_E_SUCCESS ) if ( UpnpResolveURL( s1, s2, url ) ==
UPNP_E_SUCCESS )
{ {
// msg_Dbg( cookie->serviceDiscovery, "CDS CTRL URL: %s", url );
server->setContentDirectoryControlURL( url ); server->setContentDirectoryControlURL( url );
server->fetchContents(); server->fetchContents();
} }
...@@ -604,18 +654,18 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* locati ...@@ -604,18 +654,18 @@ void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* locati
free( url ); free( url );
} }
} }
ixmlNodeList_free( serviceList ); ixmlNodeList_free( serviceList );
} }
} }
ixmlNodeList_free( deviceList ); ixmlNodeList_free( deviceList );
} }
} }
MediaServer::MediaServer( const char* UDN, const char* friendlyName, Cookie* cookie ) MediaServer::MediaServer( const char* UDN,
const char* friendlyName,
services_discovery_t* p_sd )
{ {
_cookie = cookie; _p_sd = p_sd;
_UDN = UDN; _UDN = UDN;
_friendlyName = friendlyName; _friendlyName = friendlyName;
...@@ -626,14 +676,6 @@ MediaServer::MediaServer( const char* UDN, const char* friendlyName, Cookie* coo ...@@ -626,14 +676,6 @@ MediaServer::MediaServer( const char* UDN, const char* friendlyName, Cookie* coo
MediaServer::~MediaServer() MediaServer::~MediaServer()
{ {
if ( _contents )
{
vlc_object_lock( _cookie->serviceDiscovery->p_sys->p_playlist );
playlist_NodeDelete( pl_Get( _cookie->serviceDiscovery ) ,
_playlistNode, true, true );
vlc_object_unlock( _cookie->serviceDiscovery->p_sys->p_playlist );
}
delete _contents; delete _contents;
} }
...@@ -675,14 +717,14 @@ void MediaServer::subscribeToContentDirectory() ...@@ -675,14 +717,14 @@ void MediaServer::subscribeToContentDirectory()
const char* url = getContentDirectoryEventURL(); const char* url = getContentDirectoryEventURL();
if ( !url || strcmp( url, "" ) == 0 ) if ( !url || strcmp( url, "" ) == 0 )
{ {
msg_Dbg( _cookie->serviceDiscovery, "No subscription url set!" ); msg_Dbg( _p_sd, "No subscription url set!" );
return; return;
} }
int timeOut = 1810; int timeOut = 1810;
Upnp_SID sid; Upnp_SID sid;
int res = UpnpSubscribe( _cookie->clientHandle, url, &timeOut, sid ); int res = UpnpSubscribe( _p_sd->p_sys->clientHandle, url, &timeOut, sid );
if ( res == UPNP_E_SUCCESS ) if ( res == UPNP_E_SUCCESS )
{ {
...@@ -691,18 +733,28 @@ void MediaServer::subscribeToContentDirectory() ...@@ -691,18 +733,28 @@ void MediaServer::subscribeToContentDirectory()
} }
else 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( res ) );
} }
} }
IXML_Document* MediaServer::_browseAction( const char* pObjectID, const char* pBrowseFlag, const char* pFilter, IXML_Document* MediaServer::_browseAction( const char* pObjectID,
const char* pStartingIndex, const char* pRequestedCount, const char* pSortCriteria ) const char* pBrowseFlag,
const char* pFilter,
const char* pStartingIndex,
const char* pRequestedCount,
const char* pSortCriteria )
{ {
IXML_Document* action = 0; IXML_Document* action = 0;
IXML_Document* response = 0; IXML_Document* response = 0;
const char* url = getContentDirectoryControlURL(); const char* url = getContentDirectoryControlURL();
if ( !url || strcmp( url, "" ) == 0 ) { msg_Dbg( _cookie->serviceDiscovery, "No subscription url set!" ); return 0; }
if ( !url || strcmp( url, "" ) == 0 )
{
msg_Dbg( _p_sd, "No subscription url set!" );
return 0;
}
char* ObjectID = strdup( pObjectID ); char* ObjectID = strdup( pObjectID );
char* BrowseFlag = strdup( pBrowseFlag ); char* BrowseFlag = strdup( pBrowseFlag );
...@@ -710,38 +762,88 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, const char* pB ...@@ -710,38 +762,88 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, const char* pB
char* StartingIndex = strdup( pStartingIndex ); char* StartingIndex = strdup( pStartingIndex );
char* RequestedCount = strdup( pRequestedCount ); char* RequestedCount = strdup( pRequestedCount );
char* SortCriteria = strdup( pSortCriteria ); char* SortCriteria = strdup( pSortCriteria );
char* serviceType = strdup( CONTENT_DIRECTORY_SERVICE_TYPE ); char* serviceType = strdup( CONTENT_DIRECTORY_SERVICE_TYPE );
int res; int res;
res = UpnpAddToAction( &action, "Browse", serviceType, "ObjectID", ObjectID ); res = UpnpAddToAction( &action, "Browse",
if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } serviceType, "ObjectID", ObjectID );
res = UpnpAddToAction( &action, "Browse", serviceType, "BrowseFlag", BrowseFlag ); if ( res != UPNP_E_SUCCESS )
if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } {
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( res ) );
goto browseActionCleanup;
}
res = UpnpAddToAction( &action, "Browse", serviceType, "Filter", Filter ); res = UpnpAddToAction( &action, "Browse",
if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } serviceType, "BrowseFlag", BrowseFlag );
res = UpnpAddToAction( &action, "Browse", serviceType, "StartingIndex", StartingIndex ); if ( res != UPNP_E_SUCCESS )
if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } {
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( res ) );
goto browseActionCleanup;
}
res = UpnpAddToAction( &action, "Browse", serviceType, "RequestedCount", RequestedCount ); res = UpnpAddToAction( &action, "Browse",
if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } serviceType, "Filter", Filter );
res = UpnpAddToAction( &action, "Browse", serviceType, "SortCriteria", SortCriteria ); if ( res != UPNP_E_SUCCESS )
if ( res != UPNP_E_SUCCESS ) { /* msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); */ goto browseActionCleanup; } {
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( res ) );
goto browseActionCleanup;
}
res = UpnpSendAction( _cookie->clientHandle, res = UpnpAddToAction( &action, "Browse",
serviceType, "StartingIndex", StartingIndex );
if ( res != UPNP_E_SUCCESS )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( res ) );
goto browseActionCleanup;
}
res = UpnpAddToAction( &action, "Browse",
serviceType, "RequestedCount", RequestedCount );
if ( res != UPNP_E_SUCCESS )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( res ) ); goto browseActionCleanup; }
res = UpnpAddToAction( &action, "Browse",
serviceType, "SortCriteria", SortCriteria );
if ( res != UPNP_E_SUCCESS )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( res ) );
goto browseActionCleanup;
}
res = UpnpSendAction( _p_sd->p_sys->clientHandle,
url, url,
CONTENT_DIRECTORY_SERVICE_TYPE, CONTENT_DIRECTORY_SERVICE_TYPE,
0, 0,
action, action,
&response ); &response );
if ( res != UPNP_E_SUCCESS ) if ( res != UPNP_E_SUCCESS )
{ {
msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR: %s", __FILE__, __LINE__, UpnpGetErrorMessage( res ) ); msg_Dbg( _p_sd,
"%s:%d: ERROR: %s when trying the send() action with URL: %s",
__FILE__, __LINE__,
UpnpGetErrorMessage( res ), url );
ixmlDocument_free( response ); ixmlDocument_free( response );
response = 0; response = 0;
} }
...@@ -764,7 +866,7 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, const char* pB ...@@ -764,7 +866,7 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, const char* pB
void MediaServer::fetchContents() void MediaServer::fetchContents()
{ {
Container* root = new Container( 0, "0", getFriendlyName() ); Container* root = new Container( 0, "0", getFriendlyName() );
playlist_t * p_playlist = pl_Get( _cookie->serviceDiscovery ); playlist_t * p_playlist = pl_Hold( _p_sd );
_fetchContents( root ); _fetchContents( root );
if ( _contents ) if ( _contents )
...@@ -779,93 +881,140 @@ void MediaServer::fetchContents() ...@@ -779,93 +881,140 @@ void MediaServer::fetchContents()
_contents->setPlaylistNode( _playlistNode ); _contents->setPlaylistNode( _playlistNode );
_buildPlaylist( _contents ); _buildPlaylist( _contents );
pl_Release ( _p_sd );
} }
bool MediaServer::_fetchContents( Container* parent ) bool MediaServer::_fetchContents( Container* parent )
{ {
if (!parent) { msg_Dbg( _cookie->serviceDiscovery, "%s:%d: parent==NULL", __FILE__, __LINE__ ); return false; } if (!parent)
{
msg_Dbg( _p_sd,
"%s:%d: parent==NULL", __FILE__, __LINE__ );
return false;
}
IXML_Document* response = _browseAction( parent->getObjectID(), "BrowseDirectChildren", "*", "0", "0", "" ); IXML_Document* response = _browseAction( parent->getObjectID(),
if ( !response ) { msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR!", __FILE__, __LINE__ ); return false; } "BrowseDirectChildren",
"*", "0", "0", "" );
if ( !response )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR! No response from browse() action",
__FILE__, __LINE__ );
return false;
}
IXML_Document* result = parseBrowseResult( response ); IXML_Document* result = parseBrowseResult( response );
ixmlDocument_free( response ); ixmlDocument_free( response );
if ( !result ) { msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR!", __FILE__, __LINE__ ); return false; }
IXML_NodeList* containerNodeList = ixmlDocument_getElementsByTagName( result, "container" ); if ( !result )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR! browse() response parsing failed",
__FILE__, __LINE__ );
return false;
}
IXML_NodeList* containerNodeList =
ixmlDocument_getElementsByTagName( result, "container" );
if ( containerNodeList ) if ( containerNodeList )
{ {
for ( unsigned int i = 0; i < ixmlNodeList_length( containerNodeList ); i++ ) for ( unsigned int i = 0;
i < ixmlNodeList_length( containerNodeList ); i++ )
{ {
IXML_Element* containerElement = ( IXML_Element* )ixmlNodeList_item( 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" ); const char* childCountStr =
if ( !objectID ) continue; ixmlElement_getAttribute( containerElement, "childCount" );
if ( !childCountStr )
continue;
const char* childCountStr = ixmlElement_getAttribute( containerElement, "childCount" );
if ( !childCountStr ) continue;
int childCount = atoi( childCountStr ); int childCount = atoi( childCountStr );
const char* title = xml_getChildElementValue( containerElement,
"dc:title" );
const char* title = xml_getChildElementValue( containerElement, "dc:title" ); if ( !title )
if ( !title ) continue; continue;
const char* resource = xml_getChildElementValue( containerElement, "res" ); const char* resource = xml_getChildElementValue( containerElement,
"res" );
if ( resource && childCount < 1 ) if ( resource && childCount < 1 )
{ {
Item* item = new Item( parent, objectID, title, resource ); Item* item = new Item( parent, objectID, title, resource );
parent->addItem( item ); parent->addItem( item );
} }
else else
{ {
Container* container = new Container( parent, objectID, title ); Container* container = new Container( parent, objectID, title );
parent->addContainer( container ); parent->addContainer( container );
if ( childCount > 0 ) _fetchContents( container ); if ( childCount > 0 )
_fetchContents( container );
} }
} }
ixmlNodeList_free( containerNodeList ); ixmlNodeList_free( containerNodeList );
} }
IXML_NodeList* itemNodeList = ixmlDocument_getElementsByTagName( result, "item" ); IXML_NodeList* itemNodeList = ixmlDocument_getElementsByTagName( result,
"item" );
if ( itemNodeList ) if ( itemNodeList )
{ {
for ( unsigned int i = 0; i < ixmlNodeList_length( itemNodeList ); i++ ) 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* title =
xml_getChildElementValue( itemElement, "dc:title" );
const char* objectID = ixmlElement_getAttribute( itemElement, "id" ); if ( !title )
if ( !objectID ) continue; continue;
const char* title = xml_getChildElementValue( itemElement, "dc:title" ); const char* resource =
if ( !title ) continue; xml_getChildElementValue( itemElement, "res" );
const char* resource = xml_getChildElementValue( itemElement, "res" ); if ( !resource )
if ( !resource ) continue; continue;
Item* item = new Item( parent, objectID, title, resource ); Item* item = new Item( parent, objectID, title, resource );
parent->addItem( item ); parent->addItem( item );
} }
ixmlNodeList_free( itemNodeList ); ixmlNodeList_free( itemNodeList );
} }
ixmlDocument_free( result ); ixmlDocument_free( result );
return true; return true;
} }
void MediaServer::_buildPlaylist( Container* parent ) void MediaServer::_buildPlaylist( Container* parent )
{ {
playlist_t *p_playlist = pl_Get( _cookie->serviceDiscovery ); playlist_t *p_playlist = pl_Hold( _p_sd );
for ( unsigned int i = 0; i < parent->getNumContainers(); i++ ) for ( unsigned int i = 0; i < parent->getNumContainers(); i++ )
{ {
Container* container = parent->getContainer( i ); Container* container = parent->getContainer( i );
playlist_item_t* parentNode = parent->getPlaylistNode(); playlist_item_t* parentNode = parent->getPlaylistNode();
char* title = strdup( container->getTitle() ); char* title = strdup( container->getTitle() );
playlist_item_t* node = playlist_NodeCreate( p_playlist, title, parentNode, 0, NULL ); PL_LOCK;
playlist_item_t* node = playlist_NodeCreate( p_playlist,
title, parentNode, 0, NULL );
PL_UNLOCK;
free( title ); free( title );
container->setPlaylistNode( node ); container->setPlaylistNode( node );
...@@ -877,7 +1026,7 @@ void MediaServer::_buildPlaylist( Container* parent ) ...@@ -877,7 +1026,7 @@ void MediaServer::_buildPlaylist( Container* parent )
Item* item = parent->getItem( i ); Item* item = parent->getItem( i );
playlist_item_t* parentNode = parent->getPlaylistNode(); playlist_item_t* parentNode = parent->getPlaylistNode();
input_item_t* p_input = input_item_New( _cookie->serviceDiscovery, input_item_t* p_input = input_item_New( _p_sd,
item->getResource(), item->getResource(),
item->getTitle() ); item->getTitle() );
int i_cat; int i_cat;
...@@ -887,10 +1036,12 @@ void MediaServer::_buildPlaylist( Container* parent ) ...@@ -887,10 +1036,12 @@ void MediaServer::_buildPlaylist( Container* parent )
pl_Unlocked ); pl_Unlocked );
vlc_gc_decref( p_input ); vlc_gc_decref( p_input );
/* TODO: do this better by storing ids */ /* TODO: do this better by storing ids */
playlist_item_t *p_node = playlist_ItemGetById( p_playlist, i_cat, false ); playlist_item_t *p_node =
playlist_ItemGetById( p_playlist, i_cat, false );
assert( p_node ); assert( p_node );
item->setPlaylistNode( p_node ); item->setPlaylistNode( p_node );
} }
pl_Release( _p_sd );
} }
void MediaServer::setPlaylistNode( playlist_item_t* playlistNode ) void MediaServer::setPlaylistNode( playlist_item_t* playlistNode )
...@@ -906,9 +1057,9 @@ bool MediaServer::compareSID( const char* sid ) ...@@ -906,9 +1057,9 @@ bool MediaServer::compareSID( const char* sid )
// MediaServerList... // MediaServerList...
MediaServerList::MediaServerList( Cookie* cookie ) MediaServerList::MediaServerList( services_discovery_t* p_sd )
{ {
_cookie = cookie; _p_sd = p_sd;
} }
MediaServerList::~MediaServerList() MediaServerList::~MediaServerList()
...@@ -923,17 +1074,37 @@ bool MediaServerList::addServer( MediaServer* s ) ...@@ -923,17 +1074,37 @@ bool MediaServerList::addServer( MediaServer* s )
{ {
if ( getServer( s->getUDN() ) != 0 ) return false; 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() );
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 );
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);
_list.push_back( s ); _list.push_back( s );
char* name = strdup( s->getFriendlyName() ); char* name = strdup( s->getFriendlyName() );
vlc_object_lock( _cookie->serviceDiscovery->p_sys->p_playlist ); PL_LOCK;
playlist_item_t* node = playlist_NodeCreate( playlist_item_t* node =
pl_Get( _cookie->serviceDiscovery ), name, playlist_NodeCreate( p_playlist, name, p_node_cat, 0, NULL );
_cookie->serviceDiscovery->p_sys->p_node_cat, PL_UNLOCK;
0, NULL ); pl_Release( _p_sd );
vlc_object_unlock( _cookie->serviceDiscovery->p_sys->p_playlist );
free( name ); free( name );
s->setPlaylistNode( node ); s->setPlaylistNode( node );
...@@ -977,7 +1148,8 @@ void MediaServerList::removeServer( const char* UDN ) ...@@ -977,7 +1148,8 @@ void MediaServerList::removeServer( const char* UDN )
MediaServer* server = getServer( UDN ); MediaServer* server = getServer( UDN );
if ( !server ) return; if ( !server ) return;
msg_Dbg( _cookie->serviceDiscovery, "Removing server '%s'", server->getFriendlyName() ); msg_Dbg( _p_sd,
"Removing server '%s'", server->getFriendlyName() );
std::vector<MediaServer*>::iterator it; std::vector<MediaServer*>::iterator it;
for ( it = _list.begin(); it != _list.end(); it++ ) for ( it = _list.begin(); it != _list.end(); it++ )
...@@ -1033,7 +1205,9 @@ playlist_item_t* Item::getPlaylistNode() const ...@@ -1033,7 +1205,9 @@ playlist_item_t* Item::getPlaylistNode() const
// Container... // Container...
Container::Container( Container* parent, const char* objectID, const char* title ) Container::Container( Container* parent,
const char* objectID,
const char* title )
{ {
_parent = parent; _parent = parent;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment