[svn r702] Changed the architecture to support GObject signals in the clinkc's UPnP model. trunk
authorrosfran
Tue May 22 19:14:37 2007 +0100 (2007-05-22)
branchtrunk
changeset 6967afeec40ed62
parent 695 4712c96954be
child 697 e323e95b88dd
[svn r702] Changed the architecture to support GObject signals in the clinkc's UPnP model.
gmyth-upnp/src/Makefile.am
gmyth-upnp/src/gmyth_upnp.c
gmyth-upnp/src/gmyth_upnp.h
gmyth-upnp/src/gmyth_upnp_marshal.list
     1.1 --- a/gmyth-upnp/src/Makefile.am	Fri May 18 23:29:00 2007 +0100
     1.2 +++ b/gmyth-upnp/src/Makefile.am	Tue May 22 19:14:37 2007 +0100
     1.3 @@ -2,9 +2,25 @@
     1.4  
     1.5  lib_LTLIBRARIES = libgmythupnp.la
     1.6  
     1.7 +BUILT_SOURCES =                                 \
     1.8 +        gmyth_upnp_marshal.c                    \
     1.9 +	gmyth_upnp_marshal.h
    1.10 +
    1.11  libgmythupnp_la_SOURCES = 			\
    1.12  	gmyth_upnp.c
    1.13 -	
    1.14 +
    1.15 +EXTRA_libgmythupnp_la_SOURCES = gmyth_upnp_marshal.list
    1.16 +
    1.17 +gmyth_upnp_marshal.h: gmyth_upnp_marshal.list
    1.18 +	glib-genmarshal --header --prefix=gmyth_upnp_marshal gmyth_upnp_marshal.list > gmyth_upnp_marshal.h.tmp
    1.19 +	mv gmyth_upnp_marshal.h.tmp gmyth_upnp_marshal.h
    1.20 +
    1.21 +gmyth_upnp_marshal.c: gmyth_upnp_marshal.list gmyth_upnp_marshal.h
    1.22 +	echo "#include \"glib-object.h\"" > gmyth_upnp_marshal.c.tmp
    1.23 +	echo "#include \"gmyth_upnp_marshal.h\"" >> gmyth_upnp_marshal.c.tmp
    1.24 +	glib-genmarshal --body --prefix=gmyth_upnp_marshal $(srcdir)/gmyth_upnp_marshal.list >> gmyth_upnp_marshal.c.tmp
    1.25 +	mv gmyth_upnp_marshal.c.tmp gmyth_upnp_marshal.c
    1.26 +
    1.27  libgmythupnp_la_CFLAGS = 			\
    1.28  	-DDATADIR=\"$(pkgdatadir)\" 	\
    1.29  	$(LIBGMYTH_CFLAGS)			\
     2.1 --- a/gmyth-upnp/src/gmyth_upnp.c	Fri May 18 23:29:00 2007 +0100
     2.2 +++ b/gmyth-upnp/src/gmyth_upnp.c	Tue May 22 19:14:37 2007 +0100
     2.3 @@ -32,6 +32,7 @@
     2.4  #endif
     2.5  
     2.6  #include "gmyth_upnp.h"
     2.7 +#include "gmyth_upnp_marshal.h"
     2.8  
     2.9  #include <arpa/inet.h>
    2.10  #include <sys/types.h>
    2.11 @@ -45,48 +46,83 @@
    2.12  #include <gmyth/gmyth_uri.h>
    2.13  #include <gmyth/gmyth_debug.h>
    2.14  
    2.15 +/* Maximum number of searches in the synchronized search */
    2.16  #define GMYTH_UPNP_MAX_SEARCHS		10
    2.17  
    2.18 +#define GMYTH_UPNP_GET_PRIVATE(obj) \
    2.19 +    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GMYTH_UPNP_TYPE, GMythUPnPPrivate))
    2.20 +
    2.21 +struct _GMythUPnPPrivate {
    2.22 +	GHashTable *mythtv_servers;
    2.23 +	GMythUPnPDeviceStatus last_status;
    2.24 +	gboolean upnp_dev_found;
    2.25 +	gchar *udn;
    2.26 +	GMutex *mutex;
    2.27 +};
    2.28 +
    2.29  static void gmyth_upnp_class_init          (GMythUPnPClass *klass);
    2.30  static void gmyth_upnp_init                (GMythUPnP *object);
    2.31  
    2.32  static void gmyth_upnp_dispose  (GObject *object);
    2.33  static void gmyth_upnp_finalize (GObject *object);
    2.34  
    2.35 -static gboolean gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info );
    2.36 +static void _mythtv_device_found ( GMythUPnPDeviceStatus status, gchar *dev );
    2.37 +static void _clinkc_mythtv_device_found ( gchar *udn, GMythUPnPDeviceStatus status );
    2.38  
    2.39 -static gboolean gmyth_upnp_print_cp_device_list( CgUpnpControlPoint* controlPt, gchar **udn, 
    2.40 -						GList **mythtv_servers_lst );
    2.41 +static gboolean gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info,
    2.42 +		GMythUPnPDeviceListener listener);
    2.43 +
    2.44 +static gboolean gmyth_upnp_got_mythtv_service( CgUpnpControlPoint* controlPt, gchar **udn, 
    2.45 +						GHashTable **mythtv_servers_lst );
    2.46  
    2.47  G_DEFINE_TYPE(GMythUPnP, gmyth_upnp, G_TYPE_OBJECT)
    2.48  
    2.49 -static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
    2.50 +static GMythUPnP *gmyth_upnp_static = NULL;
    2.51  
    2.52  static void
    2.53  gmyth_upnp_class_init (GMythUPnPClass *klass)
    2.54  {
    2.55  	GObjectClass *gobject_class;
    2.56 +	GMythUPnPClass *gupnp_class;
    2.57  
    2.58  	gobject_class = (GObjectClass *) klass;
    2.59 +	gupnp_class = (GMythUPnPClass*) gobject_class;
    2.60  
    2.61  	gobject_class->dispose  = gmyth_upnp_dispose;
    2.62 -	gobject_class->finalize = gmyth_upnp_finalize;	
    2.63 +	gobject_class->finalize = gmyth_upnp_finalize;
    2.64 +	
    2.65 +	g_type_class_add_private( gobject_class, sizeof( GMythUPnPPrivate ) );
    2.66 +
    2.67 +	gupnp_class->device_found_handler = _mythtv_device_found;
    2.68 +
    2.69 +	gupnp_class->device_found_handler_signal_id =
    2.70 +		g_signal_new ("device-found",
    2.71 +				G_TYPE_FROM_CLASS (gupnp_class),
    2.72 +				G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE |
    2.73 +				G_SIGNAL_NO_HOOKS, 0, NULL, NULL,
    2.74 +				gmyth_upnp_marshal_VOID__INT_STRING, G_TYPE_NONE, 2,
    2.75 +				G_TYPE_INT, G_TYPE_STRING);
    2.76 +
    2.77  }
    2.78  
    2.79  static void
    2.80  gmyth_upnp_init ( GMythUPnP *gmyth_upnp )
    2.81  {
    2.82 -	gmyth_upnp->upnp_dev_found = FALSE;
    2.83 -	
    2.84 -	gmyth_upnp->uri = NULL;
    2.85 -	gmyth_upnp->host = NULL;
    2.86 -	gmyth_upnp->port = 0;
    2.87 -	gmyth_upnp->protocol = NULL;
    2.88 -	
    2.89 -	gmyth_upnp->gmyth_backend_info = NULL;
    2.90 -	
    2.91 +
    2.92 +	gmyth_upnp->backend_info = NULL;
    2.93 +
    2.94  	gmyth_upnp->control_point = NULL;
    2.95 -	
    2.96 +
    2.97 +	gmyth_upnp->priv = GMYTH_UPNP_GET_PRIVATE(gmyth_upnp);
    2.98 +	gmyth_upnp->priv->mutex = g_mutex_new ();
    2.99 +	gmyth_upnp->priv->upnp_dev_found = FALSE;
   2.100 +
   2.101 +	g_signal_connect (G_OBJECT (gmyth_upnp), "device-found",
   2.102 +			(GCallback) (GMYTH_UPNP_GET_CLASS (gmyth_upnp)->
   2.103 +				device_found_handler), NULL);
   2.104 +
   2.105 +	gmyth_upnp_static = gmyth_upnp;
   2.106 +
   2.107  }
   2.108  
   2.109  /** Creates a new instance of GMythUPnP.
   2.110 @@ -94,14 +130,18 @@
   2.111   * @return a new instance of GMythUPnP. 
   2.112   */
   2.113  GMythUPnP *
   2.114 -gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info ) 
   2.115 +gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info, GMythUPnPDeviceListener handler ) 
   2.116  {
   2.117      GMythUPnP *gmyth_upnp = GMYTH_UPNP (g_object_new (GMYTH_UPNP_TYPE, NULL));
   2.118      
   2.119 -    gmyth_upnp->gmyth_backend_info = gmyth_backend_info;
   2.120 -    
   2.121 -    if ( !gmyth_upnp_initialize ( gmyth_upnp, gmyth_backend_info ) )
   2.122 -    	return NULL;
   2.123 +    g_object_ref( gmyth_backend_info );
   2.124 +
   2.125 +    gmyth_upnp->backend_info = gmyth_backend_info;
   2.126 +
   2.127 +    if ( !gmyth_upnp_initialize ( gmyth_upnp, gmyth_backend_info, handler ) )
   2.128 +    {
   2.129 +    	gmyth_debug( "Error initializing the GMythUPnP!!!" );
   2.130 +    }
   2.131      
   2.132      return gmyth_upnp;
   2.133  }
   2.134 @@ -116,27 +156,17 @@
   2.135  		cg_upnp_controlpoint_delete( gmyth_upnp->control_point );
   2.136  		gmyth_upnp->control_point = NULL;
   2.137  	}
   2.138 +	
   2.139 +	if ( gmyth_upnp->priv->mythtv_servers != NULL )	{
   2.140 +		g_hash_table_destroy( gmyth_upnp->priv->mythtv_servers );
   2.141 +		gmyth_upnp->priv->mythtv_servers = NULL;
   2.142 +	}
   2.143  
   2.144 -	if ( gmyth_upnp->uri != NULL ) {
   2.145 -		g_free ( gmyth_upnp->uri );
   2.146 -		gmyth_upnp->uri = NULL;
   2.147 +	if ( gmyth_upnp->backend_info != NULL )	{
   2.148 +		g_object_unref( gmyth_upnp->backend_info );
   2.149 +		gmyth_upnp->backend_info = NULL;
   2.150  	}
   2.151 -	
   2.152 -	if ( gmyth_upnp->host != NULL ) {
   2.153 -		g_free ( gmyth_upnp->host );
   2.154 -		gmyth_upnp->host = NULL;
   2.155 -	}
   2.156 -	
   2.157 -	if ( gmyth_upnp->protocol != NULL ) {
   2.158 -		g_free ( gmyth_upnp->protocol );
   2.159 -		gmyth_upnp->protocol = NULL;
   2.160 -	}
   2.161 -	
   2.162 -	if ( gmyth_upnp->mythtv_servers != NULL )	{
   2.163 -		g_list_free( gmyth_upnp->mythtv_servers );
   2.164 -		gmyth_upnp->mythtv_servers = NULL;
   2.165 -	}
   2.166 -	
   2.167 +
   2.168  	G_OBJECT_CLASS (gmyth_upnp_parent_class)->dispose (object);
   2.169  }
   2.170  
   2.171 @@ -149,103 +179,139 @@
   2.172  }
   2.173  
   2.174  /**
   2.175 + * GObject's signal handler
   2.176 + */ 
   2.177 +static void
   2.178 +_mythtv_device_found( GMythUPnPDeviceStatus status, gchar* udn )
   2.179 +{
   2.180 +	g_debug( "status = %d, UDN = %s\n", status, udn );
   2.181 +}
   2.182 +
   2.183 +/**
   2.184 + * GObject's signal handler
   2.185 + */
   2.186 +static void 
   2.187 +_clinkc_mythtv_device_found ( gchar *udn, GMythUPnPDeviceStatus status )
   2.188 +{
   2.189 +	if ( gmyth_upnp_static != NULL )
   2.190 +		g_signal_emit ( gmyth_upnp_static, 
   2.191 +			GMYTH_UPNP_GET_CLASS (gmyth_upnp_static)->device_found_handler_signal_id, 0, /* details */
   2.192 +			status, udn );
   2.193 +}
   2.194 +
   2.195 +/**
   2.196   * Create a control point and start it.
   2.197   */
   2.198  static gboolean
   2.199 -gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info )
   2.200 +gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info, 
   2.201 +	GMythUPnPDeviceListener device_found_handler )
   2.202  {
   2.203 -	
   2.204 -	gboolean ret = FALSE;
   2.205 -	
   2.206 -	GMythURI* uri = NULL;
   2.207 -	
   2.208 -	guint iter_count = GMYTH_UPNP_MAX_SEARCHS;
   2.209 -	
   2.210 +	gboolean ret = TRUE;
   2.211 +
   2.212  	g_return_val_if_fail( gmyth_backend_info != NULL, FALSE );
   2.213 -	
   2.214 +
   2.215  	/* Create the cybergarage control point */
   2.216  	gmyth_upnp->control_point = cg_upnp_controlpoint_new();
   2.217 -	/* cg_upnp_controlpoint_setdevicelistener( gmyth_upnp->control_point, device_listener ); */
   2.218 -	
   2.219 +
   2.220 +	if ( device_found_handler != NULL )
   2.221 +	{
   2.222 +		GMYTH_UPNP_GET_CLASS(gmyth_upnp)->device_found_handler = device_found_handler; 
   2.223 +
   2.224 +		cg_upnp_controlpoint_setdevicelistener( gmyth_upnp->control_point, _clinkc_mythtv_device_found );
   2.225 +	}
   2.226 +
   2.227  	/* Start the control point */
   2.228 -  if ( cg_upnp_controlpoint_start( gmyth_upnp->control_point ) == FALSE)
   2.229 +	if ( cg_upnp_controlpoint_start( gmyth_upnp->control_point ) == FALSE)
   2.230  	{
   2.231 -	  gmyth_debug( "Unable to start UPnP control point!!!" );
   2.232 -	  goto done;
   2.233 -  }
   2.234 +		gmyth_debug( "Unable to start UPnP control point!!!" );
   2.235 +		ret = FALSE;
   2.236 +		goto done;
   2.237 +	}
   2.238  	else
   2.239  	{
   2.240 -    gmyth_debug( "Control point started." );
   2.241 +		gmyth_debug( "Control point started." );
   2.242  	}
   2.243 -	
   2.244 -	while ( gmyth_upnp->upnp_dev_found == FALSE && ( --iter_count > 0 ) ) {
   2.245 -		
   2.246 +
   2.247 +done:
   2.248 +
   2.249 +	return ret;
   2.250 +}
   2.251 +
   2.252 +static void
   2.253 +_gmyth_foreach_key_value( gchar *udn, gchar *dev, GList *upnp_servers_list )
   2.254 +{
   2.255 +	GMythUPnPDevice *gmyth_upnp = g_malloc0( sizeof( GMythUPnPDevice ) );
   2.256 +
   2.257 +	GMythURI* uri = NULL;
   2.258 +	gmyth_upnp->uri = (gchar*) (dev);
   2.259 +	uri = gmyth_uri_new_with_value( gmyth_upnp->uri );
   2.260 +
   2.261 +	gmyth_upnp->host = gmyth_uri_get_host( uri );
   2.262 +	gmyth_upnp->port = gmyth_uri_get_port( uri );
   2.263 +	gmyth_upnp->protocol = gmyth_uri_get_protocol( uri );
   2.264 +
   2.265 +	upnp_servers_list = g_list_append( upnp_servers_list, gmyth_upnp );
   2.266 +
   2.267 +	if ( uri != NULL )
   2.268 +	{
   2.269 +		g_object_unref( uri );
   2.270 +		uri = NULL;
   2.271 +	}
   2.272 +
   2.273 +}
   2.274 +
   2.275 +GList *
   2.276 +gmyth_upnp_do_search_sync( GMythUPnP* gmyth_upnp )
   2.277 +{
   2.278 +	GList *upnp_servers_list = NULL;
   2.279 +	guint iter_count = GMYTH_UPNP_MAX_SEARCHS;
   2.280 +	/* gmyth_upnp->priv = GMYTH_UPNP_GET_PRIVATE( gmyth_upnp ); */
   2.281 +
   2.282 +	while ( gmyth_upnp->priv->upnp_dev_found == FALSE && ( --iter_count > 0 ) ) {
   2.283 +
   2.284  		gmyth_debug( "UPnP MythTV Client control point is searching MythTV AV Device server...\n" );
   2.285 -       
   2.286 +
   2.287  		if ( gmyth_upnp->control_point != NULL )
   2.288  			cg_upnp_controlpoint_search ( gmyth_upnp->control_point, 
   2.289 -		        		"urn:schemas-upnp-org:service:ContentDirectory:1" );
   2.290 +					"urn:schemas-upnp-org:service:ContentDirectory:1" );
   2.291  
   2.292  		/* just to avoid clinkc pthread concurrency faults */
   2.293  		cg_wait( 1000 );
   2.294 -		
   2.295 +
   2.296  		/* discover if it was found */
   2.297 -		gmyth_upnp->upnp_dev_found = gmyth_upnp_print_cp_device_list( gmyth_upnp->control_point, &gmyth_upnp->udn,
   2.298 -									&gmyth_upnp->mythtv_servers );
   2.299 -		
   2.300 -	}
   2.301 -	
   2.302 -	if ( gmyth_upnp->upnp_dev_found ) {
   2.303 -		
   2.304 +		gmyth_upnp->priv->upnp_dev_found = gmyth_upnp_got_mythtv_service( gmyth_upnp->control_point, &gmyth_upnp->priv->udn,
   2.305 +				&gmyth_upnp->priv->mythtv_servers );
   2.306 +
   2.307 +	} /* while */
   2.308 +
   2.309 +	if ( gmyth_upnp->priv->upnp_dev_found ) {
   2.310 +
   2.311  		gmyth_debug( "Found UPnP MythTV AV Device...\n" );
   2.312 -		
   2.313 -		if ( g_list_first( gmyth_upnp->mythtv_servers ) != NULL && (g_list_first( gmyth_upnp->mythtv_servers ))->data != NULL )
   2.314 -		{
   2.315 -			gmyth_upnp->uri = (gchar*) (g_list_first( gmyth_upnp->mythtv_servers ))->data;
   2.316 -			uri = gmyth_uri_new_with_value( gmyth_upnp->uri );
   2.317 -			
   2.318 -			gmyth_upnp->host = gmyth_uri_get_host( uri );
   2.319 -			gmyth_upnp->port = gmyth_uri_get_port( uri );
   2.320 -			gmyth_upnp->protocol = gmyth_uri_get_protocol( uri );
   2.321 -			
   2.322 -			/* sets all the discovered data from the UPnP remote device, like host name, IP address, port,... */
   2.323 -			if ( NULL != gmyth_upnp->host )
   2.324 -				gmyth_backend_info_set_hostname ( gmyth_upnp->gmyth_backend_info, gmyth_upnp->host );
   2.325 -			
   2.326 -			if ( gmyth_upnp->port > 0 )
   2.327 -				 gmyth_backend_info_set_port ( gmyth_upnp->gmyth_backend_info, gmyth_upnp->port );
   2.328 -				 
   2.329 -			ret = TRUE;
   2.330 -		}
   2.331 -	}	
   2.332  
   2.333 -done:
   2.334 +		g_hash_table_foreach( gmyth_upnp->priv->mythtv_servers, (GHFunc)_gmyth_foreach_key_value, upnp_servers_list );
   2.335  
   2.336 -  if ( uri != NULL )
   2.337 -  {
   2.338 -  	g_object_unref( uri );
   2.339 -  	uri = NULL;
   2.340 -  }  	
   2.341 +	} /* if - found UPnP device  */
   2.342  
   2.343 -	return ret;
   2.344 -	
   2.345 +	return upnp_servers_list;
   2.346  }
   2.347  
   2.348  /** 
   2.349 - * Prints the Control Point's device list
   2.350 + * Checks if got the MythTV service in the Control Point's device list.
   2.351   */
   2.352  static gboolean
   2.353 -gmyth_upnp_print_cp_device_list( CgUpnpControlPoint* controlPt, gchar **udn, GList **mythtv_servers_lst )
   2.354 +gmyth_upnp_got_mythtv_service( CgUpnpControlPoint* controlPt, gchar **udn, 
   2.355 +	GHashTable **mythtv_servers_lst )
   2.356  {
   2.357  	
   2.358  	g_return_val_if_fail( mythtv_servers_lst != NULL, FALSE );	
   2.359  	g_return_val_if_fail( controlPt != NULL, FALSE );
   2.360 +
   2.361 +	*mythtv_servers_lst = g_hash_table_new( g_str_hash, g_str_equal );
   2.362  	
   2.363  	gchar* mythtvFriendlyName = "Myth";
   2.364  	/* begin assertion about the size of discovered devices */
   2.365  	gint numDevices = cg_upnp_controlpoint_getndevices(controlPt);
   2.366  	gint cntDevs = 0;	
   2.367 -	//CgUpnpDeviceList *devList = NULL;
   2.368  	CgUpnpDevice *childDev;
   2.369  	gchar *devName = NULL, *dev_url = NULL;
   2.370  	gboolean upnp_dev_found = FALSE;
   2.371 @@ -259,8 +325,10 @@
   2.372  		gmyth_debug( "Device's friendly name = %s, and  device's URL = %s\n", devName, dev_url );
   2.373  		if ( ( upnp_dev_found = ( g_strstr_len( devName, strlen( devName ), mythtvFriendlyName ) != NULL ) ) == TRUE ) 
   2.374  		{
   2.375 +			/* stores the last UDN number ID */
   2.376  			*udn = cg_upnp_device_getudn( childDev );
   2.377 -			*mythtv_servers_lst = g_list_append( *mythtv_servers_lst, dev_url ); 
   2.378 +			/* *mythtv_servers_lst = g_list_append( *mythtv_servers_lst, dev_url );  */
   2.379 +			g_hash_table_insert( *mythtv_servers_lst, (gpointer)*udn, (gpointer)dev_url );
   2.380  		}
   2.381  		++cntDevs;
   2.382  	}
   2.383 @@ -277,57 +345,22 @@
   2.384  
   2.385  }
   2.386  
   2.387 -/** Gets the GMythBackendInfo host object associated to this upnp.
   2.388 - * 
   2.389 - * @return The string host object currently valid or NULL if the settings
   2.390 - * were not opened.
   2.391 - */
   2.392 -gchar*
   2.393 -gmyth_upnp_get_host ( GMythUPnP *gmyth_upnp )
   2.394 -{
   2.395 -	
   2.396 -	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->host ) 
   2.397 -	{
   2.398 -		gmyth_debug ("[%s] GMythUPnP host field not initialized\n", __FUNCTION__);
   2.399 -		return NULL;
   2.400 -	}
   2.401 -
   2.402 -	return gmyth_upnp->host;
   2.403 -}
   2.404 -
   2.405 -/** Gets the GMythBackendInfo port object associated to this upnp.
   2.406 - * 
   2.407 - * @return The string object currently valid or NULL if the port number.
   2.408 - */
   2.409 -gint
   2.410 -gmyth_upnp_get_port( GMythUPnP *gmyth_upnp )
   2.411 -{
   2.412 -
   2.413 -	if ( NULL == gmyth_upnp || gmyth_upnp->port <= 0 ) 
   2.414 -	{
   2.415 -		gmyth_debug ("[%s] GMythUPnP host field not initialized\n", __FUNCTION__);
   2.416 -		return 0;
   2.417 -	}
   2.418 -
   2.419 -	return gmyth_upnp->port;
   2.420 -}
   2.421 -
   2.422  /** Gets the UPnP AV devices server's list associated to this upnp.
   2.423   * 
   2.424 - * @return The GList* containing all the URI values for each recognized UPnP device,
   2.425 + * @return The GHashTable* containing all the URI values for each recognized UPnP device,
   2.426   * 			or NULL if it couldn't recognize any MythTV AV device.
   2.427   */
   2.428 -GList*
   2.429 +GHashTable*
   2.430  gmyth_upnp_get_servers ( GMythUPnP *gmyth_upnp )
   2.431  {
   2.432  	
   2.433 -	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->mythtv_servers ) 
   2.434 +	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->priv->mythtv_servers ) 
   2.435  	{
   2.436  		gmyth_debug ("[%s] GMythUPnP has no MythTV servers recognized.\n", __FUNCTION__);
   2.437  		return NULL;
   2.438  	}
   2.439  
   2.440 -	return gmyth_upnp->mythtv_servers;
   2.441 +	return gmyth_upnp->priv->mythtv_servers;
   2.442  }
   2.443  
   2.444  /** Gets the GMythBackendInfo object associated to this upnp.
   2.445 @@ -339,12 +372,12 @@
   2.446  gmyth_upnp_get_backend_info ( GMythUPnP *gmyth_upnp )
   2.447  {
   2.448  	
   2.449 -	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->gmyth_backend_info ) 
   2.450 +	if ( NULL == gmyth_upnp || NULL == gmyth_upnp->backend_info ) 
   2.451  	{
   2.452  		gmyth_debug ("[%s] GMythUPnP not initialized\n", __FUNCTION__);
   2.453  		return NULL;
   2.454  	}
   2.455  
   2.456 -	return gmyth_upnp->gmyth_backend_info;
   2.457 +	return gmyth_upnp->backend_info;
   2.458  }
   2.459  
     3.1 --- a/gmyth-upnp/src/gmyth_upnp.h	Fri May 18 23:29:00 2007 +0100
     3.2 +++ b/gmyth-upnp/src/gmyth_upnp.h	Tue May 22 19:14:37 2007 +0100
     3.3 @@ -51,45 +51,62 @@
     3.4  
     3.5  typedef struct _GMythUPnP         GMythUPnP;
     3.6  typedef struct _GMythUPnPClass    GMythUPnPClass;
     3.7 +typedef struct _GMythUPnPPrivate  GMythUPnPPrivate;
     3.8  
     3.9  /****************************************
    3.10  * Data Type
    3.11  ****************************************/
    3.12  
    3.13 +typedef enum upnp_device_list_status {
    3.14 +	GMYTH_UPNP_DEVICE_ADDED = 0,
    3.15 +	GMYTH_UPNP_DEVICE_REMOVED,
    3.16 +	GMYTH_UPNP_DEVICE_UPDATED
    3.17 +} GMythUPnPDeviceStatus;
    3.18 +
    3.19 +typedef void (*GMythUPnPDeviceListener) ( GMythUPnPDeviceStatus status, gchar *dev );
    3.20 +
    3.21  struct _GMythUPnPClass
    3.22  {
    3.23 -  GObjectClass parent_class;
    3.24 +	GObjectClass parent_class;
    3.25  
    3.26 -  /* callbacks */
    3.27 -  /* no one for now */
    3.28 +	/* callbacks */
    3.29 +	guint device_found_handler_signal_id;
    3.30 +
    3.31 +	GMythUPnPDeviceListener device_found_handler;
    3.32 +
    3.33 +	/* no one for now */
    3.34  };
    3.35  
    3.36 +struct _GMythUPnPDevice {
    3.37 +	gchar *uri;
    3.38 +	gchar *host;
    3.39 +	gint port;
    3.40 +	gchar *protocol;
    3.41 +};
    3.42 +
    3.43 +typedef struct _GMythUPnPDevice GMythUPnPDevice;
    3.44 +
    3.45  struct _GMythUPnP {
    3.46  	
    3.47  	GObject parent;
    3.48 +	GMythUPnPPrivate *priv;
    3.49  	
    3.50 -	gchar *uri;
    3.51 -	gchar *host;
    3.52 -	gint port;
    3.53 -	gchar *protocol;
    3.54 -	
    3.55 +
    3.56  	CgUpnpControlPoint* control_point;
    3.57  	
    3.58  	gchar *udn;
    3.59  	
    3.60 -	GMythBackendInfo *gmyth_backend_info;
    3.61 -	
    3.62 -	GList* mythtv_servers;
    3.63 -	
    3.64 +	GMythBackendInfo *backend_info;
    3.65 +
    3.66  	gboolean upnp_dev_found;
    3.67 -	
    3.68  };
    3.69  
    3.70  GType       			gmyth_upnp_get_type (void);
    3.71 -GMythUPnP *				gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info );
    3.72 -gchar*						gmyth_upnp_get_host ( GMythUPnP *gmyth_upnp );
    3.73 -gint							gmyth_upnp_get_port ( GMythUPnP *gmyth_upnp );
    3.74 -GMythBackendInfo*	gmyth_upnp_get_backend_info ( GMythUPnP *gmyth_upnp );
    3.75 +GMythUPnP *			gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info, 
    3.76 +						GMythUPnPDeviceListener handler );
    3.77 +gchar*				gmyth_upnp_get_host ( GMythUPnP *gmyth_upnp );
    3.78 +gint				gmyth_upnp_get_port ( GMythUPnP *gmyth_upnp );
    3.79 +GMythBackendInfo*		gmyth_upnp_get_backend_info ( GMythUPnP *gmyth_upnp );
    3.80  
    3.81  G_END_DECLS
    3.82  
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/gmyth-upnp/src/gmyth_upnp_marshal.list	Tue May 22 19:14:37 2007 +0100
     4.3 @@ -0,0 +1,2 @@
     4.4 +VOID:INT,STRING
     4.5 +VOID:INT,POINTER