summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegis Merlino <regis.merlino@intel.com>2013-05-28 10:40:56 +0200
committerRegis Merlino <regis.merlino@intel.com>2013-05-29 11:37:39 +0200
commit45baf6c8d77ae4c7ecf43d92bacaecd2499ba4c6 (patch)
treea5d621224495d762dba34aeccde87d4ec7728487
parente95c135e09a86196d55a8e54a8c944cfab24e914 (diff)
downloaddleyna-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.txt10
-rw-r--r--libdleyna/renderer/device.c142
-rw-r--r--libdleyna/renderer/device.h11
-rw-r--r--libdleyna/renderer/server.c24
-rw-r--r--libdleyna/renderer/task.c30
-rw-r--r--libdleyna/renderer/task.h13
-rw-r--r--libdleyna/renderer/upnp.c26
-rw-r--r--libdleyna/renderer/upnp.h3
-rw-r--r--test/dbus/rendererconsole.py7
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