diff options
author | Jens Georg <mail@jensge.org> | 2016-04-02 20:11:53 +0200 |
---|---|---|
committer | Jens Georg <mail@jensge.org> | 2016-04-25 23:20:53 +0200 |
commit | 98a2ed00ba692390b87582f3e5ca19bf6021fec2 (patch) | |
tree | bbf1d04c0bec2832d07aa0f33632564d74292075 | |
parent | f18b0dc1f40a80d03f56d8a290a49a8c2e161b4b (diff) | |
download | gupnp-tools-98a2ed00ba692390b87582f3e5ca19bf6021fec2.tar.gz |
av-cp: Make server device async initable
Retrieve sort caps and icon
Signed-off-by: Jens Georg <mail@jensge.org>
https://bugzilla.gnome.org/show_bug.cgi?id=730747
-rw-r--r-- | src/av-cp/playlist-treeview.c | 50 | ||||
-rw-r--r-- | src/av-cp/server-device.c | 232 |
2 files changed, 262 insertions, 20 deletions
diff --git a/src/av-cp/playlist-treeview.c b/src/av-cp/playlist-treeview.c index ad96ba0..458149c 100644 --- a/src/av-cp/playlist-treeview.c +++ b/src/av-cp/playlist-treeview.c @@ -75,6 +75,11 @@ void on_didl_menuitem_activate (GtkMenuItem *menuitem, gpointer user_data); +static void +on_proxy_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data); + typedef struct { GUPnPServiceProxy *content_dir; @@ -729,9 +734,7 @@ append_didl_object (GUPnPDIDLLiteObject *object, } static void -on_device_icon_available (GUPnPDeviceInfo *info, - GParamSpec *spec, - gpointer user_data) +update_device_icon (GUPnPDeviceInfo *info) { GtkTreeModel *model; GtkTreeIter iter; @@ -775,6 +778,35 @@ get_content_dir (GUPnPDeviceProxy *proxy) } static void +on_proxy_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + gboolean result = FALSE; + + result = g_async_initable_init_finish (G_ASYNC_INITABLE (source_object), + res, + &error); + + if (result == TRUE) { + GUPnPServiceProxy *content_dir = GUPNP_SERVICE_PROXY (user_data); + char *sort_order = NULL; + + update_device_icon (GUPNP_DEVICE_INFO (source_object)); + + g_object_get (source_object, + "sort-order", + &sort_order, + NULL); + + browse (content_dir, "0", 0, MAX_BROWSE); + g_free (sort_order); + } +} + + +static void on_didl_object_available (GUPnPDIDLLiteParser *parser, GUPnPDIDLLiteObject *object, gpointer user_data) @@ -1039,6 +1071,12 @@ append_media_server (GUPnPDeviceProxy *proxy, -1); g_free (friendly_name); + g_async_initable_init_async (G_ASYNC_INITABLE (proxy), + G_PRIORITY_DEFAULT, + NULL, + on_proxy_ready, + content_dir); + /* Append the embedded devices */ child = gupnp_device_info_list_devices (info); while (child) { @@ -1049,12 +1087,6 @@ append_media_server (GUPnPDeviceProxy *proxy, child = g_list_delete_link (child, child); } - g_signal_connect (proxy, - "notify::icon", - G_CALLBACK (on_device_icon_available), - NULL); - - browse (content_dir, "0", 0, MAX_BROWSE); gupnp_service_proxy_add_notify (content_dir, "ContainerUpdateIDs", G_TYPE_STRING, diff --git a/src/av-cp/server-device.c b/src/av-cp/server-device.c index f961054..b14f2e9 100644 --- a/src/av-cp/server-device.c +++ b/src/av-cp/server-device.c @@ -18,30 +18,91 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include <string.h> + #include "server-device.h" #include "icons.h" -G_DEFINE_TYPE (AVCPMediaServer, av_cp_media_server, GUPNP_TYPE_DEVICE_PROXY) +#define CONTENT_DIR "urn:schemas-upnp-org:service:ContentDirectory" + +#define AV_CP_MEDIA_SERVER_ERROR av_cp_media_server_error_quark() + +GQuark +av_cp_media_server_error_quark (void); + +typedef enum _AVCPMediaServerError { + AV_CP_MEDIA_SERVER_FAILED +} AVCPMediaServerError; + +static void +av_cp_media_server_async_intable_init (gpointer iface, gpointer iface_data); + +static void +av_cp_media_server_init_async (GAsyncInitable *initable, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +static gboolean +av_cp_media_server_init_finish (GAsyncInitable *initable, + GAsyncResult *res, + GError **error); +static void +av_cp_media_server_introspect (AVCPMediaServer *self); + +static void +av_cp_media_server_introspect_finish (AVCPMediaServer *self); + +G_DEFINE_TYPE_WITH_CODE (AVCPMediaServer, + av_cp_media_server, + GUPNP_TYPE_DEVICE_PROXY, + G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, + av_cp_media_server_async_intable_init)) + +enum _AVCPMediaServerInitState { + NONE = 0, + INITIALIZED, + INIT_FAILED, + INITIALIZING +}; + +typedef enum _AVCPMediaServerInitState AVCPMediaServerInitState; struct _AVCPMediaServerPrivate { GdkPixbuf *icon; + char *default_sort_order; + GList *tasks; + AVCPMediaServerInitState state; }; enum { PROP_ICON = 1, + PROP_SORT_ORDER, N_PROPERTIES }; static GParamSpec *av_cp_media_server_properties[N_PROPERTIES] = { NULL, }; /* GObject overrides */ + static void -av_cp_media_server_constructed (GObject *obj); +av_cp_media_server_finalize (GObject *object) +{ + AVCPMediaServer *self = AV_CP_MEDIA_SERVER (object); + GObjectClass *parent_class = + G_OBJECT_CLASS (av_cp_media_server_parent_class); + + g_clear_pointer (&self->priv->default_sort_order, g_free); + + parent_class->finalize (object); +} static void av_cp_media_server_dispose (GObject *object) { + AVCPMediaServer *self = AV_CP_MEDIA_SERVER (object); GObjectClass *parent_class = G_OBJECT_CLASS (av_cp_media_server_parent_class); @@ -62,6 +123,9 @@ av_cp_media_server_get_property (GObject *obj, case PROP_ICON: g_value_set_object (value, self->priv->icon); break; + case PROP_SORT_ORDER: + g_value_set_string (value, self->priv->default_sort_order); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, spec); break; @@ -73,13 +137,53 @@ av_cp_media_server_on_icon_updated (GUPnPDeviceInfo *info, GdkPixbuf *icon); static void +av_cp_media_server_on_get_sort_caps (GUPnPServiceProxy *proxy, + GUPnPServiceProxyAction *action, + gpointer user_data) +{ + AVCPMediaServer *self = AV_CP_MEDIA_SERVER (user_data); + GError *error = NULL; + char *sort_caps = NULL; + + gupnp_service_proxy_end_action (proxy, + action, + &error, + "SortCaps", + G_TYPE_STRING, + &sort_caps, + NULL); + if (error != NULL) { + g_warning ("Failed to get sort caps from server: %s", + error->message); + g_error_free (error); + } else { + GString *default_sort_order = g_string_new (NULL); + if (strstr (sort_caps, "upnp:class") != NULL) { + g_string_append (default_sort_order, "+upnp:class,"); + } + + if (strstr (sort_caps, "dc:title") != NULL) { + g_string_append (default_sort_order, "+dc:title"); + } + + self->priv->default_sort_order = + g_string_free (default_sort_order, FALSE); + } + + self->priv->state = INITIALIZED; + av_cp_media_server_introspect_finish (self); + g_object_notify (G_OBJECT (self), "sort-order"); + g_object_unref (self); +} + +static void av_cp_media_server_class_init (AVCPMediaServerClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS (klass); - obj_class->constructed = av_cp_media_server_constructed; obj_class->get_property = av_cp_media_server_get_property; obj_class->dispose = av_cp_media_server_dispose; + obj_class->finalize = av_cp_media_server_finalize; g_type_class_add_private (klass, sizeof (AVCPMediaServerPrivate)); @@ -91,6 +195,14 @@ av_cp_media_server_class_init (AVCPMediaServerClass *klass) G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + av_cp_media_server_properties[PROP_SORT_ORDER] = + g_param_spec_string ("sort-order", + "sort-order", + "sort-order", + NULL, + G_PARAM_STATIC_STRINGS | + G_PARAM_READABLE); + g_object_class_install_properties (obj_class, N_PROPERTIES, av_cp_media_server_properties); @@ -105,22 +217,120 @@ av_cp_media_server_init (AVCPMediaServer *self) } static void -av_cp_media_server_constructed (GObject *obj) +av_cp_media_server_on_icon_updated (GUPnPDeviceInfo *info, + GdkPixbuf *icon) { - AVCPMediaServer *self = AV_CP_MEDIA_SERVER (obj); + AVCPMediaServer *self = AV_CP_MEDIA_SERVER (info); + GUPnPServiceInfo *proxy = NULL; + + self->priv->icon = icon; + proxy = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (self), + CONTENT_DIR); + if (proxy != NULL) { + gupnp_service_proxy_begin_action + (GUPNP_SERVICE_PROXY (proxy), + "GetSortCapabilities", + av_cp_media_server_on_get_sort_caps, + g_object_ref (self), + NULL); + } else { + g_debug ("Invalid MediaServer device without ContentDirectory"); + self->priv->state = INIT_FAILED; + av_cp_media_server_introspect_finish (self); + } +} + + +static void +av_cp_media_server_async_intable_init (gpointer iface, gpointer iface_data) +{ + GAsyncInitableIface *aii = (GAsyncInitableIface *)iface; + aii->init_async = av_cp_media_server_init_async; + aii->init_finish = av_cp_media_server_init_finish; +} + +static void +av_cp_media_server_init_async (GAsyncInitable *initable, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + AVCPMediaServer *self = AV_CP_MEDIA_SERVER (initable); + GTask *task; + + task = g_task_new (initable, cancellable, callback, user_data); + switch (self->priv->state) { + case INITIALIZED: + g_task_return_boolean (task, TRUE); + g_object_unref (task); + + break; + case INIT_FAILED: + g_task_return_new_error (task, + AV_CP_MEDIA_SERVER_ERROR, + AV_CP_MEDIA_SERVER_FAILED, + "Initialisation failed"); + g_object_unref (task); + break; + case NONE: + self->priv->state = INITIALIZING; + self->priv->tasks = g_list_prepend (self->priv->tasks, + task); + av_cp_media_server_introspect (self); + break; + case INITIALIZING: + self->priv->tasks = g_list_prepend (self->priv->tasks, + task); + break; + default: + g_assert_not_reached (); + break; + } +} - G_OBJECT_CLASS (av_cp_media_server_parent_class)->constructed (obj); +static gboolean +av_cp_media_server_init_finish (GAsyncInitable *initable, + GAsyncResult *res, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (res, initable), FALSE); + + return g_task_propagate_boolean (G_TASK (res), error); +} +static void +av_cp_media_server_introspect (AVCPMediaServer *self) +{ schedule_icon_update (GUPNP_DEVICE_INFO (self), av_cp_media_server_on_icon_updated); } static void -av_cp_media_server_on_icon_updated (GUPnPDeviceInfo *info, - GdkPixbuf *icon) +av_cp_media_server_introspect_finish (AVCPMediaServer *self) { - AVCPMediaServer *self = AV_CP_MEDIA_SERVER (info); + GList *l; - self->priv->icon = icon; - g_object_notify (G_OBJECT (info), "icon"); + for (l = self->priv->tasks; l != NULL; l = l->next) { + GTask *task = l->data; + + if (self->priv->state == INITIALIZED) { + g_task_return_boolean (task, TRUE); + } else { + g_task_return_new_error (task, + AV_CP_MEDIA_SERVER_ERROR, + AV_CP_MEDIA_SERVER_FAILED, + "Initialisation failed"); + } + + g_object_unref (task); + } + + g_clear_pointer (&self->priv->tasks, g_list_free); +} + +GQuark +av_cp_media_server_error_quark (void) +{ + return g_quark_from_static_string ("av-cp-media-server-error-quark"); } |