1.1 --- a/gmyth-upnp/src/gmyth_upnp.c Wed Jan 10 23:23:54 2007 +0000
1.2 +++ b/gmyth-upnp/src/gmyth_upnp.c Tue May 22 19:14:37 2007 +0100
1.3 @@ -32,6 +32,7 @@
1.4 #endif
1.5
1.6 #include "gmyth_upnp.h"
1.7 +#include "gmyth_upnp_marshal.h"
1.8
1.9 #include <arpa/inet.h>
1.10 #include <sys/types.h>
1.11 @@ -45,48 +46,83 @@
1.12 #include <gmyth/gmyth_uri.h>
1.13 #include <gmyth/gmyth_debug.h>
1.14
1.15 +/* Maximum number of searches in the synchronized search */
1.16 #define GMYTH_UPNP_MAX_SEARCHS 10
1.17
1.18 +#define GMYTH_UPNP_GET_PRIVATE(obj) \
1.19 + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GMYTH_UPNP_TYPE, GMythUPnPPrivate))
1.20 +
1.21 +struct _GMythUPnPPrivate {
1.22 + GHashTable *mythtv_servers;
1.23 + GMythUPnPDeviceStatus last_status;
1.24 + gboolean upnp_dev_found;
1.25 + gchar *udn;
1.26 + GMutex *mutex;
1.27 +};
1.28 +
1.29 static void gmyth_upnp_class_init (GMythUPnPClass *klass);
1.30 static void gmyth_upnp_init (GMythUPnP *object);
1.31
1.32 static void gmyth_upnp_dispose (GObject *object);
1.33 static void gmyth_upnp_finalize (GObject *object);
1.34
1.35 -static gboolean gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info );
1.36 +static void _mythtv_device_found ( GMythUPnPDeviceStatus status, gchar *dev );
1.37 +static void _clinkc_mythtv_device_found ( gchar *udn, GMythUPnPDeviceStatus status );
1.38
1.39 -static gboolean gmyth_upnp_print_cp_device_list( CgUpnpControlPoint* controlPt, gchar **udn,
1.40 - GList **mythtv_servers_lst );
1.41 +static gboolean gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info,
1.42 + GMythUPnPDeviceListener listener);
1.43 +
1.44 +static gboolean gmyth_upnp_got_mythtv_service( CgUpnpControlPoint* controlPt, gchar **udn,
1.45 + GHashTable **mythtv_servers_lst );
1.46
1.47 G_DEFINE_TYPE(GMythUPnP, gmyth_upnp, G_TYPE_OBJECT)
1.48
1.49 -static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
1.50 +static GMythUPnP *gmyth_upnp_static = NULL;
1.51
1.52 static void
1.53 gmyth_upnp_class_init (GMythUPnPClass *klass)
1.54 {
1.55 GObjectClass *gobject_class;
1.56 + GMythUPnPClass *gupnp_class;
1.57
1.58 gobject_class = (GObjectClass *) klass;
1.59 + gupnp_class = (GMythUPnPClass*) gobject_class;
1.60
1.61 gobject_class->dispose = gmyth_upnp_dispose;
1.62 - gobject_class->finalize = gmyth_upnp_finalize;
1.63 + gobject_class->finalize = gmyth_upnp_finalize;
1.64 +
1.65 + g_type_class_add_private( gobject_class, sizeof( GMythUPnPPrivate ) );
1.66 +
1.67 + gupnp_class->device_found_handler = _mythtv_device_found;
1.68 +
1.69 + gupnp_class->device_found_handler_signal_id =
1.70 + g_signal_new ("device-found",
1.71 + G_TYPE_FROM_CLASS (gupnp_class),
1.72 + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE |
1.73 + G_SIGNAL_NO_HOOKS, 0, NULL, NULL,
1.74 + gmyth_upnp_marshal_VOID__INT_STRING, G_TYPE_NONE, 2,
1.75 + G_TYPE_INT, G_TYPE_STRING);
1.76 +
1.77 }
1.78
1.79 static void
1.80 gmyth_upnp_init ( GMythUPnP *gmyth_upnp )
1.81 {
1.82 - gmyth_upnp->upnp_dev_found = FALSE;
1.83 -
1.84 - gmyth_upnp->uri = NULL;
1.85 - gmyth_upnp->host = NULL;
1.86 - gmyth_upnp->port = 0;
1.87 - gmyth_upnp->protocol = NULL;
1.88 -
1.89 - gmyth_upnp->gmyth_backend_info = NULL;
1.90 -
1.91 +
1.92 + gmyth_upnp->backend_info = NULL;
1.93 +
1.94 gmyth_upnp->control_point = NULL;
1.95 -
1.96 +
1.97 + gmyth_upnp->priv = GMYTH_UPNP_GET_PRIVATE(gmyth_upnp);
1.98 + gmyth_upnp->priv->mutex = g_mutex_new ();
1.99 + gmyth_upnp->priv->upnp_dev_found = FALSE;
1.100 +
1.101 + g_signal_connect (G_OBJECT (gmyth_upnp), "device-found",
1.102 + (GCallback) (GMYTH_UPNP_GET_CLASS (gmyth_upnp)->
1.103 + device_found_handler), NULL);
1.104 +
1.105 + gmyth_upnp_static = gmyth_upnp;
1.106 +
1.107 }
1.108
1.109 /** Creates a new instance of GMythUPnP.
1.110 @@ -94,14 +130,18 @@
1.111 * @return a new instance of GMythUPnP.
1.112 */
1.113 GMythUPnP *
1.114 -gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info )
1.115 +gmyth_upnp_new ( GMythBackendInfo *gmyth_backend_info, GMythUPnPDeviceListener handler )
1.116 {
1.117 GMythUPnP *gmyth_upnp = GMYTH_UPNP (g_object_new (GMYTH_UPNP_TYPE, NULL));
1.118
1.119 - gmyth_upnp->gmyth_backend_info = gmyth_backend_info;
1.120 -
1.121 - if ( !gmyth_upnp_initialize ( gmyth_upnp, gmyth_backend_info ) )
1.122 - return NULL;
1.123 + g_object_ref( gmyth_backend_info );
1.124 +
1.125 + gmyth_upnp->backend_info = gmyth_backend_info;
1.126 +
1.127 + if ( !gmyth_upnp_initialize ( gmyth_upnp, gmyth_backend_info, handler ) )
1.128 + {
1.129 + gmyth_debug( "Error initializing the GMythUPnP!!!" );
1.130 + }
1.131
1.132 return gmyth_upnp;
1.133 }
1.134 @@ -116,27 +156,17 @@
1.135 cg_upnp_controlpoint_delete( gmyth_upnp->control_point );
1.136 gmyth_upnp->control_point = NULL;
1.137 }
1.138 +
1.139 + if ( gmyth_upnp->priv->mythtv_servers != NULL ) {
1.140 + g_hash_table_destroy( gmyth_upnp->priv->mythtv_servers );
1.141 + gmyth_upnp->priv->mythtv_servers = NULL;
1.142 + }
1.143
1.144 - if ( gmyth_upnp->uri != NULL ) {
1.145 - g_free ( gmyth_upnp->uri );
1.146 - gmyth_upnp->uri = NULL;
1.147 + if ( gmyth_upnp->backend_info != NULL ) {
1.148 + g_object_unref( gmyth_upnp->backend_info );
1.149 + gmyth_upnp->backend_info = NULL;
1.150 }
1.151 -
1.152 - if ( gmyth_upnp->host != NULL ) {
1.153 - g_free ( gmyth_upnp->host );
1.154 - gmyth_upnp->host = NULL;
1.155 - }
1.156 -
1.157 - if ( gmyth_upnp->protocol != NULL ) {
1.158 - g_free ( gmyth_upnp->protocol );
1.159 - gmyth_upnp->protocol = NULL;
1.160 - }
1.161 -
1.162 - if ( gmyth_upnp->mythtv_servers != NULL ) {
1.163 - g_list_free( gmyth_upnp->mythtv_servers );
1.164 - gmyth_upnp->mythtv_servers = NULL;
1.165 - }
1.166 -
1.167 +
1.168 G_OBJECT_CLASS (gmyth_upnp_parent_class)->dispose (object);
1.169 }
1.170
1.171 @@ -149,103 +179,139 @@
1.172 }
1.173
1.174 /**
1.175 + * GObject's signal handler
1.176 + */
1.177 +static void
1.178 +_mythtv_device_found( GMythUPnPDeviceStatus status, gchar* udn )
1.179 +{
1.180 + g_debug( "status = %d, UDN = %s\n", status, udn );
1.181 +}
1.182 +
1.183 +/**
1.184 + * GObject's signal handler
1.185 + */
1.186 +static void
1.187 +_clinkc_mythtv_device_found ( gchar *udn, GMythUPnPDeviceStatus status )
1.188 +{
1.189 + if ( gmyth_upnp_static != NULL )
1.190 + g_signal_emit ( gmyth_upnp_static,
1.191 + GMYTH_UPNP_GET_CLASS (gmyth_upnp_static)->device_found_handler_signal_id, 0, /* details */
1.192 + status, udn );
1.193 +}
1.194 +
1.195 +/**
1.196 * Create a control point and start it.
1.197 */
1.198 static gboolean
1.199 -gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info )
1.200 +gmyth_upnp_initialize ( GMythUPnP *gmyth_upnp, GMythBackendInfo *gmyth_backend_info,
1.201 + GMythUPnPDeviceListener device_found_handler )
1.202 {
1.203 -
1.204 - gboolean ret = FALSE;
1.205 -
1.206 - GMythURI* uri = NULL;
1.207 -
1.208 - guint iter_count = GMYTH_UPNP_MAX_SEARCHS;
1.209 -
1.210 + gboolean ret = TRUE;
1.211 +
1.212 g_return_val_if_fail( gmyth_backend_info != NULL, FALSE );
1.213 -
1.214 +
1.215 /* Create the cybergarage control point */
1.216 gmyth_upnp->control_point = cg_upnp_controlpoint_new();
1.217 - /* cg_upnp_controlpoint_setdevicelistener( gmyth_upnp->control_point, device_listener ); */
1.218 -
1.219 +
1.220 + if ( device_found_handler != NULL )
1.221 + {
1.222 + GMYTH_UPNP_GET_CLASS(gmyth_upnp)->device_found_handler = device_found_handler;
1.223 +
1.224 + cg_upnp_controlpoint_setdevicelistener( gmyth_upnp->control_point, _clinkc_mythtv_device_found );
1.225 + }
1.226 +
1.227 /* Start the control point */
1.228 - if ( cg_upnp_controlpoint_start( gmyth_upnp->control_point ) == FALSE)
1.229 + if ( cg_upnp_controlpoint_start( gmyth_upnp->control_point ) == FALSE)
1.230 {
1.231 - gmyth_debug( "Unable to start UPnP control point!!!" );
1.232 - goto done;
1.233 - }
1.234 + gmyth_debug( "Unable to start UPnP control point!!!" );
1.235 + ret = FALSE;
1.236 + goto done;
1.237 + }
1.238 else
1.239 {
1.240 - gmyth_debug( "Control point started." );
1.241 + gmyth_debug( "Control point started." );
1.242 }
1.243 -
1.244 - while ( gmyth_upnp->upnp_dev_found == FALSE && ( --iter_count > 0 ) ) {
1.245 -
1.246 +
1.247 +done:
1.248 +
1.249 + return ret;
1.250 +}
1.251 +
1.252 +static void
1.253 +_gmyth_foreach_key_value( gchar *udn, gchar *dev, GList *upnp_servers_list )
1.254 +{
1.255 + GMythUPnPDevice *gmyth_upnp = g_malloc0( sizeof( GMythUPnPDevice ) );
1.256 +
1.257 + GMythURI* uri = NULL;
1.258 + gmyth_upnp->uri = (gchar*) (dev);
1.259 + uri = gmyth_uri_new_with_value( gmyth_upnp->uri );
1.260 +
1.261 + gmyth_upnp->host = gmyth_uri_get_host( uri );
1.262 + gmyth_upnp->port = gmyth_uri_get_port( uri );
1.263 + gmyth_upnp->protocol = gmyth_uri_get_protocol( uri );
1.264 +
1.265 + upnp_servers_list = g_list_append( upnp_servers_list, gmyth_upnp );
1.266 +
1.267 + if ( uri != NULL )
1.268 + {
1.269 + g_object_unref( uri );
1.270 + uri = NULL;
1.271 + }
1.272 +
1.273 +}
1.274 +
1.275 +GList *
1.276 +gmyth_upnp_do_search_sync( GMythUPnP* gmyth_upnp )
1.277 +{
1.278 + GList *upnp_servers_list = NULL;
1.279 + guint iter_count = GMYTH_UPNP_MAX_SEARCHS;
1.280 + /* gmyth_upnp->priv = GMYTH_UPNP_GET_PRIVATE( gmyth_upnp ); */
1.281 +
1.282 + while ( gmyth_upnp->priv->upnp_dev_found == FALSE && ( --iter_count > 0 ) ) {
1.283 +
1.284 gmyth_debug( "UPnP MythTV Client control point is searching MythTV AV Device server...\n" );
1.285 -
1.286 +
1.287 if ( gmyth_upnp->control_point != NULL )
1.288 cg_upnp_controlpoint_search ( gmyth_upnp->control_point,
1.289 - "urn:schemas-upnp-org:service:ContentDirectory:1" );
1.290 + "urn:schemas-upnp-org:service:ContentDirectory:1" );
1.291
1.292 /* just to avoid clinkc pthread concurrency faults */
1.293 cg_wait( 1000 );
1.294 -
1.295 +
1.296 /* discover if it was found */
1.297 - gmyth_upnp->upnp_dev_found = gmyth_upnp_print_cp_device_list( gmyth_upnp->control_point, &gmyth_upnp->udn,
1.298 - &gmyth_upnp->mythtv_servers );
1.299 -
1.300 - }
1.301 -
1.302 - if ( gmyth_upnp->upnp_dev_found ) {
1.303 -
1.304 + gmyth_upnp->priv->upnp_dev_found = gmyth_upnp_got_mythtv_service( gmyth_upnp->control_point, &gmyth_upnp->priv->udn,
1.305 + &gmyth_upnp->priv->mythtv_servers );
1.306 +
1.307 + } /* while */
1.308 +
1.309 + if ( gmyth_upnp->priv->upnp_dev_found ) {
1.310 +
1.311 gmyth_debug( "Found UPnP MythTV AV Device...\n" );
1.312 -
1.313 - if ( g_list_first( gmyth_upnp->mythtv_servers ) != NULL && (g_list_first( gmyth_upnp->mythtv_servers ))->data != NULL )
1.314 - {
1.315 - gmyth_upnp->uri = (gchar*) (g_list_first( gmyth_upnp->mythtv_servers ))->data;
1.316 - uri = gmyth_uri_new_with_value( gmyth_upnp->uri );
1.317 -
1.318 - gmyth_upnp->host = gmyth_uri_get_host( uri );
1.319 - gmyth_upnp->port = gmyth_uri_get_port( uri );
1.320 - gmyth_upnp->protocol = gmyth_uri_get_protocol( uri );
1.321 -
1.322 - /* sets all the discovered data from the UPnP remote device, like host name, IP address, port,... */
1.323 - if ( NULL != gmyth_upnp->host )
1.324 - gmyth_backend_info_set_hostname ( gmyth_upnp->gmyth_backend_info, gmyth_upnp->host );
1.325 -
1.326 - if ( gmyth_upnp->port > 0 )
1.327 - gmyth_backend_info_set_port ( gmyth_upnp->gmyth_backend_info, gmyth_upnp->port );
1.328 -
1.329 - ret = TRUE;
1.330 - }
1.331 - }
1.332
1.333 -done:
1.334 + g_hash_table_foreach( gmyth_upnp->priv->mythtv_servers, (GHFunc)_gmyth_foreach_key_value, upnp_servers_list );
1.335
1.336 - if ( uri != NULL )
1.337 - {
1.338 - g_object_unref( uri );
1.339 - uri = NULL;
1.340 - }
1.341 + } /* if - found UPnP device */
1.342
1.343 - return ret;
1.344 -
1.345 + return upnp_servers_list;
1.346 }
1.347
1.348 /**
1.349 - * Prints the Control Point's device list
1.350 + * Checks if got the MythTV service in the Control Point's device list.
1.351 */
1.352 static gboolean
1.353 -gmyth_upnp_print_cp_device_list( CgUpnpControlPoint* controlPt, gchar **udn, GList **mythtv_servers_lst )
1.354 +gmyth_upnp_got_mythtv_service( CgUpnpControlPoint* controlPt, gchar **udn,
1.355 + GHashTable **mythtv_servers_lst )
1.356 {
1.357
1.358 g_return_val_if_fail( mythtv_servers_lst != NULL, FALSE );
1.359 g_return_val_if_fail( controlPt != NULL, FALSE );
1.360 +
1.361 + *mythtv_servers_lst = g_hash_table_new( g_str_hash, g_str_equal );
1.362
1.363 gchar* mythtvFriendlyName = "Myth";
1.364 /* begin assertion about the size of discovered devices */
1.365 gint numDevices = cg_upnp_controlpoint_getndevices(controlPt);
1.366 gint cntDevs = 0;
1.367 - //CgUpnpDeviceList *devList = NULL;
1.368 CgUpnpDevice *childDev;
1.369 gchar *devName = NULL, *dev_url = NULL;
1.370 gboolean upnp_dev_found = FALSE;
1.371 @@ -259,8 +325,10 @@
1.372 gmyth_debug( "Device's friendly name = %s, and device's URL = %s\n", devName, dev_url );
1.373 if ( ( upnp_dev_found = ( g_strstr_len( devName, strlen( devName ), mythtvFriendlyName ) != NULL ) ) == TRUE )
1.374 {
1.375 + /* stores the last UDN number ID */
1.376 *udn = cg_upnp_device_getudn( childDev );
1.377 - *mythtv_servers_lst = g_list_append( *mythtv_servers_lst, dev_url );
1.378 + /* *mythtv_servers_lst = g_list_append( *mythtv_servers_lst, dev_url ); */
1.379 + g_hash_table_insert( *mythtv_servers_lst, (gpointer)*udn, (gpointer)dev_url );
1.380 }
1.381 ++cntDevs;
1.382 }
1.383 @@ -277,57 +345,22 @@
1.384
1.385 }
1.386
1.387 -/** Gets the GMythBackendInfo host object associated to this upnp.
1.388 - *
1.389 - * @return The string host object currently valid or NULL if the settings
1.390 - * were not opened.
1.391 - */
1.392 -gchar*
1.393 -gmyth_upnp_get_host ( GMythUPnP *gmyth_upnp )
1.394 -{
1.395 -
1.396 - if ( NULL == gmyth_upnp || NULL == gmyth_upnp->host )
1.397 - {
1.398 - gmyth_debug ("[%s] GMythUPnP host field not initialized\n", __FUNCTION__);
1.399 - return NULL;
1.400 - }
1.401 -
1.402 - return gmyth_upnp->host;
1.403 -}
1.404 -
1.405 -/** Gets the GMythBackendInfo port object associated to this upnp.
1.406 - *
1.407 - * @return The string object currently valid or NULL if the port number.
1.408 - */
1.409 -gint
1.410 -gmyth_upnp_get_port( GMythUPnP *gmyth_upnp )
1.411 -{
1.412 -
1.413 - if ( NULL == gmyth_upnp || gmyth_upnp->port <= 0 )
1.414 - {
1.415 - gmyth_debug ("[%s] GMythUPnP host field not initialized\n", __FUNCTION__);
1.416 - return 0;
1.417 - }
1.418 -
1.419 - return gmyth_upnp->port;
1.420 -}
1.421 -
1.422 /** Gets the UPnP AV devices server's list associated to this upnp.
1.423 *
1.424 - * @return The GList* containing all the URI values for each recognized UPnP device,
1.425 + * @return The GHashTable* containing all the URI values for each recognized UPnP device,
1.426 * or NULL if it couldn't recognize any MythTV AV device.
1.427 */
1.428 -GList*
1.429 +GHashTable*
1.430 gmyth_upnp_get_servers ( GMythUPnP *gmyth_upnp )
1.431 {
1.432
1.433 - if ( NULL == gmyth_upnp || NULL == gmyth_upnp->mythtv_servers )
1.434 + if ( NULL == gmyth_upnp || NULL == gmyth_upnp->priv->mythtv_servers )
1.435 {
1.436 gmyth_debug ("[%s] GMythUPnP has no MythTV servers recognized.\n", __FUNCTION__);
1.437 return NULL;
1.438 }
1.439
1.440 - return gmyth_upnp->mythtv_servers;
1.441 + return gmyth_upnp->priv->mythtv_servers;
1.442 }
1.443
1.444 /** Gets the GMythBackendInfo object associated to this upnp.
1.445 @@ -339,12 +372,12 @@
1.446 gmyth_upnp_get_backend_info ( GMythUPnP *gmyth_upnp )
1.447 {
1.448
1.449 - if ( NULL == gmyth_upnp || NULL == gmyth_upnp->gmyth_backend_info )
1.450 + if ( NULL == gmyth_upnp || NULL == gmyth_upnp->backend_info )
1.451 {
1.452 gmyth_debug ("[%s] GMythUPnP not initialized\n", __FUNCTION__);
1.453 return NULL;
1.454 }
1.455
1.456 - return gmyth_upnp->gmyth_backend_info;
1.457 + return gmyth_upnp->backend_info;
1.458 }
1.459