Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

upnp.cpp

00001 /*****************************************************************************
00002  * upnp.cpp :  UPnP discovery module
00003  *****************************************************************************
00004  * Copyright (C) 2004-2005 the VideoLAN team
00005  * $Id$
00006  *
00007  * Authors: RĂ©mi Denis-Courmont <rem # videolan.org>
00008  * 
00009  * Based on original wxWindows patch for VLC, and dependant on CyberLink
00010  * UPnP library from :
00011  *          Satoshi Konno <[email protected]>
00012  *
00013  * This program is free software; you can redistribute it and/or modify
00014  * it under the terms of the GNU General Public License as published by
00015  * the Free Software Foundation; either version 2 of the License, or
00016  * (at your option) any later version.
00017  *
00018  * This program is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00026  *****************************************************************************/
00027 
00028 /*****************************************************************************
00029  * Includes
00030  *****************************************************************************/
00031 #include <stdlib.h>                                      /* malloc(), free() */
00032 
00033 #include <cybergarage/upnp/media/player/MediaPlayer.h>
00034 
00035 #undef PACKAGE_NAME
00036 #include <vlc/vlc.h>
00037 #include <vlc/intf.h>
00038 
00039 /* FIXME: thread-safety ?? */
00040 /* FIXME: playlist locking */
00041 
00042 /************************************************************************
00043  * Macros and definitions
00044  ************************************************************************/
00045 using namespace std;
00046 using namespace CyberLink;
00047 
00048 /*****************************************************************************
00049  * Module descriptor
00050  *****************************************************************************/
00051 
00052 /* Callbacks */
00053     static int  Open ( vlc_object_t * );
00054     static void Close( vlc_object_t * );
00055 
00056 vlc_module_begin();
00057     set_shortname( _("UPnP"));
00058     set_description( _("Universal Plug'n'Play discovery") );
00059     set_category( CAT_PLAYLIST );
00060     set_subcategory( SUBCAT_PLAYLIST_SD );
00061 
00062     set_capability( "services_discovery", 0 );
00063     set_callbacks( Open, Close );
00064 
00065 vlc_module_end();
00066 
00067 
00068 /*****************************************************************************
00069  * Local structures
00070  *****************************************************************************/
00071 
00072 struct services_discovery_sys_t
00073 {
00074     /* playlist node */
00075     playlist_item_t *p_node;
00076     playlist_t *p_playlist;
00077 };
00078 
00079 /*****************************************************************************
00080  * Local prototypes
00081  *****************************************************************************/
00082 
00083 /* Main functions */
00084     static void Run    ( services_discovery_t *p_sd );
00085 
00086 /*****************************************************************************
00087  * Open: initialize and create stuff
00088  *****************************************************************************/
00089 static int Open( vlc_object_t *p_this )
00090 {
00091     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
00092     services_discovery_sys_t *p_sys  = (services_discovery_sys_t *)
00093                                 malloc( sizeof( services_discovery_sys_t ) );
00094 
00095     playlist_view_t     *p_view;
00096     vlc_value_t         val;
00097 
00098     p_sd->pf_run = Run;
00099     p_sd->p_sys  = p_sys;
00100 
00101     /* Create our playlist node */
00102     p_sys->p_playlist = (playlist_t *)vlc_object_find( p_sd,
00103                                                        VLC_OBJECT_PLAYLIST,
00104                                                        FIND_ANYWHERE );
00105     if( !p_sys->p_playlist )
00106     {
00107         msg_Warn( p_sd, "unable to find playlist, cancelling UPnP listening");
00108         return VLC_EGENERIC;
00109     }
00110 
00111     p_view = playlist_ViewFind( p_sys->p_playlist, VIEW_CATEGORY );
00112     p_sys->p_node = playlist_NodeCreate( p_sys->p_playlist, VIEW_CATEGORY,
00113                                          _("UPnP"), p_view->p_root );
00114     p_sys->p_node->i_flags |= PLAYLIST_RO_FLAG;
00115     p_sys->p_node->i_flags &= ~PLAYLIST_SKIP_FLAG;
00116     val.b_bool = VLC_TRUE;
00117     var_Set( p_sys->p_playlist, "intf-change", val );
00118 
00119     return VLC_SUCCESS;
00120 }
00121 
00122 
00123 /*****************************************************************************
00124  * Close:
00125  *****************************************************************************/
00126 static void Close( vlc_object_t *p_this )
00127 {
00128     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
00129     services_discovery_sys_t    *p_sys  = p_sd->p_sys;
00130 
00131     if( p_sys->p_playlist )
00132     {
00133         playlist_NodeDelete( p_sys->p_playlist, p_sys->p_node, VLC_TRUE,
00134                              VLC_TRUE );
00135         vlc_object_release( p_sys->p_playlist );
00136     }
00137 
00138     free( p_sys );
00139 }
00140 
00141 /*****************************************************************************
00142  * Run: main UPnP thread
00143  *****************************************************************************
00144  * Processes UPnP events
00145  *****************************************************************************/
00146 class UPnPHandler : public MediaPlayer, public DeviceChangeListener,
00147                     /*public EventListener,*/ public SearchResponseListener
00148 {
00149     private:
00150         services_discovery_t *p_sd;
00151         services_discovery_sys_t *p_sys;
00152 
00153         Device *GetDeviceFromUSN( const string& usn )
00154         {
00155             return getDevice( usn.substr( 0, usn.find( "::" ) ).c_str() );
00156         }
00157 
00158         playlist_item_t *FindDeviceNode( Device *dev )
00159         {
00160             return playlist_ChildSearchName( p_sys->p_node, dev->getFriendlyName() );
00161         }
00162 
00163         playlist_item_t *FindDeviceNode( const string &usn )
00164         {
00165             return FindDeviceNode( GetDeviceFromUSN( usn ) );
00166         }
00167 
00168         playlist_item_t *AddDevice( Device *dev );
00169         void AddDeviceContent( Device *dev );
00170         void AddContent( playlist_item_t *p_parent, ContentNode *node );
00171         void RemoveDevice( Device *dev );
00172 
00173         /* CyberLink callbacks */
00174         virtual void deviceAdded( Device *dev );
00175         virtual void deviceRemoved( Device *dev );
00176 
00177         virtual void deviceSearchResponseReceived( SSDPPacket *packet );
00178         /*virtual void eventNotifyReceived( const char *uuid, long seq,
00179                                           const char *name,
00180                                           const char *value );*/
00181 
00182     public:
00183         UPnPHandler( services_discovery_t *p_this )
00184             : p_sd( p_this ), p_sys( p_this->p_sys )
00185         {
00186             addDeviceChangeListener( this );
00187             addSearchResponseListener( this );
00188             //addEventListener( this );
00189         }
00190 
00191 };
00192 
00193 static void Run( services_discovery_t *p_sd )
00194 {
00195     UPnPHandler u( p_sd );
00196 
00197     u.start();
00198 
00199     msg_Dbg( p_sd, "UPnP discovery started" );
00200     /* read SAP packets */
00201     while( !p_sd->b_die )
00202     {
00203         msleep( 500 );
00204     }
00205 
00206     u.stop();
00207     msg_Dbg( p_sd, "UPnP discovery stopped" );
00208 }
00209 
00210 
00211 playlist_item_t *UPnPHandler::AddDevice( Device *dev )
00212 {
00213     if( dev == NULL )
00214         return NULL;
00215 
00216     /* We are not interested in IGD devices or whatever (at the moment) */
00217     if ( !dev->isDeviceType( MediaServer::DEVICE_TYPE ) )
00218         return NULL;
00219 
00220     playlist_item_t *p_item = FindDeviceNode( dev );
00221     if ( p_item != NULL )
00222         return p_item;
00223 
00224     /* FIXME:
00225      * Maybe one day, VLC API will make sensible use of the const keyword;
00226      * That day, you will no longer need this strdup().
00227      */
00228     char *str = strdup( dev->getFriendlyName( ) );
00229 
00230     p_item = playlist_NodeCreate( p_sys->p_playlist, VIEW_CATEGORY,
00231                                   str, p_sys->p_node );
00232     p_item->i_flags &= ~PLAYLIST_SKIP_FLAG;
00233     msg_Dbg( p_sd, "device %s added", str );
00234     free( str );
00235 
00236     return p_item;
00237 }
00238 
00239 void UPnPHandler::AddDeviceContent( Device *dev )
00240 {
00241     playlist_item_t *p_devnode = AddDevice( dev );
00242 
00243     if( p_devnode == NULL )
00244         return;
00245 
00246     AddContent( p_devnode, getContentDirectory( dev ) );
00247 }
00248 
00249 void UPnPHandler::AddContent( playlist_item_t *p_parent, ContentNode *node )
00250 {
00251     if( node == NULL )
00252         return;
00253 
00254     const char *title = node->getTitle();
00255     if( title == NULL )
00256         return;
00257 
00258     msg_Dbg( p_sd, "title = %s", title );
00259 
00260     if ( node->isItemNode() ) 
00261     {
00262         ItemNode *iNode = (ItemNode *)node;
00263 
00264         playlist_item_t *p_item;
00265         p_item = playlist_ItemNew( p_sd, iNode->getResource(), title );
00266     
00267         playlist_NodeAddItem( p_sys->p_playlist, p_item, VIEW_CATEGORY,
00268                               p_parent, PLAYLIST_APPEND, PLAYLIST_END );
00269 
00270     } else if ( node->isContainerNode() ) 
00271     {
00272         ContainerNode *conNode = (ContainerNode *)node;
00273 
00274         char* p_name = strdup(title); /* See other comment on strdup */
00275         playlist_item_t* p_node = playlist_NodeCreate( p_sys->p_playlist, VIEW_CATEGORY, 
00276                                                        p_name, p_parent );
00277         free(p_name);
00278 
00279         unsigned nContentNodes = conNode->getNContentNodes();
00280 
00281         for( unsigned n = 0; n < nContentNodes; n++ )
00282             AddContent( p_node, conNode->getContentNode( n ) );
00283     }
00284 }
00285 
00286 
00287 void UPnPHandler::RemoveDevice( Device *dev )
00288 {
00289     playlist_item_t *p_item = FindDeviceNode( dev );
00290 
00291     if( p_item != NULL )
00292         playlist_NodeDelete( p_sys->p_playlist, p_item, VLC_TRUE, VLC_TRUE );
00293 }
00294 
00295 
00296 void UPnPHandler::deviceAdded( Device *dev )
00297 {
00298     msg_Dbg( p_sd, "adding device" );
00299     AddDeviceContent( dev );
00300 }
00301 
00302 
00303 void UPnPHandler::deviceRemoved( Device *dev )
00304 {
00305     msg_Dbg( p_sd, "removing device" );
00306     RemoveDevice( dev );
00307 }
00308 
00309 
00310 void UPnPHandler::deviceSearchResponseReceived( SSDPPacket *packet )
00311 {
00312     if( !packet->isRootDevice() )
00313         return;
00314 
00315     string usn, nts, nt, udn;
00316 
00317     packet->getUSN( usn );
00318     packet->getNT( nt );
00319     packet->getNTS( nts );
00320     udn = usn.substr( 0, usn.find( "::" ) );
00321 
00322     /* Remove existing root device before adding updated one */
00323 
00324     Device *dev = GetDeviceFromUSN( usn );
00325     RemoveDevice( dev );
00326 
00327     if( !packet->isByeBye() )
00328         AddDeviceContent( dev );
00329 }
00330 
00331 /*void UPnPHandler::eventNotifyReceived( const char *uuid, long seq,
00332                                        const char *name, const char *value )
00333 {
00334     msg_Dbg( p_sd, "event notify received" );
00335     msg_Dbg( p_sd, "uuid = %s, name = %s, value = %s", uuid, name, value );
00336 }*/

Generated on Tue Dec 20 10:14:49 2005 for vlc-0.8.4a by  doxygen 1.4.2