1.1 --- a/gmyth-upnp/src/gmyth_upnp.c Thu Jun 14 20:40:47 2007 +0100
1.2 +++ b/gmyth-upnp/src/gmyth_upnp.c Fri Feb 01 22:17:33 2008 +0000
1.3 @@ -30,64 +30,69 @@
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 -#include <sys/socket.h>
1.12 -#include <netdb.h>
1.13 -#include <errno.h>
1.14 -#include <stdlib.h>
1.15 +#include <gmyth/gmyth.h>
1.16 +#include <upnp/upnp.h>
1.17 +#include <string.h>
1.18
1.19 -#include <gmyth/gmyth_backendinfo.h>
1.20 -#include <gmyth/gmyth_socket.h>
1.21 -#include <gmyth/gmyth_uri.h>
1.22 -#include <gmyth/gmyth_debug.h>
1.23
1.24 -/*
1.25 - * Maximum number of searches in the synchronized search
1.26 - */
1.27 -#define GMYTH_UPNP_MAX_SEARCHS 10
1.28 +#define UPNP_SEARCH_TIMEOUT 5
1.29 +#define UPNP_SERVICE_FILTER "urn:schemas-mythtv-org:service:MythTv:1"
1.30 +#define SERVER_ID "MythTV AV Media Server"
1.31 +
1.32 +typedef struct _GMythUPnPPrivate GMythUPnPPrivate;
1.33 +typedef struct _GMythUPnPIdleData GMythUPnPIdleData;
1.34
1.35 #define GMYTH_UPNP_GET_PRIVATE(obj) \
1.36 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GMYTH_UPNP_TYPE, GMythUPnPPrivate))
1.37
1.38 +enum
1.39 +{
1.40 + DEVICE_FOUND,
1.41 + DEVICE_LOST,
1.42 + LAST_SIGNAL
1.43 +};
1.44 +
1.45 +struct _GMythUPnPIdleData
1.46 +{
1.47 + GMythUPnP *parent;
1.48 + GMythBackendInfo *server;
1.49 +};
1.50 +
1.51 struct _GMythUPnPPrivate {
1.52 - GHashTable *mythtv_servers;
1.53 + GHashTable *servers;
1.54 GMythUPnPDeviceStatus last_status;
1.55 gboolean upnp_dev_found;
1.56 gchar *udn;
1.57 GMutex *mutex;
1.58 + gint idle_count;
1.59 +
1.60 + /* upnp */
1.61 + UpnpClient_Handle client_id;
1.62 };
1.63
1.64 -static void gmyth_upnp_class_init(GMythUPnPClass * klass);
1.65 -static void gmyth_upnp_init(GMythUPnP * object);
1.66 +static void gmyth_upnp_class_init (GMythUPnPClass* klass);
1.67 +static void gmyth_upnp_init (GMythUPnP* object);
1.68 +static void gmyth_upnp_dispose (GObject* object);
1.69 +static void gmyth_upnp_finalize (GObject* object);
1.70 +static GObject* gmyth_upnp_constructor (GType type,
1.71 + guint n_construct_params,
1.72 + GObjectConstructParam *construct_params);
1.73
1.74 -static void gmyth_upnp_dispose(GObject * object);
1.75 -static void gmyth_upnp_finalize(GObject * object);
1.76
1.77 -static void _mythtv_device_found(GMythUPnP * gmyth_upnp,
1.78 - GMythUPnPDeviceStatus status,
1.79 - gchar * dev);
1.80 -static void _clinkc_mythtv_device_found(gchar * udn,
1.81 - GMythUPnPDeviceStatus status);
1.82 +static int _upnp_event_handler (Upnp_EventType e_type,
1.83 + void* e,
1.84 + void* data);
1.85
1.86 -static gboolean gmyth_upnp_initialize(GMythUPnP * gmyth_upnp,
1.87 - GMythBackendInfo *
1.88 - gmyth_backend_info,
1.89 - GMythUPnPDeviceListener listener);
1.90
1.91 -static gboolean gmyth_upnp_got_mythtv_service(CgUpnpControlPoint *
1.92 - controlPt, gchar ** udn,
1.93 - GHashTable **
1.94 - mythtv_servers_lst);
1.95 +static int signals[LAST_SIGNAL] = {0};
1.96
1.97 -G_DEFINE_TYPE(GMythUPnP, gmyth_upnp, G_TYPE_OBJECT)
1.98 +static GMythUPnP *singleton = NULL;
1.99
1.100 - static GMythUPnP *gmyth_upnp_static = NULL;
1.101 +G_DEFINE_TYPE(GMythUPnP, gmyth_upnp, G_TYPE_OBJECT);
1.102
1.103 - static void
1.104 - gmyth_upnp_class_init(GMythUPnPClass * klass)
1.105 +static void
1.106 +gmyth_upnp_class_init(GMythUPnPClass * klass)
1.107 {
1.108 GObjectClass *gobject_class;
1.109 GMythUPnPClass *gupnp_class;
1.110 @@ -97,347 +102,354 @@
1.111
1.112 gobject_class->dispose = gmyth_upnp_dispose;
1.113 gobject_class->finalize = gmyth_upnp_finalize;
1.114 + gobject_class->constructor = gmyth_upnp_constructor;
1.115
1.116 - g_type_class_add_private(gobject_class, sizeof(GMythUPnPPrivate));
1.117 + g_type_class_add_private (gobject_class, sizeof(GMythUPnPPrivate));
1.118
1.119 - gupnp_class->device_found_handler = _mythtv_device_found;
1.120
1.121 - gupnp_class->device_found_handler_signal_id =
1.122 - g_signal_new("device-found",
1.123 - G_TYPE_FROM_CLASS(gupnp_class),
1.124 - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE |
1.125 - G_SIGNAL_NO_HOOKS, 0, NULL, NULL,
1.126 - gmyth_upnp_marshal_VOID__INT_STRING, G_TYPE_NONE, 2,
1.127 - G_TYPE_INT, G_TYPE_STRING);
1.128 +
1.129 + signals[DEVICE_FOUND] = g_signal_new("device-found",
1.130 + G_TYPE_FROM_CLASS(gupnp_class),
1.131 + G_SIGNAL_RUN_LAST,
1.132 + 0, NULL, NULL,
1.133 + g_cclosure_marshal_VOID__OBJECT,
1.134 + G_TYPE_NONE, 1,
1.135 + GMYTH_BACKEND_INFO_TYPE);
1.136 +
1.137 + signals[DEVICE_LOST] = g_signal_new("device-lost",
1.138 + G_TYPE_FROM_CLASS(gupnp_class),
1.139 + G_SIGNAL_RUN_LAST,
1.140 + 0, NULL, NULL,
1.141 + g_cclosure_marshal_VOID__OBJECT,
1.142 + G_TYPE_NONE, 1,
1.143 + GMYTH_BACKEND_INFO_TYPE);
1.144
1.145 }
1.146
1.147 static void
1.148 -gmyth_upnp_init(GMythUPnP * gmyth_upnp)
1.149 +gmyth_upnp_init(GMythUPnP* self)
1.150 {
1.151 + gint ret;
1.152 + GMythUPnPPrivate *priv;
1.153
1.154 - gmyth_upnp->backend_info = NULL;
1.155 + priv = GMYTH_UPNP_GET_PRIVATE (self);
1.156
1.157 - gmyth_upnp->control_point = NULL;
1.158 + priv->mutex = g_mutex_new ();
1.159 + priv->servers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
1.160
1.161 - gmyth_upnp->priv = GMYTH_UPNP_GET_PRIVATE(gmyth_upnp);
1.162 - gmyth_upnp->priv->mutex = g_mutex_new();
1.163 - gmyth_upnp->priv->upnp_dev_found = FALSE;
1.164 + /* initalize upnp client */
1.165 + ret = UpnpInit (NULL, 0);
1.166 + if (ret != UPNP_E_SUCCESS)
1.167 + g_warning ("Fail to inilialize upnp SDK: %d", ret);
1.168 + else
1.169 + {
1.170 + ret = UpnpRegisterClient (_upnp_event_handler,
1.171 + &priv->client_id, &priv->client_id);
1.172
1.173 - g_signal_connect(G_OBJECT(gmyth_upnp), "device-found",
1.174 - (GCallback) (GMYTH_UPNP_GET_CLASS(gmyth_upnp)->
1.175 - device_found_handler), NULL);
1.176 -
1.177 - gmyth_upnp_static = gmyth_upnp;
1.178 -
1.179 + if (ret != UPNP_E_SUCCESS)
1.180 + g_warning ("Fail to start upnp client: %d", ret);
1.181 + }
1.182 }
1.183
1.184 -/** Creates a new instance of GMythUPnP.
1.185 - *
1.186 - * @return a new instance of GMythUPnP.
1.187 - */
1.188 -GMythUPnP *
1.189 -gmyth_upnp_new(GMythBackendInfo * gmyth_backend_info,
1.190 - GMythUPnPDeviceListener handler)
1.191 +static GObject*
1.192 +gmyth_upnp_constructor (GType type,
1.193 + guint n_construct_params,
1.194 + GObjectConstructParam *construct_params)
1.195 {
1.196 - GMythUPnP *gmyth_upnp =
1.197 - GMYTH_UPNP(g_object_new(GMYTH_UPNP_TYPE, NULL));
1.198 + GObject *object;
1.199
1.200 - g_object_ref(gmyth_backend_info);
1.201 + if (!singleton)
1.202 + {
1.203 + object = G_OBJECT_CLASS (gmyth_upnp_parent_class)->constructor (type,
1.204 + n_construct_params,
1.205 + construct_params);
1.206
1.207 - gmyth_upnp->backend_info = gmyth_backend_info;
1.208 + singleton = GMYTH_UPNP (object);
1.209 + }
1.210 + else
1.211 + object = g_object_ref (G_OBJECT (singleton));
1.212
1.213 - if (!gmyth_upnp_initialize(gmyth_upnp, gmyth_backend_info, handler)) {
1.214 - gmyth_debug("Error initializing the GMythUPnP!!!");
1.215 - }
1.216 -
1.217 - return gmyth_upnp;
1.218 + return object;
1.219 }
1.220
1.221 static void
1.222 gmyth_upnp_dispose(GObject * object)
1.223 {
1.224 - GMythUPnP *gmyth_upnp = GMYTH_UPNP(object);
1.225 -
1.226 - if (gmyth_upnp->control_point != NULL) {
1.227 - cg_upnp_controlpoint_stop(gmyth_upnp->control_point);
1.228 - cg_upnp_controlpoint_delete(gmyth_upnp->control_point);
1.229 - gmyth_upnp->control_point = NULL;
1.230 - }
1.231 -
1.232 - if (gmyth_upnp->priv->mythtv_servers != NULL) {
1.233 - g_hash_table_destroy(gmyth_upnp->priv->mythtv_servers);
1.234 - gmyth_upnp->priv->mythtv_servers = NULL;
1.235 - }
1.236 -
1.237 - if (gmyth_upnp->backend_info != NULL) {
1.238 - g_object_unref(gmyth_upnp->backend_info);
1.239 - gmyth_upnp->backend_info = NULL;
1.240 - }
1.241 -
1.242 + /* finalize upnp client */
1.243 + UpnpFinish ();
1.244 G_OBJECT_CLASS(gmyth_upnp_parent_class)->dispose(object);
1.245 }
1.246
1.247 static void
1.248 gmyth_upnp_finalize(GObject * object)
1.249 {
1.250 - g_signal_handlers_destroy(object);
1.251 -
1.252 G_OBJECT_CLASS(gmyth_upnp_parent_class)->finalize(object);
1.253 + singleton = NULL;
1.254 }
1.255
1.256 -gchar *
1.257 -gmyth_upnp_device_status_to_string(GMythUPnPDeviceStatus status)
1.258 +
1.259 +GMythUPnP*
1.260 +gmyth_upnp_get_instance (void)
1.261 {
1.262 - if (status == CgUpnpDeviceStatusAdded)
1.263 - return "Added";
1.264 - else if (status == CgUpnpDeviceStatusUpdated)
1.265 - return "Updated";
1.266 - else if (status == CgUpnpDeviceStatusInvalid)
1.267 - return "Invalid";
1.268 - else if (status == CgUpnpDeviceStatusRemoved)
1.269 - return "Removed";
1.270 -
1.271 - return "";
1.272 + return GMYTH_UPNP(g_object_new(GMYTH_UPNP_TYPE, NULL));
1.273 }
1.274
1.275 -/**
1.276 - * GObject's signal handler
1.277 - */
1.278 -static void
1.279 -_mythtv_device_found(GMythUPnP * gmyth_upnp, GMythUPnPDeviceStatus status,
1.280 - gchar * udn)
1.281 +
1.282 +void
1.283 +gmyth_upnp_search (GMythUPnP *self)
1.284 {
1.285 - g_debug("Device: [status = %s, UDN = %s]\n",
1.286 - gmyth_upnp_device_status_to_string(status), udn);
1.287 + int ret;
1.288 + GMythUPnPPrivate *priv;
1.289 +
1.290 + priv = GMYTH_UPNP_GET_PRIVATE (self);
1.291 +
1.292 + ret = UpnpSearchAsync (priv->client_id,
1.293 + UPNP_SEARCH_TIMEOUT,
1.294 + UPNP_SERVICE_FILTER,
1.295 + NULL);
1.296 +
1.297 + if (ret != UPNP_E_SUCCESS)
1.298 + g_warning ("Fail to start upnp listener: %d", ret);
1.299 }
1.300
1.301 -/**
1.302 - * GObject's signal handler
1.303 - */
1.304 -static void
1.305 -_clinkc_mythtv_device_found(gchar * udn, GMythUPnPDeviceStatus status)
1.306 +static gboolean
1.307 +_idle_emit_device_found_signal (gpointer data)
1.308 {
1.309 - if (gmyth_upnp_static != NULL && udn != NULL)
1.310 - g_signal_emit(gmyth_upnp_static, GMYTH_UPNP_GET_CLASS(gmyth_upnp_static)->device_found_handler_signal_id, 0, /* details
1.311 - */
1.312 - status, udn);
1.313 + GMythUPnPPrivate *priv;
1.314 + GMythUPnPIdleData *idle_data;
1.315 +
1.316 + idle_data = (GMythUPnPIdleData *) data;
1.317 + priv = GMYTH_UPNP_GET_PRIVATE (idle_data->parent);
1.318 +
1.319 + g_signal_emit (idle_data->parent, signals[DEVICE_FOUND], 0, idle_data->server);
1.320 +
1.321 + g_object_unref (idle_data->server);
1.322 + g_free (idle_data);
1.323 + priv->idle_count--;
1.324 +
1.325 + return FALSE;
1.326 }
1.327
1.328 -/**
1.329 - * Create a control point and start it.
1.330 - */
1.331 -static gboolean
1.332 -gmyth_upnp_initialize(GMythUPnP * gmyth_upnp,
1.333 - GMythBackendInfo * gmyth_backend_info,
1.334 - GMythUPnPDeviceListener device_found_handler)
1.335 +static gboolean
1.336 +_idle_emit_device_lost_signal (gpointer data)
1.337 {
1.338 - gboolean ret = TRUE;
1.339 + GMythUPnPPrivate *priv;
1.340 + GMythUPnPIdleData *idle_data;
1.341
1.342 - g_return_val_if_fail(gmyth_backend_info != NULL, FALSE);
1.343 + idle_data = (GMythUPnPIdleData *) data;
1.344 + priv = GMYTH_UPNP_GET_PRIVATE (idle_data->parent);
1.345
1.346 - /*
1.347 - * Create the cybergarage control point
1.348 - */
1.349 - gmyth_upnp->control_point = cg_upnp_controlpoint_new();
1.350 + g_signal_emit (idle_data->parent, signals[DEVICE_LOST], 0, idle_data->server);
1.351
1.352 - if (device_found_handler != NULL) {
1.353 - GMYTH_UPNP_GET_CLASS(gmyth_upnp)->device_found_handler =
1.354 - device_found_handler;
1.355 + g_object_unref (idle_data->server);
1.356 + g_free (idle_data);
1.357 + priv->idle_count--;
1.358
1.359 - cg_upnp_controlpoint_setdevicelistener(gmyth_upnp->control_point,
1.360 - _clinkc_mythtv_device_found);
1.361 + return FALSE;
1.362 +}
1.363 +
1.364 +static char*
1.365 +_xml_get_first_document_item (IXML_Document * doc,
1.366 + const gchar *item )
1.367 +{
1.368 + IXML_NodeList *node_list = NULL;
1.369 + IXML_Node *text_node = NULL;
1.370 + IXML_Node *tmp_node = NULL;
1.371 +
1.372 + gchar *ret = NULL;
1.373 +
1.374 + node_list = ixmlDocument_getElementsByTagName (doc,
1.375 + (char *) item);
1.376 +
1.377 + if (node_list)
1.378 + {
1.379 + if ((tmp_node = ixmlNodeList_item (node_list, 0)))
1.380 + {
1.381 + text_node = ixmlNode_getFirstChild (tmp_node);
1.382 +
1.383 + ret = strdup (ixmlNode_getNodeValue (text_node));
1.384 + }
1.385 }
1.386
1.387 - /*
1.388 - * Start the control point
1.389 - */
1.390 - if (cg_upnp_controlpoint_start(gmyth_upnp->control_point) == FALSE) {
1.391 - gmyth_debug("Unable to start UPnP control point!!!");
1.392 - ret = FALSE;
1.393 - goto done;
1.394 - } else {
1.395 - gmyth_debug("Control point started.");
1.396 - }
1.397 -
1.398 - done:
1.399 + if (node_list)
1.400 + ixmlNodeList_free (node_list);
1.401
1.402 return ret;
1.403 }
1.404
1.405 +
1.406 static void
1.407 -_gmyth_foreach_key_value(gchar * udn, gchar * dev,
1.408 - GList * upnp_servers_list)
1.409 +_append_mythtv_server_from_loation (GMythUPnP *self,
1.410 + const gchar *uuid,
1.411 + const gchar *location)
1.412 {
1.413 - GMythUPnPDevice *gmyth_upnp = g_malloc0(sizeof(GMythUPnPDevice));
1.414 + GMythUPnPPrivate *priv;
1.415 + gchar *base_url;
1.416 + gchar *end;
1.417
1.418 - GMythURI *uri = NULL;
1.419 - gmyth_upnp->uri = (gchar *) (dev);
1.420 - uri = gmyth_uri_new_with_value(gmyth_upnp->uri);
1.421 + priv = GMYTH_UPNP_GET_PRIVATE (self);
1.422
1.423 - gmyth_upnp->host = gmyth_uri_get_host(uri);
1.424 - gmyth_upnp->port = gmyth_uri_get_port(uri);
1.425 - gmyth_upnp->protocol = gmyth_uri_get_protocol(uri);
1.426 + base_url = g_strdup (location);
1.427 + end = g_strrstr (base_url, "/");
1.428 + if (end)
1.429 + {
1.430 + gint ret;
1.431 + IXML_Document *desc_doc;
1.432 + gchar *info_url;
1.433
1.434 - gmyth_debug("MythTV UPnP service [ %s, %d ].", gmyth_upnp->host,
1.435 - gmyth_upnp->port);
1.436 + end[0] = '\0';
1.437 + info_url = g_strconcat (base_url,
1.438 + "Myth/GetConnectionInfo",
1.439 + NULL);
1.440 + g_free (base_url);
1.441 + desc_doc = NULL;
1.442 + ret = UpnpDownloadXmlDoc (info_url, &desc_doc);
1.443 + if (ret != UPNP_E_SUCCESS)
1.444 + {
1.445 + g_warning ("Error obtaining device desc: %d", ret);
1.446 + }
1.447 + else
1.448 + {
1.449 + GMythBackendInfo *info;
1.450 + GMythUPnPIdleData *idle_data;
1.451
1.452 - upnp_servers_list = g_list_append(upnp_servers_list, gmyth_upnp);
1.453 + info = gmyth_backend_info_new_full (
1.454 + _xml_get_first_document_item (desc_doc, "Host"),
1.455 + _xml_get_first_document_item (desc_doc, "UserName"),
1.456 + _xml_get_first_document_item (desc_doc, "Password"),
1.457 + _xml_get_first_document_item (desc_doc, "Name"),
1.458 + // Current mythtv version not export port number
1.459 + 6543);
1.460
1.461 - if (uri != NULL) {
1.462 - g_object_unref(uri);
1.463 - uri = NULL;
1.464 + if (desc_doc)
1.465 + ixmlDocument_free (desc_doc);
1.466 +
1.467 + g_mutex_lock (priv->mutex);
1.468 + g_hash_table_insert (priv->servers,
1.469 + g_strdup (uuid),
1.470 + g_object_ref (info));
1.471 + g_mutex_unlock (priv->mutex);
1.472 + g_debug ("info url: %s", info_url);
1.473 + g_free (info_url);
1.474 +
1.475 + idle_data = g_new0 (GMythUPnPIdleData, 1);
1.476 + idle_data->parent = self;
1.477 + idle_data->server = g_object_ref (info);
1.478 +
1.479 + priv->idle_count++;
1.480 + g_idle_add (_idle_emit_device_found_signal, idle_data);
1.481 + }
1.482 }
1.483 +}
1.484 +
1.485 +static void
1.486 +_remove_mythtv_server (GMythUPnP *self,
1.487 + const gchar *uuid)
1.488 +{
1.489 + GMythUPnPPrivate *priv;
1.490 + GMythBackendInfo *info;
1.491 +
1.492 + priv = GMYTH_UPNP_GET_PRIVATE (self);
1.493 +
1.494 + g_mutex_lock (priv->mutex);
1.495 + info = g_hash_table_lookup (priv->servers, uuid);
1.496 + if (info)
1.497 + {
1.498 + GMythUPnPIdleData *idle_data;
1.499 +
1.500 + idle_data = g_new0 (GMythUPnPIdleData, 1);
1.501 + idle_data->parent = self;
1.502 + idle_data->server = g_object_ref (info);
1.503 +
1.504 + g_hash_table_remove (priv->servers, uuid);
1.505 +
1.506 + priv->idle_count++;
1.507 + g_idle_add (_idle_emit_device_lost_signal, idle_data);
1.508 + }
1.509 + g_mutex_unlock (priv->mutex);
1.510
1.511 }
1.512
1.513 -GList *
1.514 -gmyth_upnp_do_search_sync(GMythUPnP * gmyth_upnp)
1.515 +static GMythBackendInfo*
1.516 +_find_service_by_uuid (GMythUPnP *self,
1.517 + const gchar *uuid)
1.518 {
1.519 - GList *upnp_servers_list = NULL;
1.520 - guint iter_count = GMYTH_UPNP_MAX_SEARCHS;
1.521 - /*
1.522 - * gmyth_upnp->priv = GMYTH_UPNP_GET_PRIVATE( gmyth_upnp );
1.523 - */
1.524 + GMythUPnPPrivate *priv;
1.525 + GMythBackendInfo *info;
1.526
1.527 - while (gmyth_upnp->priv->upnp_dev_found == FALSE && (--iter_count > 0)) {
1.528 + priv = GMYTH_UPNP_GET_PRIVATE (self);
1.529 + info = NULL;
1.530
1.531 - gmyth_debug
1.532 - ("UPnP MythTV Client control point is searching MythTV AV Device server...\n");
1.533 + g_mutex_lock (priv->mutex);
1.534 + info = g_hash_table_lookup (priv->servers, uuid);
1.535 + g_mutex_unlock (priv->mutex);
1.536
1.537 - if (gmyth_upnp->control_point != NULL)
1.538 - cg_upnp_controlpoint_search(gmyth_upnp->control_point,
1.539 - "urn:schemas-upnp-org:service:ContentDirectory:1");
1.540 -
1.541 - /*
1.542 - * just to avoid clinkc pthread concurrency faults
1.543 - */
1.544 - cg_wait(1000);
1.545 -
1.546 - /*
1.547 - * discover if it was found
1.548 - */
1.549 - gmyth_upnp->priv->upnp_dev_found =
1.550 - gmyth_upnp_got_mythtv_service(gmyth_upnp->control_point,
1.551 - &gmyth_upnp->priv->udn,
1.552 - &gmyth_upnp->priv->
1.553 - mythtv_servers);
1.554 -
1.555 - } /* while */
1.556 -
1.557 - if (gmyth_upnp->priv->upnp_dev_found) {
1.558 -
1.559 - gmyth_debug("Found UPnP MythTV AV Device...\n");
1.560 -
1.561 - g_hash_table_foreach(gmyth_upnp->priv->mythtv_servers,
1.562 - (GHFunc) _gmyth_foreach_key_value,
1.563 - upnp_servers_list);
1.564 -
1.565 - }
1.566 - /*
1.567 - * if - found UPnP device
1.568 - */
1.569 - return upnp_servers_list;
1.570 + return info;
1.571 }
1.572
1.573 -/**
1.574 - * Checks if got the MythTV service in the Control Point's device list.
1.575 - */
1.576 -static gboolean
1.577 -gmyth_upnp_got_mythtv_service(CgUpnpControlPoint * controlPt, gchar ** udn,
1.578 - GHashTable ** mythtv_servers_lst)
1.579 +static int
1.580 +_upnp_event_handler (Upnp_EventType e_type,
1.581 + void* e,
1.582 + void* data)
1.583 {
1.584 + g_return_val_if_fail (singleton != NULL, 0);
1.585
1.586 - g_return_val_if_fail(mythtv_servers_lst != NULL, FALSE);
1.587 - g_return_val_if_fail(controlPt != NULL, FALSE);
1.588 + switch (e_type)
1.589 + {
1.590 + case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
1.591 + case UPNP_DISCOVERY_SEARCH_RESULT:
1.592 + {
1.593 + struct Upnp_Discovery *d_event;
1.594
1.595 - *mythtv_servers_lst = g_hash_table_new(g_str_hash, g_str_equal);
1.596 + d_event = (struct Upnp_Discovery *) e;
1.597
1.598 - const gchar *mythtvFriendlyName = "Myth";
1.599 - /*
1.600 - * begin assertion about the size of discovered devices
1.601 - */
1.602 - gint numDevices =
1.603 - cg_upnp_controlpoint_getndevices(controlPt);
1.604 - gint cntDevs = 0;
1.605 - CgUpnpDevice *childDev;
1.606 - gchar *devName = NULL,
1.607 - *dev_url = NULL;
1.608 - gboolean upnp_dev_found = FALSE;
1.609 + g_debug ("TYPE: %s", d_event->ServiceType);
1.610
1.611 - gmyth_debug("UPnP MythTV AV Device list size = %d\n", numDevices);
1.612 + if (strcmp (d_event->ServiceType, UPNP_SERVICE_FILTER) != 0)
1.613 + {
1.614 + g_debug ("invalid device : %s", d_event->DeviceId);
1.615 + break;
1.616 + }
1.617
1.618 - for (childDev = cg_upnp_controlpoint_getdevices(controlPt);
1.619 - childDev != NULL; childDev = cg_upnp_device_next(childDev)) {
1.620 - devName = cg_upnp_device_getfriendlyname(childDev);
1.621 - dev_url = cg_upnp_device_getlocationfromssdppacket(childDev);
1.622 - gmyth_debug
1.623 - ("Device's friendly name = %s, and device's URL = %s\n",
1.624 - devName, dev_url);
1.625 - if ((g_strstr_len(devName, strlen(devName), mythtvFriendlyName) !=
1.626 - NULL) == TRUE) {
1.627 - upnp_dev_found = TRUE;
1.628 - /*
1.629 - * stores the last UDN number ID
1.630 - */
1.631 - *udn = cg_upnp_device_getudn(childDev);
1.632 - /*
1.633 - *mythtv_servers_lst = g_list_append( *mythtv_servers_lst, dev_url ); */
1.634 - g_hash_table_insert(*mythtv_servers_lst, (gpointer) * udn,
1.635 - (gpointer) dev_url);
1.636 +
1.637 + if (d_event->ErrCode != UPNP_E_SUCCESS)
1.638 + {
1.639 + g_warning ("Error in Discovery: %d", d_event->ErrCode);
1.640 + break;
1.641 + }
1.642 +
1.643 + if (_find_service_by_uuid (GMYTH_UPNP (singleton), d_event->DeviceId) == NULL)
1.644 + _append_mythtv_server_from_loation (singleton,
1.645 + d_event->DeviceId,
1.646 + d_event->Location);
1.647 +
1.648 +
1.649 + break;
1.650 }
1.651 - ++cntDevs;
1.652 + case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
1.653 + {
1.654 + GMythUPnPPrivate *priv;
1.655 + struct Upnp_Discovery *d_event;
1.656 +
1.657 + d_event = (struct Upnp_Discovery *) e;
1.658 + if (d_event->ErrCode != UPNP_E_SUCCESS)
1.659 + {
1.660 + g_warning ("Error in Discovery: %d", d_event->ErrCode);
1.661 + break;
1.662 + }
1.663 +
1.664 + priv = GMYTH_UPNP_GET_PRIVATE (singleton);
1.665 + _remove_mythtv_server (singleton,
1.666 + d_event->DeviceId);
1.667 +
1.668 + break;
1.669 +
1.670 + }
1.671 + default:
1.672 + g_debug ("No handle event: %d", e_type);
1.673 + break;
1.674 }
1.675
1.676 - if (upnp_dev_found == TRUE) {
1.677 - gmyth_debug
1.678 - ("MythTV AV Device found, from a total of %d devices.\n",
1.679 - cntDevs);
1.680 - } else if (numDevices == cntDevs) {
1.681 - gmyth_debug
1.682 - ("MythTV AV Device not found, from a total of %d devices.\n",
1.683 - cntDevs);
1.684 - } else {
1.685 - gmyth_debug
1.686 - ("Control Point's MythTV AV Device count is wrong: iterated over %d devices, but there are %d registered devices.\n",
1.687 - cntDevs, numDevices);
1.688 - }
1.689 -
1.690 - return upnp_dev_found;
1.691 -
1.692 + return 0;
1.693 }
1.694
1.695 -/** Gets the UPnP AV devices server's list associated to this upnp.
1.696 - *
1.697 - * @return The GHashTable* containing all the URI values for each recognized UPnP device,
1.698 - * or NULL if it couldn't recognize any MythTV AV device.
1.699 - */
1.700 -GHashTable *
1.701 -gmyth_upnp_get_servers(GMythUPnP * gmyth_upnp)
1.702 -{
1.703 -
1.704 - if (NULL == gmyth_upnp || NULL == gmyth_upnp->priv->mythtv_servers) {
1.705 - gmyth_debug("[%s] GMythUPnP has no MythTV servers recognized.\n",
1.706 - __FUNCTION__);
1.707 - return NULL;
1.708 - }
1.709 -
1.710 - return gmyth_upnp->priv->mythtv_servers;
1.711 -}
1.712 -
1.713 -/** Gets the GMythBackendInfo object associated to this upnp.
1.714 - *
1.715 - * @return The GMythBackendInfo object currently valid or NULL if the settings
1.716 - * were not opened.
1.717 - */
1.718 -GMythBackendInfo *
1.719 -gmyth_upnp_get_backend_info(GMythUPnP * gmyth_upnp)
1.720 -{
1.721 -
1.722 - if (NULL == gmyth_upnp || NULL == gmyth_upnp->backend_info) {
1.723 - gmyth_debug("[%s] GMythUPnP not initialized\n", __FUNCTION__);
1.724 - return NULL;
1.725 - }
1.726 -
1.727 - return gmyth_upnp->backend_info;
1.728 -}