Commit 45baf6c8 authored by Regis Merlino's avatar Regis Merlino

[Device] Add a GetIcon() method

Signed-off-by: default avatarRegis Merlino <regis.merlino@intel.com>
parent e95c135e
......@@ -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
----------------------
......
......@@ -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);
}
......@@ -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__ */
......@@ -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)
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment