From: "Frédéric Danis" <frederic.danis@collabora.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v2 6/7] obexd: Add GetImage to bip-avrcp
Date: Thu, 12 Sep 2024 19:49:20 +0200 [thread overview]
Message-ID: <20240912174921.386856-7-frederic.danis@collabora.com> (raw)
In-Reply-To: <20240912174921.386856-1-frederic.danis@collabora.com>
Retrieves the image corresponding to the handle and the description,
as one of the descriptions retrieved by GetImageProperties, and store
it in a local file.
If the "transform" property description exists it should be set
to one of the value listed by GetImageProperties for this
description.
---
obexd/client/bip-avrcp.c | 155 ++++++++++++++++++++++++++++++++++++++
obexd/client/bip-common.c | 21 +++++-
obexd/client/bip-common.h | 5 ++
profiles/audio/avrcp.c | 10 ++-
4 files changed, 186 insertions(+), 5 deletions(-)
diff --git a/obexd/client/bip-avrcp.c b/obexd/client/bip-avrcp.c
index 272a288b4..8f00ddf8d 100644
--- a/obexd/client/bip-avrcp.c
+++ b/obexd/client/bip-avrcp.c
@@ -32,6 +32,14 @@
#define BIP_AVRCP_UUID "0000111A-0000-1000-8000-00805f9b34fb"
#define IMG_HANDLE_TAG 0x30
+#define IMG_DESC_TAG 0x71
+
+#define EOL_CHARS "\n"
+#define IMG_DESC_BEGIN "<image-descriptor version=\"1.0\">" EOL_CHARS
+#define IMG_BEGIN "<image encoding=\"%s\" pixel=\"%s\""
+#define IMG_TRANSFORM " transformation=\"%s\""
+#define IMG_END "/>" EOL_CHARS
+#define IMG_DESC_END "</image-descriptor>" EOL_CHARS
static DBusConnection *conn;
@@ -175,11 +183,158 @@ fail:
return reply;
}
+static gboolean parse_get_image_dict(DBusMessage *msg, char **path,
+ char **handle, char **pixel,
+ char **encoding, uint64_t *maxsize,
+ char **transform)
+{
+ DBusMessageIter iter, array;
+
+ DBG("");
+
+ *path = NULL;
+ *handle = NULL;
+ *pixel = NULL;
+ *encoding = NULL;
+ *transform = NULL;
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ goto failed;
+ dbus_message_iter_get_basic(&iter, path);
+ *path = g_strdup(*path);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ goto failed;
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, handle);
+ *handle = g_strdup(*handle);
+ dbus_message_iter_next(&iter);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ goto failed;
+
+ dbus_message_iter_recurse(&iter, &array);
+
+ while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key, *val;
+
+ dbus_message_iter_recurse(&array, &entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ return FALSE;
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+ switch (dbus_message_iter_get_arg_type(&value)) {
+ case DBUS_TYPE_STRING:
+ dbus_message_iter_get_basic(&value, &val);
+ if (g_str_equal(key, "pixel")) {
+ if (!parse_pixel_range(val, NULL, NULL, NULL))
+ goto failed;
+ *pixel = g_strdup(val);
+ } else if (g_str_equal(key, "encoding")) {
+ if (!verify_encoding(val))
+ goto failed;
+ *encoding = g_strdup(val);
+ if (*encoding == NULL)
+ goto failed;
+ } else if (g_str_equal(key, "transformation")) {
+ *transform = parse_transform(val);
+ if (*transform == NULL)
+ goto failed;
+ }
+ break;
+ case DBUS_TYPE_UINT64:
+ if (g_str_equal(key, "maxsize") == TRUE) {
+ dbus_message_iter_get_basic(&value, maxsize);
+ if (*maxsize == 0)
+ goto failed;
+ }
+ break;
+ }
+ dbus_message_iter_next(&array);
+ }
+
+ if (*pixel == NULL)
+ *pixel = strdup("");
+ if (*encoding == NULL)
+ *encoding = strdup("");
+
+ DBG("pixel: '%s' encoding: '%s' maxsize: '%lu' transform: '%s'",
+ *pixel, *encoding, *maxsize, *transform
+ );
+
+ return TRUE;
+failed:
+ g_free(*path);
+ g_free(*handle);
+ g_free(*pixel);
+ g_free(*encoding);
+ g_free(*transform);
+ return FALSE;
+}
+
+static DBusMessage *get_image(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct bip_avrcp_data *bip_avrcp = user_data;
+ char *handle = NULL, *image_path = NULL, *transform = NULL,
+ *encoding = NULL, *pixel = NULL;
+ uint64_t maxsize;
+ struct obc_transfer *transfer;
+ GObexHeader *header;
+ DBusMessage *reply = NULL;
+ GString *descriptor = NULL;
+ GError *err = NULL;
+
+ DBG("");
+
+ if (!parse_get_image_dict(message, &image_path, &handle, &pixel,
+ &encoding, &maxsize, &transform))
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".InvalidArguments", NULL);
+
+ transfer = obc_transfer_get("x-bt/img-img", NULL, image_path, &err);
+ if (transfer == NULL)
+ goto fail;
+
+ header = g_obex_header_new_unicode(IMG_HANDLE_TAG, handle);
+ obc_transfer_add_header(transfer, header);
+
+ descriptor = g_string_new(IMG_DESC_BEGIN);
+ g_string_append_printf(descriptor, IMG_BEGIN, encoding, pixel);
+ if (transform != NULL)
+ g_string_append_printf(descriptor, IMG_TRANSFORM, transform);
+ g_string_append(descriptor, IMG_END);
+ descriptor = g_string_append(descriptor, IMG_DESC_END);
+ header = g_obex_header_new_bytes(IMG_DESC_TAG, descriptor->str,
+ descriptor->len);
+ obc_transfer_add_header(transfer, header);
+ g_string_free(descriptor, TRUE);
+
+ if (!obc_session_queue(bip_avrcp->session, transfer, NULL, NULL, &err))
+ goto fail;
+
+ return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+ reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+ err->message);
+ g_error_free(err);
+ return reply;
+}
+
static const GDBusMethodTable bip_avrcp_methods[] = {
{ GDBUS_ASYNC_METHOD("GetImageProperties",
GDBUS_ARGS({ "handle", "s"}),
GDBUS_ARGS({ "properties", "aa{sv}" }),
get_image_properties) },
+ { GDBUS_ASYNC_METHOD("GetImage",
+ GDBUS_ARGS({ "file", "s" }, { "handle", "s"},
+ {"properties", "a{sv}"}),
+ GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+ get_image) },
{ GDBUS_ASYNC_METHOD("GetImageThumbnail",
GDBUS_ARGS({ "file", "s" }, { "handle", "s"}),
GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
diff --git a/obexd/client/bip-common.c b/obexd/client/bip-common.c
index b93921df5..16a199977 100644
--- a/obexd/client/bip-common.c
+++ b/obexd/client/bip-common.c
@@ -49,7 +49,7 @@ static const gchar *convBIP2IM(const gchar *encoding)
return NULL;
}
-static gboolean parse_pixel_range(const gchar *dim, unsigned int *lower_ret,
+gboolean parse_pixel_range(const gchar *dim, unsigned int *lower_ret,
unsigned int *upper_ret,
gboolean *fixed_ratio_ret)
{
@@ -139,6 +139,18 @@ char *transforms[] = {
NULL
};
+gboolean verify_encoding(const char *encoding)
+{
+ struct encconv_pair *et = encconv_table;
+
+ while (et->bip) {
+ if (g_strcmp0(encoding, et->bip) == 0)
+ return TRUE;
+ et++;
+ }
+ return FALSE;
+}
+
static gboolean verify_transform(const char *transform)
{
char **str = transforms;
@@ -151,6 +163,13 @@ static gboolean verify_transform(const char *transform)
return FALSE;
}
+char *parse_transform(const char *transform)
+{
+ if (!verify_transform(transform))
+ return NULL;
+ return g_strdup(transform);
+}
+
static char *parse_transform_list(const char *transform)
{
char **args = NULL, **arg = NULL;
diff --git a/obexd/client/bip-common.h b/obexd/client/bip-common.h
index 0fee54636..6e7aac375 100644
--- a/obexd/client/bip-common.h
+++ b/obexd/client/bip-common.h
@@ -13,6 +13,11 @@
struct prop_object;
+gboolean parse_pixel_range(const gchar *dim, unsigned int *lower_ret,
+ unsigned int *upper_ret,
+ gboolean *fixed_ratio_ret);
+gboolean verify_encoding(const char *encoding);
+char *parse_transform(const char *transform);
struct prop_object *parse_properties(char *data, unsigned int length,
int *err);
gboolean verify_properties(struct prop_object *obj);
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index fe24b5a92..ee750f50b 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -415,10 +415,12 @@ static sdp_record_t *avrcp_ct_record(bool browsing)
uint16_t lp = AVCTP_CONTROL_PSM;
uint16_t avctp_ver = 0x0103;
uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
- AVRCP_FEATURE_CATEGORY_2 |
- AVRCP_FEATURE_CATEGORY_3 |
- AVRCP_FEATURE_CATEGORY_4 |
- AVRCP_FEATURE_CT_GET_THUMBNAIL);
+ AVRCP_FEATURE_CATEGORY_2 |
+ AVRCP_FEATURE_CATEGORY_3 |
+ AVRCP_FEATURE_CATEGORY_4 |
+ AVRCP_FEATURE_CT_GET_IMAGE_PROP |
+ AVRCP_FEATURE_CT_GET_IMAGE |
+ AVRCP_FEATURE_CT_GET_THUMBNAIL);
record = sdp_record_alloc();
if (!record)
--
2.34.1
next prev parent reply other threads:[~2024-09-12 17:49 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-12 17:49 [PATCH BlueZ v2 0/7] Add BIP for AVRCP covert art OBEX client Frédéric Danis
2024-09-12 17:49 ` [PATCH BlueZ v2 1/7] obexd: Add PSM support to session create Frédéric Danis
2024-09-12 22:37 ` Add BIP for AVRCP covert art OBEX client bluez.test.bot
2024-09-12 17:49 ` [PATCH BlueZ v2 2/7] player: Add OBEX PSM port for cover art support Frédéric Danis
2024-09-12 17:49 ` [PATCH BlueZ v2 3/7] player: Add image handle support property Frédéric Danis
2024-09-12 17:49 ` [PATCH BlueZ v2 4/7] obexd: Add BIP client for AVRCP cover art download Frédéric Danis
2024-09-13 15:59 ` Luiz Augusto von Dentz
2024-09-12 17:49 ` [PATCH BlueZ v2 5/7] obexd: Add GetImageProperties to bip-avrcp Frédéric Danis
2024-09-12 17:49 ` Frédéric Danis [this message]
2024-09-13 16:05 ` [PATCH BlueZ v2 6/7] obexd: Add GetImage " Luiz Augusto von Dentz
2024-09-12 17:49 ` [PATCH BlueZ v2 7/7] doc: Add description of org.bluez.obex.BipAvrcp Frédéric Danis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240912174921.386856-7-frederic.danis@collabora.com \
--to=frederic.danis@collabora.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox