diff options
author | Regis Merlino <regis.merlino@intel.com> | 2013-05-28 10:40:56 +0200 |
---|---|---|
committer | Regis Merlino <regis.merlino@intel.com> | 2013-05-29 11:37:39 +0200 |
commit | 45baf6c8d77ae4c7ecf43d92bacaecd2499ba4c6 (patch) | |
tree | a5d621224495d762dba34aeccde87d4ec7728487 | |
parent | e95c135e09a86196d55a8e54a8c944cfab24e914 (diff) | |
download | dleyna-renderer-45baf6c8d77ae4c7ecf43d92bacaecd2499ba4c6.tar.gz |
[Device] Add a GetIcon() method
Signed-off-by: Regis Merlino <regis.merlino@intel.com>
-rw-r--r-- | doc/server/dbus/API.txt | 10 | ||||
-rw-r--r-- | libdleyna/renderer/device.c | 142 | ||||
-rw-r--r-- | libdleyna/renderer/device.h | 11 | ||||
-rw-r--r-- | libdleyna/renderer/server.c | 24 | ||||
-rw-r--r-- | libdleyna/renderer/task.c | 30 | ||||
-rw-r--r-- | libdleyna/renderer/task.h | 13 | ||||
-rw-r--r-- | libdleyna/renderer/upnp.c | 26 | ||||
-rw-r--r-- | libdleyna/renderer/upnp.h | 3 | ||||
-rw-r--r-- | test/dbus/rendererconsole.py | 7 |
9 files changed, 257 insertions, 9 deletions
diff --git a/doc/server/dbus/API.txt b/doc/server/dbus/API.txt index a6f61c0..6e80e9f 100644 --- a/doc/server/dbus/API.txt +++ b/doc/server/dbus/API.txt @@ -190,13 +190,19 @@ URL for the renderer. Methods: --------- -The com.intel.dLeynaRenderer.RendererDevice interface currently exposes a -single method: +The com.intel.dLeynaRenderer.RendererDevice interface currently exposes two +methods: Cancel() -> void Cancels all requests a client has outstanding on that server. +GetIcon(s Resolution) -> (ay Data, s MimeType) + +Returns the device icon bytes and mime type according to +the Resolution parameter. +The Resolution parameter is currently reserved for future use +and should be set as an empty string. org.mpris.MediaPlayer2 ---------------------- diff --git a/libdleyna/renderer/device.c b/libdleyna/renderer/device.c index 62b9f25..dff3d39 100644 --- a/libdleyna/renderer/device.c +++ b/libdleyna/renderer/device.c @@ -24,6 +24,7 @@ #include <string.h> #include <math.h> +#include <libsoup/soup.h> #include <libgupnp/gupnp-control-point.h> #include <libgupnp-av/gupnp-av.h> @@ -50,6 +51,13 @@ struct prv_new_device_ct_t_ { const dleyna_connector_dispatch_cb_t *dispatch_table; }; +typedef struct prv_download_info_t_ prv_download_info_t; +struct prv_download_info_t_ { + SoupSession *session; + SoupMessage *msg; + dlr_async_task_t *task; +}; + static void prv_last_change_cb(GUPnPServiceProxy *proxy, const char *variable, GValue *value, @@ -386,6 +394,10 @@ void dlr_device_delete(void *device) if (dev->mpris_transport_play_speeds) g_variant_unref(dev->mpris_transport_play_speeds); g_free(dev->rate); + + g_free(dev->icon.mime_type); + g_free(dev->icon.bytes); + g_free(dev); } } @@ -2653,3 +2665,133 @@ void dlr_device_remove_uri(dlr_device_t *device, dlr_task_t *task, (void) g_idle_add(dlr_async_task_complete, cb_data); } + +static void prv_build_icon_result(dlr_device_t *device, dlr_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) +{ + prv_download_info_t *download = (prv_download_info_t *)user_data; + + dlr_async_task_cancelled(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(prv_download_info_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) +{ + prv_download_info_t *download = (prv_download_info_t *)user_data; + dlr_async_task_t *cb_data = (dlr_async_task_t *)download->task; + dlr_device_t *device = (dlr_device_t *)cb_data->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(dlr_async_task_complete, cb_data); + g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id); + +out: + + prv_free_download_info(download); +} + +void dlr_device_get_icon(dlr_device_t *device, dlr_task_t *task, + dlr_upnp_task_complete_t cb) +{ + GUPnPDeviceInfo *info; + dlr_device_context_t *context; + dlr_async_task_t *cb_data = (dlr_async_task_t *)task; + gchar *url; + prv_download_info_t *download; + + cb_data->cb = cb; + cb_data->device = device; + + if (device->icon.size != 0) { + prv_build_icon_result(device, task); + goto end; + } + + context = dlr_device_get_context(device); + 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 || *url == 0) { + cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, + DLEYNA_ERROR_NOT_SUPPORTED, + "No icon available"); + goto end; + } + + download = g_new0(prv_download_info_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); + + goto end; + } + + cb_data->cancel_id = + g_cancellable_connect(cb_data->cancellable, + G_CALLBACK(prv_get_icon_cancelled), + download, NULL); + + soup_session_queue_message(download->session, download->msg, + prv_get_icon_session_cb, download); + + return; + +end: + + (void) g_idle_add(dlr_async_task_complete, cb_data); +} diff --git a/libdleyna/renderer/device.h b/libdleyna/renderer/device.h index dd9a1f3..2fef1fb 100644 --- a/libdleyna/renderer/device.h +++ b/libdleyna/renderer/device.h @@ -64,6 +64,13 @@ struct dlr_props_t_ { gboolean synced; }; +typedef struct dlr_device_icon_t_ dlr_device_icon_t; +struct dlr_device_icon_t_ { + gchar *mime_type; + guchar *bytes; + gsize size; +}; + struct dlr_device_t_ { dleyna_connector_id_t connection; guint ids[DLR_INTERFACE_INFO_MAX]; @@ -79,6 +86,7 @@ struct dlr_device_t_ { double min_rate; double max_rate; guint construct_step; + dlr_device_icon_t icon; }; void dlr_device_construct( @@ -158,4 +166,7 @@ void dlr_device_remove_uri(dlr_device_t *device, dlr_task_t *task, dlr_host_service_t *host_service, dlr_upnp_task_complete_t cb); +void dlr_device_get_icon(dlr_device_t *device, dlr_task_t *task, + dlr_upnp_task_complete_t cb); + #endif /* DLR_DEVICE_H__ */ diff --git a/libdleyna/renderer/server.c b/libdleyna/renderer/server.c index 3b8fff0..31d1050 100644 --- a/libdleyna/renderer/server.c +++ b/libdleyna/renderer/server.c @@ -97,6 +97,11 @@ #define DLR_INTERFACE_GOTO_TRACK "GotoTrack" #define DLR_INTERFACE_CANCEL "Cancel" +#define DLR_INTERFACE_GET_ICON "GetIcon" +#define DLR_INTERFACE_RESOLUTION "Resolution" +#define DLR_INTERFACE_ICON_BYTES "Bytes" +#define DLR_INTERFACE_MIME_TYPE "MimeType" + typedef struct dlr_context_t_ dlr_context_t; struct dlr_context_t_ { @@ -274,6 +279,14 @@ static const gchar g_server_introspection[] = " <interface name='"DLEYNA_SERVER_INTERFACE_RENDERER_DEVICE"'>" " <method name='"DLR_INTERFACE_CANCEL"'>" " </method>" + " <method name='"DLR_INTERFACE_GET_ICON"'>" + " <arg type='s' name='"DLR_INTERFACE_RESOLUTION"'" + " direction='in'/>" + " <arg type='ay' name='"DLR_INTERFACE_ICON_BYTES"'" + " direction='out'/>" + " <arg type='s' name='"DLR_INTERFACE_MIME_TYPE"'" + " direction='out'/>" + " </method>" " <property type='s' name='"DLR_INTERFACE_PROP_DEVICE_TYPE"'" " access='read'/>" " <property type='s' name='"DLR_INTERFACE_PROP_UDN"'" @@ -499,6 +512,10 @@ static void prv_process_async_task(dlr_task_t *task) dlr_upnp_remove_uri(g_context.upnp, task, prv_async_task_complete); break; + case DLR_TASK_GET_ICON: + dlr_upnp_get_icon(g_context.upnp, task, + prv_async_task_complete); + break; default: break; } @@ -825,6 +842,7 @@ static void prv_renderer_device_method_call( GVariant *parameters, dleyna_connector_msg_id_t invocation) { + dlr_task_t *task; const gchar *device_id = NULL; GError *error = NULL; const dleyna_task_queue_key_t *queue_id; @@ -845,11 +863,15 @@ static void prv_renderer_device_method_call( dleyna_task_processor_cancel_queue(queue_id); g_context.connector->return_response(invocation, NULL); + } else if (!strcmp(method, DLR_INTERFACE_GET_ICON)) { + task = dlr_task_get_icon_new(invocation, object, parameters); + + prv_add_task(task, sender, device_id); } finished: - return; + return; } static void prv_found_media_server(const gchar *path) diff --git a/libdleyna/renderer/task.c b/libdleyna/renderer/task.c index 575261a..afc1833 100644 --- a/libdleyna/renderer/task.c +++ b/libdleyna/renderer/task.c @@ -321,21 +321,41 @@ dlr_task_t *dlr_task_remove_uri_new(dleyna_connector_msg_id_t invocation, return task; } +dlr_task_t *dlr_task_get_icon_new(dleyna_connector_msg_id_t invocation, + const gchar *path, GVariant *parameters) +{ + dlr_task_t *task; + + task = prv_device_task_new(DLR_TASK_GET_ICON, invocation, path, + "(@ays)"); + task->multiple_retvals = TRUE; + + g_variant_get(parameters, "(s)", &task->ut.get_icon.resolution); + + return task; +} + void dlr_task_complete(dlr_task_t *task) { + GVariant *result; + if (!task) goto finished; if (task->invocation) { - if (task->result_format && task->result) + if (task->result_format && task->result) { + if (task->multiple_retvals) + result = task->result; + else + result = g_variant_new(task->result_format, + task->result); dlr_renderer_get_connector()->return_response( - task->invocation, - g_variant_new(task->result_format, - task->result)); - else + task->invocation, result); + } else { dlr_renderer_get_connector()->return_response( task->invocation, NULL); + } task->invocation = NULL; } diff --git a/libdleyna/renderer/task.h b/libdleyna/renderer/task.h index e1eaf1f..7993d51 100644 --- a/libdleyna/renderer/task.h +++ b/libdleyna/renderer/task.h @@ -49,7 +49,8 @@ enum dlr_task_type_t_ { DLR_TASK_SET_POSITION, DLR_TASK_GOTO_TRACK, DLR_TASK_HOST_URI, - DLR_TASK_REMOVE_URI + DLR_TASK_REMOVE_URI, + DLR_TASK_GET_ICON }; typedef enum dlr_task_type_t_ dlr_task_type_t; @@ -91,6 +92,11 @@ struct dlr_task_host_uri_t_ { gchar *client; }; +typedef struct dlr_task_get_icon_t_ dlr_task_get_icon_t; +struct dlr_task_get_icon_t_ { + gchar *resolution; +}; + typedef struct dlr_task_t_ dlr_task_t; struct dlr_task_t_ { dleyna_task_atom_t atom; /* pseudo inheritance - MUST be first field */ @@ -100,6 +106,7 @@ struct dlr_task_t_ { GVariant *result; dleyna_connector_msg_id_t invocation; gboolean synchronous; + gboolean multiple_retvals; union { dlr_task_get_props_t get_props; dlr_task_get_prop_t get_prop; @@ -107,6 +114,7 @@ struct dlr_task_t_ { dlr_task_open_uri_t open_uri; dlr_task_host_uri_t host_uri; dlr_task_seek_t seek; + dlr_task_get_icon_t get_icon; } ut; }; @@ -170,6 +178,9 @@ dlr_task_t *dlr_task_remove_uri_new(dleyna_connector_msg_id_t invocation, const gchar *path, const gchar *sender, GVariant *parameters); +dlr_task_t *dlr_task_get_icon_new(dleyna_connector_msg_id_t invocation, + const gchar *path, GVariant *parameters); + void dlr_task_complete(dlr_task_t *task); void dlr_task_fail(dlr_task_t *task, GError *error); diff --git a/libdleyna/renderer/upnp.c b/libdleyna/renderer/upnp.c index f1c4959..ee45166 100644 --- a/libdleyna/renderer/upnp.c +++ b/libdleyna/renderer/upnp.c @@ -795,6 +795,32 @@ void dlr_upnp_remove_uri(dlr_upnp_t *upnp, dlr_task_t *task, DLEYNA_LOG_DEBUG("Exit"); } +void dlr_upnp_get_icon(dlr_upnp_t *upnp, dlr_task_t *task, + dlr_upnp_task_complete_t cb) +{ + dlr_device_t *device; + dlr_async_task_t *cb_data = (dlr_async_task_t *)task; + + DLEYNA_LOG_DEBUG("Enter"); + + device = dlr_device_from_path(task->path, upnp->server_udn_map); + + if (!device) { + DLEYNA_LOG_WARNING("Cannot locate device"); + + cb_data->cb = cb; + cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, + DLEYNA_ERROR_OBJECT_NOT_FOUND, + "Cannot locate a device for the specified object"); + + (void) g_idle_add(dlr_async_task_complete, cb_data); + } else { + dlr_device_get_icon(device, task, cb); + } + + DLEYNA_LOG_DEBUG("Exit"); +} + void dlr_upnp_lost_client(dlr_upnp_t *upnp, const gchar *client_name) { dlr_host_service_lost_client(upnp->host_service, client_name); diff --git a/libdleyna/renderer/upnp.h b/libdleyna/renderer/upnp.h index 4345040..db98bd3 100644 --- a/libdleyna/renderer/upnp.h +++ b/libdleyna/renderer/upnp.h @@ -96,6 +96,9 @@ void dlr_upnp_host_uri(dlr_upnp_t *upnp, dlr_task_t *task, void dlr_upnp_remove_uri(dlr_upnp_t *upnp, dlr_task_t *task, dlr_upnp_task_complete_t cb); +void dlr_upnp_get_icon(dlr_upnp_t *upnp, dlr_task_t *task, + dlr_upnp_task_complete_t cb); + void dlr_upnp_lost_client(dlr_upnp_t *upnp, const gchar *client_name); void dlr_upnp_unsubscribe(dlr_upnp_t *upnp); diff --git a/test/dbus/rendererconsole.py b/test/dbus/rendererconsole.py index 68bffb5..3d3dc79 100644 --- a/test/dbus/rendererconsole.py +++ b/test/dbus/rendererconsole.py @@ -55,6 +55,7 @@ class Renderer(object): self.__propsIF = get_interface(object_path, PROPS_IF_NAME) self.__playerIF = get_interface(object_path, PLAYER_IF_NAME) self.__pushhostIF = get_interface(object_path, PUSH_HOST_IF_NAME) + self.__deviceIF = get_interface(object_path, DEVICE_IF_NAME) def get_interfaces(self): try: @@ -122,6 +123,10 @@ class Renderer(object): def stop(self): self.__playerIF.Stop() + def print_icon(self, resolution): + bytes, mime = self.__deviceIF.GetIcon(resolution) + print "Icon mime type: " + mime + # Push Host methods def host_file(self, path): return self.__pushhostIF.HostFile(path) @@ -217,3 +222,5 @@ if __name__ == "__main__": print("\nProperties of %s on %s:" % (if_name, name)) print("¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯" + (len(name) + len(if_name)) * "¯") renderer.print_props(if_name) + + renderer.print_icon("")
\ No newline at end of file |