* $Id$
*
* Authors: RĂ©mi Denis-Courmont <rem # videolan.org> (original plugin)
- * Christian Henz <henz # c-lab.de>
- *
+ * Christian Henz <henz # c-lab.de>
+ *
* UPnP Plugin using the Intel SDK (libupnp) instead of CyberLink
*
* This program is free software; you can redistribute it and/or modify
#undef PACKAGE_NAME
#include <vlc/vlc.h>
-#include <vlc/intf.h>
+#include <vlc_playlist.h>
+#include "vlc_strings.h"
// VLC handle
struct services_discovery_sys_t
{
- playlist_item_t *p_node;
- playlist_t *p_playlist;
+ playlist_item_t *p_node_cat;
+ playlist_item_t *p_node_one;
};
const char* CONTENT_DIRECTORY_SERVICE_TYPE = "urn:schemas-upnp-org:service:ContentDirectory:1";
-// Classes
+// Classes
class MediaServer;
class MediaServerList;
// Cookie that is passed to the callback
-typedef struct
+typedef struct
{
services_discovery_t* serviceDiscovery;
UpnpClient_Handle clientHandle;
- MediaServerList* serverList;
+ MediaServerList* serverList;
} Cookie;
// Class definitions...
-class Lockable
-{
+class Lockable
+{
public:
- Lockable( Cookie* c )
+ Lockable( Cookie* c )
{
- vlc_mutex_init( c->serviceDiscovery, &_mutex );
+ vlc_mutex_init( c->serviceDiscovery, &_mutex );
}
- ~Lockable()
+ ~Lockable()
{
- vlc_mutex_destroy( &_mutex );
+ vlc_mutex_destroy( &_mutex );
}
void lock() { vlc_mutex_lock( &_mutex ); }
void unlock() { vlc_mutex_unlock( &_mutex ); }
private:
-
+
vlc_mutex_t _mutex;
};
-class Locker
+class Locker
{
public:
- Locker( Lockable* l )
+ Locker( Lockable* l )
{
- _lockable = l;
- _lockable->lock();
+ _lockable = l;
+ _lockable->lock();
}
- ~Locker()
+ ~Locker()
{
- _lockable->unlock();
+ _lockable->unlock();
}
private:
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;
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;
};
-class Item
+class Item
{
public:
private:
playlist_item_t* _playlistNode;
-
+
Container* _parent;
std::string _objectID;
std::string _title;
};
-class Container
+class Container
{
public:
static Lockable* CallbackLock;
static int Callback( Upnp_EventType eventType, void* event, void* pCookie );
-char* xml_makeSpecialChars( const char* in );
const char* xml_getChildElementValue( IXML_Element* parent, const char* tagName );
IXML_Document* parseBrowseResult( IXML_Document* doc );
{
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_view_t *p_view;
- vlc_value_t val;
+ malloc( sizeof( services_discovery_sys_t ) );
p_sd->pf_run = Run;
p_sd->p_sys = p_sys;
/* Create our playlist node */
- p_sys->p_playlist = ( playlist_t * )vlc_object_find( p_sd,
- VLC_OBJECT_PLAYLIST,
- FIND_ANYWHERE );
- if( !p_sys->p_playlist )
- {
- msg_Warn( p_sd, "unable to find playlist, cancelling UPnP listening" );
- return VLC_EGENERIC;
- }
-
- p_view = playlist_ViewFind( p_sys->p_playlist, VIEW_CATEGORY );
- p_sys->p_node = playlist_NodeCreate( p_sys->p_playlist, VIEW_CATEGORY,
- "UPnP", p_view->p_root );
- p_sys->p_node->i_flags |= PLAYLIST_RO_FLAG;
- p_sys->p_node->i_flags &= ~PLAYLIST_SKIP_FLAG;
- val.b_bool = VLC_TRUE;
- var_Set( p_sys->p_playlist, "intf-change", val );
+ playlist_NodesPairCreate( pl_Get( p_sd ), _("Devices"),
+ &p_sys->p_node_cat, &p_sys->p_node_one,
+ VLC_TRUE );
return VLC_SUCCESS;
}
services_discovery_t *p_sd = ( services_discovery_t* )p_this;
services_discovery_sys_t *p_sys = p_sd->p_sys;
- if( p_sys->p_playlist )
- {
- playlist_NodeDelete( p_sys->p_playlist, p_sys->p_node, VLC_TRUE,
- VLC_TRUE );
- vlc_object_release( p_sys->p_playlist );
- }
+ 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 )
+ if( res != UPNP_E_SUCCESS )
{
- msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
- return;
+ msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
+ return;
}
Cookie cookie;
CallbackLock = new Lockable( &cookie );
res = UpnpRegisterClient( Callback, &cookie, &cookie.clientHandle );
- if( res != UPNP_E_SUCCESS )
+ if( res != UPNP_E_SUCCESS )
{
- msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
- goto shutDown;
+ msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
+ goto shutDown;
}
res = UpnpSearchAsync( cookie.clientHandle, 5, MEDIA_SERVER_DEVICE_TYPE, &cookie );
- if( res != UPNP_E_SUCCESS )
+ if( res != UPNP_E_SUCCESS )
{
- msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
- goto shutDown;
+ msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
+ goto shutDown;
}
-
+
msg_Dbg( p_sd, "UPnP discovery started" );
- while( !p_sd->b_die )
+ while( !p_sd->b_die )
{
- msleep( 500 );
+ 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;
return ixmlNode_getNodeValue( textNode );
}
-
-// Replaces "<" with "<" etc.
-// Returns a newly created string that has to be freed by the caller.
-// Returns 0 on error ( out of mem )
-// \TODO: Probably not very robust!!!
-char* xml_makeSpecialChars( const char* in )
-{
- if ( !in ) return 0;
-
- char* result = ( char* )malloc( strlen( in ) + 1 );
- if ( !result ) return 0;
-
- char* out = result;
-
- while( *in )
- {
- if ( strncmp( "&", in, 5 ) == 0 )
- {
- *out = '&';
-
- in += 5;
- out++;
- }
- else if ( strncmp( """, in, 6 ) == 0 )
- {
- *out = '"';
-
- in += 6;
- out++;
- }
- else if ( strncmp( ">", in, 4 ) == 0 )
- {
- *out = '>';
-
- in += 4;
- out++;
- }
- else if ( strncmp( "<", in, 4 ) == 0 )
- {
- *out = '<';
-
- in += 4;
- out++;
- }
- else
- {
- *out = *in;
-
- in++;
- out++;
- }
- }
-
- *out = '\0';
- return result;
-}
-
-
// Extracts the result document from a SOAP response
-IXML_Document* parseBrowseResult( IXML_Document* doc )
+IXML_Document* parseBrowseResult( IXML_Document* doc )
{
if ( !doc ) return 0;
-
+
IXML_NodeList* resultList = ixmlDocument_getElementsByTagName( doc, "Result" );
if ( !resultList ) return 0;
-
+
IXML_Node* resultNode = ixmlNodeList_item( resultList, 0 );
ixmlNodeList_free( resultList );
if ( !textNode ) return 0;
const char* resultString = ixmlNode_getNodeValue( textNode );
- char* resultXML = xml_makeSpecialChars( resultString );
+ char* resultXML = strdup( resultString );
+
+ resolve_xml_special_chars( resultXML );
IXML_Document* browseDoc = ixmlParseBuffer( resultXML );
// Handles all UPnP events
-static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
+static int Callback( Upnp_EventType eventType, void* event, void* pCookie )
{
Locker locker( CallbackLock );
Cookie* cookie = ( Cookie* )pCookie;
switch( eventType ) {
-
+
case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
case UPNP_DISCOVERY_SEARCH_RESULT:
- {
- struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
-
- IXML_Document *descriptionDoc = 0;
-
- int res;
- 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;
- }
-
- MediaServer::parseDeviceDescription( descriptionDoc, discovery->Location, cookie );
-
- ixmlDocument_free( descriptionDoc );
- }
- break;
-
+ {
+ struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
+
+ IXML_Document *descriptionDoc = 0;
+
+ int res;
+ 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;
+ }
+
+ MediaServer::parseDeviceDescription( descriptionDoc, discovery->Location, cookie );
+
+ ixmlDocument_free( descriptionDoc );
+ }
+ break;
+
case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
- {
- struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
+ {
+ struct Upnp_Discovery* discovery = ( struct Upnp_Discovery* )event;
- cookie->serverList->removeServer( discovery->DeviceId );
- }
- break;
+ cookie->serverList->removeServer( discovery->DeviceId );
+ }
+ break;
case UPNP_EVENT_RECEIVED:
- {
- Upnp_Event* e = ( Upnp_Event* )event;
+ {
+ Upnp_Event* e = ( Upnp_Event* )event;
- MediaServer* server = cookie->serverList->getServerBySID( e->Sid );
- if ( server ) server->fetchContents();
- }
- break;
+ MediaServer* server = cookie->serverList->getServerBySID( e->Sid );
+ if ( server ) server->fetchContents();
+ }
+ break;
case UPNP_EVENT_AUTORENEWAL_FAILED:
case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
- {
- // Re-subscribe...
+ {
+ // Re-subscribe...
- Upnp_Event_Subscribe* s = ( Upnp_Event_Subscribe* )event;
+ Upnp_Event_Subscribe* s = ( Upnp_Event_Subscribe* )event;
- MediaServer* server = cookie->serverList->getServerBySID( s->Sid );
- if ( server ) server->subscribeToContentDirectory();
- }
- break;
-
+ MediaServer* server = cookie->serverList->getServerBySID( s->Sid );
+ if ( server ) server->subscribeToContentDirectory();
+ }
+ break;
+
+ case UPNP_EVENT_SUBSCRIBE_COMPLETE:
+ msg_Warn( cookie->serviceDiscovery, "subscription complete" );
+ break;
+
+ case UPNP_DISCOVERY_SEARCH_TIMEOUT:
+ msg_Warn( cookie->serviceDiscovery, "search timeout" );
+ break;
+
default:
- msg_Dbg( cookie->serviceDiscovery, "%s:%d: DEBUG: UNHANDLED EVENT ( TYPE=%d )", __FILE__, __LINE__, eventType );
- break;
+ msg_Dbg( cookie->serviceDiscovery, "%s:%d: DEBUG: UNHANDLED EVENT ( TYPE=%d )", __FILE__, __LINE__, eventType );
+ break;
}
return UPNP_E_SUCCESS;
// MediaServer...
-void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* location, Cookie* cookie )
+void MediaServer::parseDeviceDescription( IXML_Document* doc, const char* location, Cookie* cookie )
{
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 ) )
- {
- IXML_Node* textNode = ixmlNode_getFirstChild( urlNode );
- if ( textNode ) baseURL = ixmlNode_getNodeValue( textNode );
- }
-
- ixmlNodeList_free( urlList );
+ if ( 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" );
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++ )
- {
- 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 )
- {
- // msg_Dbg( cookie->serviceDiscovery, "CDS EVENT URL: %s", url );
-
- 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 )
- {
- // msg_Dbg( cookie->serviceDiscovery, "CDS CTRL URL: %s", url );
-
- server->setContentDirectoryControlURL( url );
- server->fetchContents();
- }
-
- free( s1 );
- free( s2 );
- free( url );
- }
- }
-
- ixmlNodeList_free( serviceList );
- }
- }
-
- ixmlNodeList_free( 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++ )
+ {
+ 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 )
+ {
+ // msg_Dbg( cookie->serviceDiscovery, "CDS EVENT URL: %s", url );
+
+ 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 )
+ {
+ // msg_Dbg( cookie->serviceDiscovery, "CDS CTRL URL: %s", url );
+
+ 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, Cookie* cookie )
{
_cookie = cookie;
_playlistNode = 0;
}
-MediaServer::~MediaServer()
-{
- if ( _contents )
+MediaServer::~MediaServer()
+{
+ if ( _contents )
{
- playlist_NodeDelete( _cookie->serviceDiscovery->p_sys->p_playlist,
- _playlistNode,
- true,
- true );
+ playlist_NodeDelete( pl_Get( _cookie->serviceDiscovery ) ,
+ _playlistNode, VLC_TRUE, VLC_TRUE );
}
delete _contents;
return s;
}
-void MediaServer::setContentDirectoryEventURL( const char* url )
+void MediaServer::setContentDirectoryEventURL( const char* url )
{
_contentDirectoryEventURL = url;
}
return s;
}
-void MediaServer::setContentDirectoryControlURL( const char* url )
+void MediaServer::setContentDirectoryControlURL( const char* url )
{
_contentDirectoryControlURL = url;
}
return _contentDirectoryControlURL.c_str();
}
-void MediaServer::subscribeToContentDirectory()
+void MediaServer::subscribeToContentDirectory()
{
const char* url = getContentDirectoryEventURL();
- if ( !url || strcmp( url, "" ) == 0 )
- {
- msg_Dbg( _cookie->serviceDiscovery, "No subscription url set!" );
- return;
+ if ( !url || strcmp( url, "" ) == 0 )
+ {
+ msg_Dbg( _cookie->serviceDiscovery, "No subscription url set!" );
+ return;
}
int timeOut = 1810;
Upnp_SID sid;
-
+
int res = UpnpSubscribe( _cookie->clientHandle, url, &timeOut, sid );
- if ( res == UPNP_E_SUCCESS )
+ if ( res == UPNP_E_SUCCESS )
{
- _subscriptionTimeOut = timeOut;
- memcpy( _subscriptionID, sid, sizeof( Upnp_SID ) );
- }
- else
+ _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( _cookie->serviceDiscovery, "%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;
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; }
-
- res = UpnpSendAction( _cookie->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;
+
+ res = UpnpSendAction( _cookie->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;
}
browseActionCleanup:
return response;
}
-void MediaServer::fetchContents()
+void MediaServer::fetchContents()
{
Container* root = new Container( 0, "0", getFriendlyName() );
+ playlist_t * p_playlist = pl_Get( _cookie->serviceDiscovery );
_fetchContents( root );
- if ( _contents )
+ if ( _contents )
{
- vlc_mutex_lock( &_cookie->serviceDiscovery->p_sys->p_playlist->object_lock );
-
- playlist_NodeEmpty( _cookie->serviceDiscovery->p_sys->p_playlist,
- _playlistNode,
- true );
-
- vlc_mutex_unlock( &_cookie->serviceDiscovery->p_sys->p_playlist->object_lock );
-
- delete _contents;
+ PL_LOCK;
+ playlist_NodeEmpty( p_playlist, _playlistNode, VLC_TRUE );
+ PL_UNLOCK;
+ delete _contents;
}
_contents = root;
_buildPlaylist( _contents );
}
-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 ( !result ) { msg_Dbg( _cookie->serviceDiscovery, "%s:%d: ERROR!", __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++ )
- {
- 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
- {
- Container* container = new Container( parent, objectID, title );
- parent->addContainer( container );
-
- if ( childCount > 0 ) _fetchContents( container );
- }
- }
-
- ixmlNodeList_free( 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
+ {
+ Container* container = new Container( parent, objectID, title );
+ parent->addContainer( container );
+
+ if ( childCount > 0 ) _fetchContents( container );
+ }
+ }
+
+ ixmlNodeList_free( containerNodeList );
}
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 );
-
- 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 )
-{
- for ( unsigned int i = 0; i < parent->getNumContainers(); i++ )
+void MediaServer::_buildPlaylist( Container* parent )
+{
+ playlist_t *p_playlist = pl_Get( _cookie->serviceDiscovery );
+ 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( _cookie->serviceDiscovery->p_sys->p_playlist,
- VIEW_CATEGORY,
- title,
- parentNode );
- free( title );
-
- container->setPlaylistNode( node );
- _buildPlaylist( container );
+ 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 );
+ free( title );
+
+ container->setPlaylistNode( node );
+ _buildPlaylist( container );
}
- for ( unsigned int i = 0; i < parent->getNumItems(); i++ )
+ for ( unsigned int i = 0; i < parent->getNumItems(); i++ )
{
- Item* item = parent->getItem( i );
- playlist_item_t* parentNode = parent->getPlaylistNode();
-
- playlist_item_t* node = playlist_ItemNew( _cookie->serviceDiscovery,
- item->getResource(),
- item->getTitle() );
-
- playlist_NodeAddItem( _cookie->serviceDiscovery->p_sys->p_playlist,
- node,
- VIEW_CATEGORY,
- parentNode, PLAYLIST_APPEND, PLAYLIST_END );
-
- item->setPlaylistNode( node );
+ Item* item = parent->getItem( i );
+ playlist_item_t* parentNode = parent->getPlaylistNode();
+
+ input_item_t* p_input = input_ItemNew( _cookie->serviceDiscovery,
+ 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 );
}
}
-void MediaServer::setPlaylistNode( playlist_item_t* playlistNode )
+void MediaServer::setPlaylistNode( playlist_item_t* playlistNode )
{
_playlistNode = playlistNode;
}
-bool MediaServer::compareSID( const char* sid )
+bool MediaServer::compareSID( const char* sid )
{
return ( strncmp( _subscriptionID, sid, sizeof( Upnp_SID ) ) == 0 );
}
// MediaServerList...
-MediaServerList::MediaServerList( Cookie* cookie )
+MediaServerList::MediaServerList( Cookie* cookie )
{
_cookie = cookie;
}
-MediaServerList::~MediaServerList()
+MediaServerList::~MediaServerList()
{
for ( unsigned int i = 0; i < _list.size(); i++ )
{
- delete _list[i];
+ delete _list[i];
}
}
-bool MediaServerList::addServer( MediaServer* s )
+bool MediaServerList::addServer( MediaServer* s )
{
if ( getServer( s->getUDN() ) != 0 ) return false;
_list.push_back( s );
char* name = strdup( s->getFriendlyName() );
- playlist_item_t* node = playlist_NodeCreate( _cookie->serviceDiscovery->p_sys->p_playlist,
- VIEW_CATEGORY,
- name,
- _cookie->serviceDiscovery->p_sys->p_node );
+ playlist_item_t* node = playlist_NodeCreate( pl_Get( _cookie->serviceDiscovery ),
+ name,
+ _cookie->serviceDiscovery->p_sys->p_node_cat, 0 );
free( name );
s->setPlaylistNode( node );
return true;
}
-MediaServer* MediaServerList::getServer( const char* UDN )
+MediaServer* MediaServerList::getServer( const char* UDN )
{
MediaServer* result = 0;
-
- for ( unsigned int i = 0; i < _list.size(); i++ )
+
+ for ( unsigned int i = 0; i < _list.size(); i++ )
+ {
+ if( strcmp( UDN, _list[i]->getUDN() ) == 0 )
{
- if( strcmp( UDN, _list[i]->getUDN() ) == 0 )
- {
- result = _list[i];
- break;
- }
+ result = _list[i];
+ break;
+ }
}
return result;
}
-MediaServer* MediaServerList::getServerBySID( const char* sid )
-{
+MediaServer* MediaServerList::getServerBySID( const char* sid )
+{
MediaServer* server = 0;
- for ( unsigned int i = 0; i < _list.size(); i++ )
+ for ( unsigned int i = 0; i < _list.size(); i++ )
+ {
+ if ( _list[i]->compareSID( sid ) )
{
- if ( _list[i]->compareSID( sid ) )
- {
- server = _list[i];
- break;
- }
+ server = _list[i];
+ break;
}
-
+ }
+
return server;
}
-void MediaServerList::removeServer( const char* UDN )
+void MediaServerList::removeServer( const char* UDN )
{
MediaServer* server = getServer( UDN );
if ( !server ) return;
- msg_Dbg( _cookie->serviceDiscovery, "Removing server '%s'", server->getFriendlyName() );
+ msg_Dbg( _cookie->serviceDiscovery, "Removing server '%s'", server->getFriendlyName() );
std::vector<MediaServer*>::iterator it;
- for ( it = _list.begin(); it != _list.end(); it++ )
+ for ( it = _list.begin(); it != _list.end(); it++ )
{
- if ( *it == server )
- {
- _list.erase( it );
- delete server;
- break;
- }
+ if ( *it == server )
+ {
+ _list.erase( it );
+ delete server;
+ break;
+ }
}
}
// Item...
-Item::Item( Container* parent, const char* objectID, const char* title, const char* resource )
+Item::Item( Container* parent, const char* objectID, const char* title, const char* resource )
{
_parent = parent;
-
+
_objectID = objectID;
_title = title;
_resource = resource;
_playlistNode = 0;
}
-const char* Item::getObjectID() const
+const char* Item::getObjectID() const
{
return _objectID.c_str();
}
-const char* Item::getTitle() const
+const char* Item::getTitle() const
{
return _title.c_str();
}
-const char* Item::getResource() const
+const char* Item::getResource() const
{
return _resource.c_str();
}
-void Item::setPlaylistNode( playlist_item_t* node )
-{
- _playlistNode = node;
+void Item::setPlaylistNode( playlist_item_t* node )
+{
+ _playlistNode = node;
}
-playlist_item_t* Item::getPlaylistNode() const
-{
- return _playlistNode;
+playlist_item_t* Item::getPlaylistNode() const
+{
+ return _playlistNode;
}
// Container...
-Container::Container( Container* parent, const char* objectID, const char* title )
+Container::Container( Container* parent, const char* objectID, const char* title )
{
_parent = parent;
-
+
_objectID = objectID;
_title = title;
_playlistNode = 0;
}
-Container::~Container()
+Container::~Container()
{
- for ( unsigned int i = 0; i < _containers.size(); i++ )
+ for ( unsigned int i = 0; i < _containers.size(); i++ )
{
- delete _containers[i];
+ delete _containers[i];
}
- for ( unsigned int i = 0; i < _items.size(); i++ )
+ for ( unsigned int i = 0; i < _items.size(); i++ )
{
- delete _items[i];
+ delete _items[i];
}
}
-void Container::addItem( Item* item )
+void Container::addItem( Item* item )
{
_items.push_back( item );
}
-void Container::addContainer( Container* container )
+void Container::addContainer( Container* container )
{
_containers.push_back( container );
}
-const char* Container::getObjectID() const
-{
- return _objectID.c_str();
+const char* Container::getObjectID() const
+{
+ return _objectID.c_str();
}
-const char* Container::getTitle() const
-{
- return _title.c_str();
+const char* Container::getTitle() const
+{
+ return _title.c_str();
}
-unsigned int Container::getNumItems() const
-{
- return _items.size();
+unsigned int Container::getNumItems() const
+{
+ return _items.size();
}
-unsigned int Container::getNumContainers() const
-{
- return _containers.size();
+unsigned int Container::getNumContainers() const
+{
+ return _containers.size();
}
-Item* Container::getItem( unsigned int i ) const
+Item* Container::getItem( unsigned int i ) const
{
if ( i < _items.size() ) return _items[i];
return 0;
}
-Container* Container::getContainer( unsigned int i ) const
+Container* Container::getContainer( unsigned int i ) const
{
if ( i < _containers.size() ) return _containers[i];
return 0;
}
-void Container::setPlaylistNode( playlist_item_t* node )
-{
- _playlistNode = node;
+void Container::setPlaylistNode( playlist_item_t* node )
+{
+ _playlistNode = node;
}
-playlist_item_t* Container::getPlaylistNode() const
-{
- return _playlistNode;
+playlist_item_t* Container::getPlaylistNode() const
+{
+ return _playlistNode;
}