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 @@
*
* Authors: Rémi Denis-Courmont <rem # videolan.org> (original plugin)
* 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
*
......@@ -46,26 +47,6 @@
#include <vlc_plugin.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
const char* MEDIA_SERVER_DEVICE_TYPE = "urn:schemas-upnp-org:device:MediaServer:1";
......@@ -78,24 +59,21 @@ class MediaServer;
class MediaServerList;
class Item;
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;
MediaServerList* serverList;
Lockable* lock;
} Cookie;
};
// Class definitions...
class Lockable
{
public:
Lockable()
{
vlc_mutex_init( &_mutex );
......@@ -110,6 +88,7 @@ public:
void unlock() { vlc_mutex_unlock( &_mutex ); }
private:
vlc_mutex_t _mutex;
};
......@@ -119,13 +98,13 @@ class Locker
public:
Locker( Lockable* l )
{
_lockable = l;
_lockable->lock();
_lockable = l;
_lockable->lock();
}
~Locker()
{
_lockable->unlock();
_lockable->unlock();
}
private:
......@@ -137,9 +116,14 @@ class MediaServer
{
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, Cookie* cookie );
MediaServer( const char* UDN,
const char* friendlyName,
services_discovery_t* p_sd );
~MediaServer();
const char* getUDN() const;
......@@ -162,9 +146,11 @@ private:
bool _fetchContents( Container* parent );
void _buildPlaylist( Container* container );
IXML_Document* _browseAction( const char*, const char*, const char*, const char*, const char*, const char* );
IXML_Document* _browseAction( const char*, const char*,
const char*, const char*, const char*, const char* );
Cookie* _cookie;
services_discovery_t* _p_sd;
Container* _contents;
playlist_item_t* _playlistNode;
......@@ -184,7 +170,7 @@ class MediaServerList
{
public:
MediaServerList( Cookie* cookie );
MediaServerList( services_discovery_t* p_sd );
~MediaServerList();
bool addServer( MediaServer* s );
......@@ -195,7 +181,7 @@ public:
private:
Cookie* _cookie;
services_discovery_t* _p_sd;
std::vector<MediaServer*> _list;
};
......@@ -205,7 +191,10 @@ class Item
{
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* getTitle() const;
......@@ -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
static playlist_t *pl_Get( services_discovery_t *p_sd )
{
return p_sd->p_sys->p_playlist;
}
static int Open( vlc_object_t* );
static void Close( vlc_object_t* );
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...
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 );
IXML_Document* parseBrowseResult( IXML_Document* doc );
const char* xml_getChildElementValue( IXML_Element* parent,
const char* tagName );
IXML_Document* parseBrowseResult( IXML_Document* doc );
// VLC callbacks...
static int Open( vlc_object_t *p_this )
{
int 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 ) );
playlist_t *p_playlist = pl_Hold( p_sd );
calloc( 1, sizeof( services_discovery_sys_t ) );
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;
cookie->lock = new Lockable();
cookie->serverList = new MediaServerList( cookie );
services_discovery_SetLocalizedName( p_sd, _("UPnP devices") );
int res = UpnpInit( 0, 0 );
res = UpnpInit( 0, 0 );
if( res != UPNP_E_SUCCESS )
{
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 )
{
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,
cookie );
res = UpnpSearchAsync( p_sys->clientHandle, 5,
MEDIA_SERVER_DEVICE_TYPE, p_sd );
if( res != UPNP_E_SUCCESS )
{
msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
goto shutDown;
Close( (vlc_object_t*) p_sd );
return VLC_EGENERIC;
}
return VLC_SUCCESS;
shutDown:
Close( p_this );
return VLC_EGENERIC;
}
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_t *p_playlist = p_sys->p_playlist;
UpnpFinish();
delete p_sys->cookie.serverList;
delete p_sys->cookie.lock;
delete p_sd->p_sys->serverList;
delete CallbackLock;
PL_LOCK;
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 );
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
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 ( !tagName ) return 0;
......@@ -388,9 +374,13 @@ const char* xml_getChildElementValue( IXML_Element* parent, const char* tagName
// Extracts the result document from a SOAP response
IXML_Document* parseBrowseResult( IXML_Document* doc )
{
ixmlRelaxParser(1);
if ( !doc ) return 0;
IXML_NodeList* resultList = ixmlDocument_getElementsByTagName( doc, "Result" );
IXML_NodeList* resultList = ixmlDocument_getElementsByTagName( doc,
"Result" );
if ( !resultList ) return 0;
IXML_Node* resultNode = ixmlNodeList_item( resultList, 0 );
......@@ -414,11 +404,12 @@ IXML_Document* parseBrowseResult( IXML_Document* doc )
// 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 ) {
......@@ -433,11 +424,14 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
res = UpnpDownloadXmlDoc( discovery->Location, &descriptionDoc );
if ( 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 res;
}
MediaServer::parseDeviceDescription( descriptionDoc, discovery->Location, cookie );
MediaServer::parseDeviceDescription( descriptionDoc,
discovery->Location, p_sd );
ixmlDocument_free( descriptionDoc );
}
......@@ -447,7 +441,7 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
{
struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
cookie->serverList->removeServer( discovery->DeviceId );
p_sys->serverList->removeServer( discovery->DeviceId );
}
break;
......@@ -455,7 +449,7 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
{
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();
}
break;
......@@ -467,21 +461,23 @@ static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
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();
}
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__, eventType );
break;
}
......@@ -493,129 +489,183 @@ 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* doc,
const char* 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; }
if ( !doc )
{
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;
// Try to extract baseURL
IXML_NodeList* urlList = ixmlDocument_getElementsByTagName( doc, "baseURL" );
if ( urlList )
{
if ( IXML_Node* urlNode = ixmlNodeList_item( urlList, 0 ) )
if ( !urlList )
{
IXML_Node* textNode = ixmlNode_getFirstChild( urlNode );
if ( textNode ) baseURL = ixmlNode_getNodeValue( textNode );
}
ixmlNodeList_free( urlList );
if ( IXML_Node* urlNode = ixmlNodeList_item( urlList, 0 ) )
{
IXML_Node* textNode = ixmlNode_getFirstChild( urlNode );
if ( textNode ) baseURL = ixmlNode_getNodeValue( textNode );
}
ixmlNodeList_free( urlList );
}
// Get devices
IXML_NodeList* deviceList = ixmlDocument_getElementsByTagName( doc, "device" );
IXML_NodeList* deviceList =
ixmlDocument_getElementsByTagName( doc, "device" );
if ( deviceList )
{
for ( unsigned int i = 0; i < ixmlNodeList_length( deviceList ); i++ )
{
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;
}
// Check for ContentDirectory service...
IXML_NodeList* serviceList = ixmlElement_getElementsByTagName( deviceElement, "service" );
if ( serviceList )
{
for ( unsigned int j = 0; j < ixmlNodeList_length( serviceList ); j++ )
for ( unsigned int i = 0; i < ixmlNodeList_length( deviceList ); i++ )
{
IXML_Element* serviceElement = ( IXML_Element* )ixmlNodeList_item( serviceList, j );
const char* serviceType = xml_getChildElementValue( serviceElement, "serviceType" );
if ( !serviceType ) continue;
if ( strcmp( CONTENT_DIRECTORY_SERVICE_TYPE, serviceType ) != 0 ) continue;
const char* eventSubURL = xml_getChildElementValue( serviceElement, "eventSubURL" );
if ( !eventSubURL ) continue;
const char* controlURL = xml_getChildElementValue( serviceElement, "controlURL" );
if ( !controlURL ) continue;
IXML_Element* deviceElement =
( IXML_Element* ) ixmlNodeList_item( deviceList, i );
// Try to subscribe to ContentDirectory service
char* url = ( char* )malloc( strlen( baseURL ) + strlen( eventSubURL ) + 1 );
if ( url )
const char* deviceType = xml_getChildElementValue( deviceElement,
"deviceType" );
if ( !deviceType )
{
char* s1 = strdup( baseURL );
char* s2 = strdup( eventSubURL );
if ( UpnpResolveURL( s1, s2, url ) == UPNP_E_SUCCESS )
{
// msg_Dbg( cookie->serviceDiscovery, "CDS EVENT URL: %s", url );
server->setContentDirectoryEventURL( url );
server->subscribeToContentDirectory();
}
free( s1 );
free( s2 );
free( url );
msg_Dbg( p_sd,
"%s:%d: no deviceType!",
__FILE__, __LINE__ );
continue;
}
// Try to browse content directory...
if ( strcmp( MEDIA_SERVER_DEVICE_TYPE, deviceType ) != 0 )
continue;
url = ( char* )malloc( strlen( baseURL ) + strlen( controlURL ) + 1 );
if ( url )
const char* UDN = xml_getChildElementValue( deviceElement, "UDN" );
if ( !UDN )
{
char* s1 = strdup( baseURL );
char* s2 = strdup( controlURL );
if ( UpnpResolveURL( s1, s2, url ) == UPNP_E_SUCCESS )
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( cookie->serviceDiscovery, "CDS CTRL URL: %s", url );
server->setContentDirectoryControlURL( url );
server->fetchContents();
msg_Dbg( p_sd, "%s:%d: no friendlyName!", __FILE__, __LINE__ );
continue;
}
free( s1 );
free( s2 );
free( url );
}
}
MediaServer* server = new MediaServer( UDN, friendlyName, p_sd );
if ( !p_sd->p_sys->serverList->addServer( server ) )
{
ixmlNodeList_free( serviceList );
}
}
delete server;
server = 0;
continue;
}
ixmlNodeList_free( deviceList );
// Check for ContentDirectory service...
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 );
const char* serviceType =
xml_getChildElementValue( serviceElement,
"serviceType" );
if ( !serviceType )
continue;
if ( strcmp( CONTENT_DIRECTORY_SERVICE_TYPE,
serviceType ) != 0 )
continue;
const char* eventSubURL =
xml_getChildElementValue( serviceElement,
"eventSubURL" );
if ( !eventSubURL )
continue;
const char* controlURL =
xml_getChildElementValue( serviceElement,
"controlURL" );
if ( !controlURL )
continue;
// Try to subscribe to ContentDirectory service
char* url = ( char* ) malloc( strlen( baseURL ) +
strlen( eventSubURL ) + 1 );
if ( url )
{
char* s1 = strdup( baseURL );
char* s2 = strdup( eventSubURL );
if ( UpnpResolveURL( s1, s2, url ) ==
UPNP_E_SUCCESS )
{
server->setContentDirectoryEventURL( url );
server->subscribeToContentDirectory();
}
free( s1 );
free( s2 );
free( url );
}
// Try to browse content directory...
url = ( char* ) malloc( strlen( baseURL ) +
strlen( controlURL ) + 1 );
if ( url )
{
char* s1 = strdup( baseURL );
char* s2 = strdup( controlURL );
if ( UpnpResolveURL( s1, s2, url ) ==
UPNP_E_SUCCESS )
{
server->setContentDirectoryControlURL( url );
server->fetchContents();
}
free( s1 );
free( s2 );
free( url );
}
}
ixmlNodeList_free( serviceList );
}
}
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;
_friendlyName = friendlyName;
......@@ -626,14 +676,6 @@ MediaServer::MediaServer( const char* UDN, const char* friendlyName, Cookie* coo
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;
}
......@@ -675,34 +717,44 @@ void MediaServer::subscribeToContentDirectory()
const char* url = getContentDirectoryEventURL();
if ( !url || strcmp( url, "" ) == 0 )
{
msg_Dbg( _cookie->serviceDiscovery, "No subscription url set!" );
return;
msg_Dbg( _p_sd, "No subscription url set!" );
return;
}
int timeOut = 1810;
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 )
{
_subscriptionTimeOut = timeOut;
memcpy( _subscriptionID, sid, sizeof( Upnp_SID ) );
_subscriptionTimeOut = 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( 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* pObjectID,
const char* pBrowseFlag,
const char* pFilter,
const char* pStartingIndex,
const char* pRequestedCount,
const char* pSortCriteria )
{
IXML_Document* action = 0;
IXML_Document* response = 0;
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* BrowseFlag = strdup( pBrowseFlag );
......@@ -710,40 +762,90 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, const char* pB
char* StartingIndex = strdup( pStartingIndex );
char* RequestedCount = strdup( pRequestedCount );
char* SortCriteria = strdup( pSortCriteria );
char* serviceType = strdup( CONTENT_DIRECTORY_SERVICE_TYPE );
int res;
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; }
res = UpnpAddToAction( &action, "Browse",
serviceType, "ObjectID", ObjectID );
if ( res != UPNP_E_SUCCESS )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( res ) );
goto browseActionCleanup;
}
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; }
res = UpnpAddToAction( &action, "Browse",
serviceType, "BrowseFlag", BrowseFlag );
if ( res != UPNP_E_SUCCESS )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( 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; }
res = UpnpAddToAction( &action, "Browse",
serviceType, "Filter", Filter );
if ( res != UPNP_E_SUCCESS )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( res ) );
goto browseActionCleanup;
}
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; }
res = UpnpAddToAction( &action, "Browse",
serviceType, "StartingIndex", StartingIndex );
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; }
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 );
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 ( res != UPNP_E_SUCCESS )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR: %s", __FILE__, __LINE__,
UpnpGetErrorMessage( res ) ); goto browseActionCleanup; }
res = UpnpSendAction( _cookie->clientHandle,
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,
CONTENT_DIRECTORY_SERVICE_TYPE,
0,
action,
&response );
if ( 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( res ), url );
ixmlDocument_free( response );
response = 0;
}
browseActionCleanup:
......@@ -764,7 +866,7 @@ IXML_Document* MediaServer::_browseAction( const char* pObjectID, const char* pB
void MediaServer::fetchContents()
{
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 );
if ( _contents )
......@@ -779,93 +881,140 @@ void MediaServer::fetchContents()
_contents->setPlaylistNode( _playlistNode );
_buildPlaylist( _contents );
pl_Release ( _p_sd );
}
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", "" );
if ( !response ) { msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR!", __FILE__, __LINE__ ); return false; }
IXML_Document* response = _browseAction( parent->getObjectID(),
"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 );
ixmlDocument_free( response );
if ( !result ) { msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR!", __FILE__, __LINE__ ); return false; }
if ( !result )
{
msg_Dbg( _p_sd,
"%s:%d: ERROR! browse() response parsing failed",
__FILE__, __LINE__ );
return false;
}
IXML_NodeList* containerNodeList = ixmlDocument_getElementsByTagName( result, "container" );
IXML_NodeList* containerNodeList =
ixmlDocument_getElementsByTagName( result, "container" );
if ( containerNodeList )
{
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* 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" );
if ( resource && childCount < 1 )
{
Item* item = new Item( parent, objectID, title, resource );
parent->addItem( item );
}
else
for ( unsigned int i = 0;
i < ixmlNodeList_length( containerNodeList ); i++ )
{
Container* container = new Container( parent, objectID, title );
parent->addContainer( container );
IXML_Element* containerElement =
( IXML_Element* )ixmlNodeList_item( containerNodeList, i );
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* title = xml_getChildElementValue( containerElement,
"dc:title" );
if ( !title )
continue;
const char* resource = xml_getChildElementValue( containerElement,
"res" );
if ( resource && childCount < 1 )
{
Item* item = new Item( parent, objectID, title, resource );
parent->addItem( item );
}
if ( childCount > 0 ) _fetchContents( container );
}
}
else
{
Container* container = new Container( parent, objectID, title );
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 );
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;
Item* item = new Item( parent, objectID, title, resource );
parent->addItem( item );
}
ixmlNodeList_free( itemNodeList );
{
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" );
if ( !title )
continue;
const char* resource =
xml_getChildElementValue( itemElement, "res" );
if ( !resource )
continue;
Item* item = new Item( parent, objectID, title, resource );
parent->addItem( item );
}
ixmlNodeList_free( itemNodeList );
}
ixmlDocument_free( result );
return true;
}
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++ )
{
Container* container = parent->getContainer( i );
playlist_item_t* parentNode = parent->getPlaylistNode();
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 );
container->setPlaylistNode( node );
......@@ -877,7 +1026,7 @@ void MediaServer::_buildPlaylist( Container* parent )
Item* item = parent->getItem( i );
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->getTitle() );
int i_cat;
......@@ -887,10 +1036,12 @@ void MediaServer::_buildPlaylist( Container* parent )
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 );
playlist_item_t *p_node =
playlist_ItemGetById( p_playlist, i_cat, false );
assert( p_node );
item->setPlaylistNode( p_node );
}
pl_Release( _p_sd );
}
void MediaServer::setPlaylistNode( playlist_item_t* playlistNode )
......@@ -906,16 +1057,16 @@ 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];
}
}
......@@ -923,17 +1074,37 @@ bool MediaServerList::addServer( MediaServer* s )
{
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;
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 );
char* name = strdup( s->getFriendlyName() );
vlc_object_lock( _cookie->serviceDiscovery->p_sys->p_playlist );
playlist_item_t* node = playlist_NodeCreate(
pl_Get( _cookie->serviceDiscovery ), name,
_cookie->serviceDiscovery->p_sys->p_node_cat,
0, NULL );
vlc_object_unlock( _cookie->serviceDiscovery->p_sys->p_playlist );
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 );
......@@ -947,10 +1118,10 @@ MediaServer* MediaServerList::getServer( const char* UDN )
for ( unsigned int i = 0; i < _list.size(); i++ )
{
if( strcmp( UDN, _list[i]->getUDN() ) == 0 )
{
result = _list[i];
break;
}
{
result = _list[i];
break;
}
}
return result;
......@@ -962,11 +1133,11 @@ MediaServer* MediaServerList::getServerBySID( const char* sid )
for ( unsigned int i = 0; i < _list.size(); i++ )
{
if ( _list[i]->compareSID( sid ) )
{
server = _list[i];
break;
}
if ( _list[i]->compareSID( sid ) )
{
server = _list[i];
break;
}
}
return server;
......@@ -977,17 +1148,18 @@ void MediaServerList::removeServer( const char* UDN )
MediaServer* server = getServer( UDN );
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;
for ( it = _list.begin(); it != _list.end(); it++ )
{
if ( *it == server )
{
_list.erase( it );
delete server;
break;
}
{
_list.erase( it );
delete server;
break;
}
}
}
......@@ -1033,7 +1205,9 @@ playlist_item_t* Item::getPlaylistNode() const
// Container...
Container::Container( Container* parent, const char* objectID, const char* title )
Container::Container( Container* parent,
const char* objectID,
const char* title )
{
_parent = parent;
......@@ -1047,12 +1221,12 @@ 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];
}
}
......
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