gmyth-upnp/src/gmyth_upnp.c
branchtrunk
changeset 909 847da7267234
parent 754 cb885ee44618
child 915 e612ba1d16ab
     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 -}