From db12b51022f7cbafc6817a84b46da14455af6ce6 Mon Sep 17 00:00:00 2001 From: Regis Merlino Date: Wed, 29 May 2013 14:43:00 +0200 Subject: [Device] Add a GetIcon() method Signed-off-by: Regis Merlino --- doc/server/dbus/API.txt | 7 +++ libdleyna/server/device.c | 140 +++++++++++++++++++++++++++++++++++++++++++ libdleyna/server/device.h | 11 ++++ libdleyna/server/interface.h | 5 ++ libdleyna/server/server.c | 17 ++++++ libdleyna/server/task.c | 25 ++++++++ libdleyna/server/task.h | 14 ++++- libdleyna/server/upnp.c | 15 +++++ libdleyna/server/upnp.h | 4 ++ test/dbus/mediaconsole.py | 3 + 10 files changed, 240 insertions(+), 1 deletion(-) diff --git a/doc/server/dbus/API.txt b/doc/server/dbus/API.txt index 9635fb1..dfb05ed 100644 --- a/doc/server/dbus/API.txt +++ b/doc/server/dbus/API.txt @@ -314,6 +314,13 @@ Cancel() -> void Cancels all requests a client has outstanding on that server. +GetIcon(s RequestedMimeType, s Resolution) -> (ay Bytes, s MimeType) + +Returns the device icon bytes and mime type according to +the RequestedMimeType and Resolution parameters. +Both RequestedMimeType and Resolution parameters are currently +reserved for future use and should be set as an empty string. + Signals: --------- diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c index a6268d0..1c3b6a4 100644 --- a/libdleyna/server/device.c +++ b/libdleyna/server/device.c @@ -82,6 +82,13 @@ struct dls_device_upload_job_t_ { guint remove_idle; }; +typedef struct dls_device_download_t_ dls_device_download_t; +struct dls_device_download_t_ { + SoupSession *session; + SoupMessage *msg; + dls_async_task_t *task; +}; + /* Private structure used in chain task */ typedef struct prv_new_device_ct_t_ prv_new_device_ct_t; struct prv_new_device_ct_t_ { @@ -233,6 +240,8 @@ void dls_device_delete(void *device) g_variant_unref(dev->sort_caps); g_variant_unref(dev->sort_ext_caps); g_variant_unref(dev->feature_list); + g_free(dev->icon.mime_type); + g_free(dev->icon.bytes); g_free(dev); } } @@ -4262,3 +4271,134 @@ on_error: DLEYNA_LOG_DEBUG("Exit"); } +static void prv_build_icon_result(dls_device_t *device, dls_task_t *task) +{ + GVariant *out_p[2]; + + out_p[0] = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, + device->icon.bytes, + device->icon.size, + 1); + out_p[1] = g_variant_new_string(device->icon.mime_type); + task->result = g_variant_ref_sink(g_variant_new_tuple(out_p, 2)); +} + +static void prv_get_icon_cancelled(GCancellable *cancellable, + gpointer user_data) +{ + dls_device_download_t *download = (dls_device_download_t *)user_data; + + dls_async_task_cancelled_cb(cancellable, download->task); + + if (download->msg) { + soup_session_cancel_message(download->session, download->msg, + SOUP_STATUS_CANCELLED); + DLEYNA_LOG_DEBUG("Cancelling device icon download"); + } +} + +static void prv_free_download_info(dls_device_download_t *download) +{ + if (download->msg) + g_object_unref(download->msg); + g_object_unref(download->session); + g_free(download); +} + +static void prv_get_icon_session_cb(SoupSession *session, + SoupMessage *msg, + gpointer user_data) +{ + dls_device_download_t *download = (dls_device_download_t *)user_data; + dls_async_task_t *cb_data = (dls_async_task_t *)download->task; + dls_device_t *device = (dls_device_t *)cb_data->task.target.device; + + if (msg->status_code == SOUP_STATUS_CANCELLED) + goto out; + + if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) { + device->icon.size = msg->response_body->length; + device->icon.bytes = g_malloc(device->icon.size); + memcpy(device->icon.bytes, msg->response_body->data, + device->icon.size); + + prv_build_icon_result(device, &cb_data->task); + } else { + DLEYNA_LOG_DEBUG("Failed to GET device icon: %s", + msg->reason_phrase); + + cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, + DLEYNA_ERROR_OPERATION_FAILED, + "Failed to GET device icon"); + } + + (void) g_idle_add(dls_async_task_complete, cb_data); + g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id); + +out: + + prv_free_download_info(download); +} + +void dls_device_get_icon(dls_client_t *client, + dls_task_t *task) +{ + GUPnPDeviceInfo *info; + dls_device_context_t *context; + dls_async_task_t *cb_data = (dls_async_task_t *)task; + dls_device_t *device = task->target.device; + gchar *url; + dls_device_download_t *download; + + if (device->icon.size != 0) { + prv_build_icon_result(device, task); + goto end; + } + + context = dls_device_get_context(device, client); + info = (GUPnPDeviceInfo *)context->device_proxy; + + url = gupnp_device_info_get_icon_url(info, NULL, -1, -1, -1, FALSE, + &device->icon.mime_type, NULL, + NULL, NULL); + if (url == NULL) { + cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, + DLEYNA_ERROR_NOT_SUPPORTED, + "No icon available"); + goto end; + } + + download = g_new0(dls_device_download_t, 1); + download->session = soup_session_async_new(); + download->msg = soup_message_new(SOUP_METHOD_GET, url); + download->task = cb_data; + + if (!download->msg) { + DLEYNA_LOG_WARNING("Invalid URL %s", url); + + cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, + DLEYNA_ERROR_BAD_RESULT, + "Invalid URL %s", url); + prv_free_download_info(download); + g_free(url); + + goto end; + } + + cb_data->cancel_id = + g_cancellable_connect(cb_data->cancellable, + G_CALLBACK(prv_get_icon_cancelled), + download, NULL); + + g_object_ref(download->msg); + soup_session_queue_message(download->session, download->msg, + prv_get_icon_session_cb, download); + + g_free(url); + + return; + +end: + + (void) g_idle_add(dls_async_task_complete, cb_data); +} diff --git a/libdleyna/server/device.h b/libdleyna/server/device.h index 36687a2..30788db 100644 --- a/libdleyna/server/device.h +++ b/libdleyna/server/device.h @@ -41,6 +41,13 @@ struct dls_device_context_t_ { guint timeout_id; }; +typedef struct dls_device_icon_t_ dls_device_icon_t; +struct dls_device_icon_t_ { + gchar *mime_type; + guchar *bytes; + gsize size; +}; + struct dls_device_t_ { dleyna_connector_id_t connection; guint id; @@ -57,6 +64,7 @@ struct dls_device_t_ { GVariant *feature_list; gboolean shutting_down; guint construct_step; + dls_device_icon_t icon; }; dls_device_context_t *dls_device_append_new_context(dls_device_t *device, @@ -138,4 +146,7 @@ void dls_device_get_object_metadata(dls_client_t *client, void dls_device_create_reference(dls_client_t *client, dls_task_t *task); +void dls_device_get_icon(dls_client_t *client, + dls_task_t *task); + #endif /* DLS_DEVICE_H__ */ diff --git a/libdleyna/server/interface.h b/libdleyna/server/interface.h index 7d69b6b..14a214b 100644 --- a/libdleyna/server/interface.h +++ b/libdleyna/server/interface.h @@ -182,6 +182,11 @@ enum dls_interface_type_ { #define DLS_INTERFACE_TO_ADD_UPDATE "ToAddUpdate" #define DLS_INTERFACE_TO_DELETE "ToDelete" #define DLS_INTERFACE_CANCEL "Cancel" +#define DLS_INTERFACE_GET_ICON "GetIcon" +#define DLS_INTERFACE_RESOLUTION "Resolution" +#define DLS_INTERFACE_ICON_BYTES "Bytes" +#define DLS_INTERFACE_MIME_TYPE "MimeType" +#define DLS_INTERFACE_REQ_MIME_TYPE "RequestedMimeType" #define DLS_INTERFACE_GET_METADATA "GetMetaData" #define DLS_INTERFACE_METADATA "MetaData" diff --git a/libdleyna/server/server.c b/libdleyna/server/server.c index 6141398..a3a901b 100644 --- a/libdleyna/server/server.c +++ b/libdleyna/server/server.c @@ -399,6 +399,16 @@ static const gchar g_server_introspection[] = " " " " " " + " " + " " + " " + " " + " " + " " " " " ut.create_reference.item_path); break; + case DLS_TASK_GET_ICON: + g_free(task->ut.get_icon.resolution); + g_free(task->ut.get_icon.mime_type); + break; default: break; } @@ -536,6 +540,27 @@ dls_task_t *dls_task_get_metadata_new(dleyna_connector_msg_id_t invocation, return task; } +dls_task_t *dls_task_get_icon_new(dleyna_connector_msg_id_t invocation, + const gchar *path, GVariant *parameters, + GError **error) +{ + dls_task_t *task; + + task = prv_m2spec_task_new(DLS_TASK_GET_ICON, invocation, path, + "(@ays)", error, FALSE); + if (!task) + goto finished; + + task->multiple_retvals = TRUE; + + g_variant_get(parameters, "(ss)", &task->ut.get_icon.mime_type, + &task->ut.get_icon.resolution); + +finished: + + return task; +} + void dls_task_complete(dls_task_t *task) { GVariant *variant = NULL; diff --git a/libdleyna/server/task.h b/libdleyna/server/task.h index 3e7b708..bf9f3ba 100644 --- a/libdleyna/server/task.h +++ b/libdleyna/server/task.h @@ -52,7 +52,8 @@ enum dls_task_type_t_ { DLS_TASK_CREATE_CONTAINER_IN_ANY, DLS_TASK_UPDATE_OBJECT, DLS_TASK_GET_OBJECT_METADATA, - DLS_TASK_CREATE_REFERENCE + DLS_TASK_CREATE_REFERENCE, + DLS_TASK_GET_ICON }; typedef enum dls_task_type_t_ dls_task_type_t; @@ -142,6 +143,12 @@ struct dls_task_target_info_t_ { dls_device_t *device; }; +typedef struct dls_task_get_icon_t_ dls_task_get_icon_t; +struct dls_task_get_icon_t_ { + gchar *mime_type; + gchar *resolution; +}; + typedef struct dls_task_t_ dls_task_t; struct dls_task_t_ { dleyna_task_atom_t atom; /* pseudo inheritance - MUST be first field */ @@ -165,6 +172,7 @@ struct dls_task_t_ { dls_task_create_container_t create_container; dls_task_update_t update; dls_task_create_reference_t create_reference; + dls_task_get_icon_t get_icon; } ut; }; @@ -259,6 +267,10 @@ dls_task_t *dls_task_get_metadata_new(dleyna_connector_msg_id_t invocation, const gchar *path, GError **error); +dls_task_t *dls_task_get_icon_new(dleyna_connector_msg_id_t invocation, + const gchar *path, GVariant *parameters, + GError **error); + void dls_task_cancel(dls_task_t *task); void dls_task_complete(dls_task_t *task); diff --git a/libdleyna/server/upnp.c b/libdleyna/server/upnp.c index f603647..92b3943 100644 --- a/libdleyna/server/upnp.c +++ b/libdleyna/server/upnp.c @@ -1045,6 +1045,21 @@ void dls_upnp_create_reference(dls_upnp_t *upnp, dls_client_t *client, return; } +void dls_upnp_get_icon(dls_upnp_t *upnp, dls_client_t *client, + dls_task_t *task, + dls_upnp_task_complete_t cb) +{ + dls_async_task_t *cb_data = (dls_async_task_t *)task; + + DLEYNA_LOG_DEBUG("Enter"); + + cb_data->cb = cb; + + dls_device_get_icon(client, task); + + DLEYNA_LOG_DEBUG("Exit"); +} + void dls_upnp_unsubscribe(dls_upnp_t *upnp) { GHashTableIter iter; diff --git a/libdleyna/server/upnp.h b/libdleyna/server/upnp.h index 206dba2..833723f 100644 --- a/libdleyna/server/upnp.h +++ b/libdleyna/server/upnp.h @@ -101,6 +101,10 @@ void dls_upnp_create_reference(dls_upnp_t *upnp, dls_client_t *client, dls_task_t *task, dls_upnp_task_complete_t cb); +void dls_upnp_get_icon(dls_upnp_t *upnp, dls_client_t *client, + dls_task_t *task, + dls_upnp_task_complete_t cb); + void dls_upnp_unsubscribe(dls_upnp_t *upnp); gboolean dls_upnp_device_context_exist(dls_device_t *device, diff --git a/test/dbus/mediaconsole.py b/test/dbus/mediaconsole.py index f75a556..61c33bc 100644 --- a/test/dbus/mediaconsole.py +++ b/test/dbus/mediaconsole.py @@ -181,6 +181,9 @@ class Device(Container): def cancel(self): return self._deviceIF.Cancel() + def print_icon(self, mime_type, resolution): + bytes, mime = self._deviceIF.GetIcon(mime_type, resolution) + print "Icon mime type: " + mime class UPNP(object): -- cgit v1.2.1