Message ID | 20240912174921.386856-5-frederic.danis@collabora.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Add BIP for AVRCP covert art OBEX client | expand |
Context | Check | Description |
---|---|---|
tedd_an/pre-ci_am | success | Success |
tedd_an/CheckPatch | success | CheckPatch PASS |
tedd_an/GitLint | fail | WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search 1: T3 Title has trailing punctuation (.): "[BlueZ,v2,4/7] obexd: Add BIP client for AVRCP cover art download." |
tedd_an/IncrementalBuild | success | Incremental Build PASS |
Hi Frédéric, On Thu, Sep 12, 2024 at 1:50 PM Frédéric Danis <frederic.danis@collabora.com> wrote: > > The cover art image handle is available in the metadata of the track > when the OBEX BIP session is connected to the PSM port provided > in AVRCP SDP record and available as org.bluez.MediaPlayer property. > > This service allows to get the thumbnail. > --- > Makefile.obexd | 1 + > obexd/client/bip-avrcp.c | 171 +++++++++++++++++++++++++++++++++++++++ > obexd/client/bip-avrcp.h | 12 +++ Id got with bit.{c,h} so we can reuse the implementation for BIP. > obexd/client/manager.c | 2 + > obexd/client/transfer.c | 16 ++++ > obexd/client/transfer.h | 2 + > 6 files changed, 204 insertions(+) > create mode 100644 obexd/client/bip-avrcp.c > create mode 100644 obexd/client/bip-avrcp.h > > diff --git a/Makefile.obexd b/Makefile.obexd > index 4cdce73af..8038d2327 100644 > --- a/Makefile.obexd > +++ b/Makefile.obexd > @@ -81,6 +81,7 @@ obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \ > obexd/client/ftp.h obexd/client/ftp.c \ > obexd/client/opp.h obexd/client/opp.c \ > obexd/client/map.h obexd/client/map.c \ > + obexd/client/bip-avrcp.h obexd/client/bip-avrcp.c \ > obexd/client/map-event.h obexd/client/map-event.c \ > obexd/client/transfer.h obexd/client/transfer.c \ > obexd/client/transport.h obexd/client/transport.c \ > diff --git a/obexd/client/bip-avrcp.c b/obexd/client/bip-avrcp.c > new file mode 100644 > index 000000000..ca702be5a > --- /dev/null > +++ b/obexd/client/bip-avrcp.c > @@ -0,0 +1,171 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * > + * OBEX Client > + * > + * Copyright (C) 2024 Collabora Ltd. > + * > + * > + */ > + > +#define _GNU_SOURCE > +#include <errno.h> > +#include <stdlib.h> > +#include <string.h> > + > +#include "gdbus/gdbus.h" > +#include "gobex/gobex.h" > + > +#include "obexd/src/log.h" > +#include "transfer.h" > +#include "session.h" > +#include "driver.h" > +#include "bip-avrcp.h" > + > +#define OBEX_BIP_AVRCP_UUID \ > + "\x71\x63\xDD\x54\x4A\x7E\x11\xE2\xB4\x7C\x00\x50\xC2\x49\x00\x48" > +#define OBEX_BIP_AVRCP_UUID_LEN 16 > + > +#define BIP_AVRCP_INTERFACE "org.bluez.obex.BipAvrcp1" > +#define ERROR_INTERFACE "org.bluez.obex.Error" > +#define BIP_AVRCP_UUID "0000111A-0000-1000-8000-00805f9b34fb" > + > +#define IMG_HANDLE_TAG 0x30 > + > +static DBusConnection *conn; > + > +struct bip_avrcp_data { > + struct obc_session *session; > +}; > + > +static DBusMessage *get_image_thumbnail(DBusConnection *connection, > + DBusMessage *message, void *user_data) > +{ > + struct bip_avrcp_data *bip_avrcp = user_data; > + const char *handle = NULL, *image_path = NULL; > + struct obc_transfer *transfer; > + GObexHeader *header; > + DBusMessage *reply = NULL; > + GError *err = NULL; > + > + DBG(""); > + > + if (dbus_message_get_args(message, NULL, > + DBUS_TYPE_STRING, &image_path, > + DBUS_TYPE_STRING, &handle, > + DBUS_TYPE_INVALID) == FALSE) { > + reply = g_dbus_create_error(message, > + ERROR_INTERFACE ".InvalidArguments", NULL); > + goto fail; > + } > + > + transfer = obc_transfer_get("x-bt/img-thm", 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); > + > + 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("GetImageThumbnail", > + GDBUS_ARGS({ "file", "s" }, { "handle", "s"}), > + GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }), > + get_image_thumbnail) }, > + { } > +}; > + > +static void bip_avrcp_free(void *data) > +{ > + struct bip_avrcp_data *bip_avrcp = data; > + > + obc_session_unref(bip_avrcp->session); > + g_free(bip_avrcp); > +} > + > +static int bip_avrcp_probe(struct obc_session *session) > +{ > + struct bip_avrcp_data *bip_avrcp; > + const char *path; > + > + path = obc_session_get_path(session); > + > + DBG("%s", path); > + > + bip_avrcp = g_try_new0(struct bip_avrcp_data, 1); > + if (!bip_avrcp) > + return -ENOMEM; > + > + bip_avrcp->session = obc_session_ref(session); > + > + if (!g_dbus_register_interface(conn, path, BIP_AVRCP_INTERFACE, > + bip_avrcp_methods, > + NULL, NULL, > + bip_avrcp, bip_avrcp_free)) { > + bip_avrcp_free(bip_avrcp); > + return -ENOMEM; > + } > + > + return 0; > +} > + > +static void bip_avrcp_remove(struct obc_session *session) > +{ > + const char *path = obc_session_get_path(session); > + > + DBG("%s", path); > + > + g_dbus_unregister_interface(conn, path, BIP_AVRCP_INTERFACE); > +} > + > +static struct obc_driver bip_avrcp = { > + .service = "BIP-AVRCP", > + .uuid = BIP_AVRCP_UUID, > + .target = OBEX_BIP_AVRCP_UUID, > + .target_len = OBEX_BIP_AVRCP_UUID_LEN, > + .probe = bip_avrcp_probe, > + .remove = bip_avrcp_remove > +}; This can stay as bip_arvcp, since obc_driver is per-uuid, but in the future if someone wants to add BIP uuid it just registers another driver. > +int bip_avrcp_init(void) > +{ > + int err; > + > + DBG(""); > + > + conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); > + if (!conn) > + return -EIO; > + > + err = obc_driver_register(&bip_avrcp); > + if (err < 0) > + goto failed; > + > + return 0; > + > +failed: > + dbus_connection_unref(conn); > + conn = NULL; > + return err; > +} > + > +void bip_avrcp_exit(void) > +{ > + DBG(""); > + > + dbus_connection_unref(conn); > + conn = NULL; > + > + obc_driver_unregister(&bip_avrcp); > +} > diff --git a/obexd/client/bip-avrcp.h b/obexd/client/bip-avrcp.h > new file mode 100644 > index 000000000..acd8068f2 > --- /dev/null > +++ b/obexd/client/bip-avrcp.h > @@ -0,0 +1,12 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * > + * OBEX Client > + * > + * Copyright (C) 2024 Collabora Ltd. > + * > + * > + */ > + > +int bip_avrcp_init(void); > +void bip_avrcp_exit(void); > diff --git a/obexd/client/manager.c b/obexd/client/manager.c > index 52c00fb0c..5078f56da 100644 > --- a/obexd/client/manager.c > +++ b/obexd/client/manager.c > @@ -32,6 +32,7 @@ > #include "pbap.h" > #include "sync.h" > #include "map.h" > +#include "bip-avrcp.h" > #include "manager.h" > > #define CLIENT_INTERFACE "org.bluez.obex.Client1" > @@ -258,6 +259,7 @@ static const struct obc_module { > { "pbap", pbap_init, pbap_exit }, > { "sync", sync_init, sync_exit }, > { "map", map_init, map_exit }, > + { "bip-avrcp", bip_avrcp_init, bip_avrcp_exit }, For the module it shall be just bip, avrcp specific UUID is handled by a dedicated driver. > { } > }; > > diff --git a/obexd/client/transfer.c b/obexd/client/transfer.c > index a7a85a0c0..fdf32a985 100644 > --- a/obexd/client/transfer.c > +++ b/obexd/client/transfer.c > @@ -57,6 +57,7 @@ struct obc_transfer { > GObex *obex; > uint8_t status; > GObexApparam *apparam; > + GSList *headers; > guint8 op; > struct transfer_callback *callback; > DBusConnection *conn; > @@ -820,6 +821,16 @@ static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err) > g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type, > strlen(transfer->type) + 1); > > + if (transfer->headers != NULL) { > + GSList *l; > + > + for (l = transfer->headers; l != NULL; l = g_slist_next(l)) { > + GObexHeader *hdr = l->data; > + > + g_obex_packet_add_header(req, hdr); > + } > + } This one seems to be a different change, so Id put it in a different patch. > + > if (transfer->apparam != NULL) { > hdr = g_obex_header_new_apparam(transfer->apparam); > g_obex_packet_add_header(req, hdr); > @@ -974,3 +985,8 @@ gint64 obc_transfer_get_size(struct obc_transfer *transfer) > { > return transfer->size; > } > + > +void obc_transfer_add_header(struct obc_transfer *transfer, void *data) > +{ > + transfer->headers = g_slist_append(transfer->headers, data); > +} > diff --git a/obexd/client/transfer.h b/obexd/client/transfer.h > index 323332a62..1ed195984 100644 > --- a/obexd/client/transfer.h > +++ b/obexd/client/transfer.h > @@ -47,3 +47,5 @@ gint64 obc_transfer_get_size(struct obc_transfer *transfer); > > DBusMessage *obc_transfer_create_dbus_reply(struct obc_transfer *transfer, > DBusMessage *message); > + > +void obc_transfer_add_header(struct obc_transfer *transfer, void *data); > -- > 2.34.1 > >
diff --git a/Makefile.obexd b/Makefile.obexd index 4cdce73af..8038d2327 100644 --- a/Makefile.obexd +++ b/Makefile.obexd @@ -81,6 +81,7 @@ obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \ obexd/client/ftp.h obexd/client/ftp.c \ obexd/client/opp.h obexd/client/opp.c \ obexd/client/map.h obexd/client/map.c \ + obexd/client/bip-avrcp.h obexd/client/bip-avrcp.c \ obexd/client/map-event.h obexd/client/map-event.c \ obexd/client/transfer.h obexd/client/transfer.c \ obexd/client/transport.h obexd/client/transport.c \ diff --git a/obexd/client/bip-avrcp.c b/obexd/client/bip-avrcp.c new file mode 100644 index 000000000..ca702be5a --- /dev/null +++ b/obexd/client/bip-avrcp.c @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * OBEX Client + * + * Copyright (C) 2024 Collabora Ltd. + * + * + */ + +#define _GNU_SOURCE +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "gdbus/gdbus.h" +#include "gobex/gobex.h" + +#include "obexd/src/log.h" +#include "transfer.h" +#include "session.h" +#include "driver.h" +#include "bip-avrcp.h" + +#define OBEX_BIP_AVRCP_UUID \ + "\x71\x63\xDD\x54\x4A\x7E\x11\xE2\xB4\x7C\x00\x50\xC2\x49\x00\x48" +#define OBEX_BIP_AVRCP_UUID_LEN 16 + +#define BIP_AVRCP_INTERFACE "org.bluez.obex.BipAvrcp1" +#define ERROR_INTERFACE "org.bluez.obex.Error" +#define BIP_AVRCP_UUID "0000111A-0000-1000-8000-00805f9b34fb" + +#define IMG_HANDLE_TAG 0x30 + +static DBusConnection *conn; + +struct bip_avrcp_data { + struct obc_session *session; +}; + +static DBusMessage *get_image_thumbnail(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct bip_avrcp_data *bip_avrcp = user_data; + const char *handle = NULL, *image_path = NULL; + struct obc_transfer *transfer; + GObexHeader *header; + DBusMessage *reply = NULL; + GError *err = NULL; + + DBG(""); + + if (dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &image_path, + DBUS_TYPE_STRING, &handle, + DBUS_TYPE_INVALID) == FALSE) { + reply = g_dbus_create_error(message, + ERROR_INTERFACE ".InvalidArguments", NULL); + goto fail; + } + + transfer = obc_transfer_get("x-bt/img-thm", 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); + + 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("GetImageThumbnail", + GDBUS_ARGS({ "file", "s" }, { "handle", "s"}), + GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }), + get_image_thumbnail) }, + { } +}; + +static void bip_avrcp_free(void *data) +{ + struct bip_avrcp_data *bip_avrcp = data; + + obc_session_unref(bip_avrcp->session); + g_free(bip_avrcp); +} + +static int bip_avrcp_probe(struct obc_session *session) +{ + struct bip_avrcp_data *bip_avrcp; + const char *path; + + path = obc_session_get_path(session); + + DBG("%s", path); + + bip_avrcp = g_try_new0(struct bip_avrcp_data, 1); + if (!bip_avrcp) + return -ENOMEM; + + bip_avrcp->session = obc_session_ref(session); + + if (!g_dbus_register_interface(conn, path, BIP_AVRCP_INTERFACE, + bip_avrcp_methods, + NULL, NULL, + bip_avrcp, bip_avrcp_free)) { + bip_avrcp_free(bip_avrcp); + return -ENOMEM; + } + + return 0; +} + +static void bip_avrcp_remove(struct obc_session *session) +{ + const char *path = obc_session_get_path(session); + + DBG("%s", path); + + g_dbus_unregister_interface(conn, path, BIP_AVRCP_INTERFACE); +} + +static struct obc_driver bip_avrcp = { + .service = "BIP-AVRCP", + .uuid = BIP_AVRCP_UUID, + .target = OBEX_BIP_AVRCP_UUID, + .target_len = OBEX_BIP_AVRCP_UUID_LEN, + .probe = bip_avrcp_probe, + .remove = bip_avrcp_remove +}; + +int bip_avrcp_init(void) +{ + int err; + + DBG(""); + + conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); + if (!conn) + return -EIO; + + err = obc_driver_register(&bip_avrcp); + if (err < 0) + goto failed; + + return 0; + +failed: + dbus_connection_unref(conn); + conn = NULL; + return err; +} + +void bip_avrcp_exit(void) +{ + DBG(""); + + dbus_connection_unref(conn); + conn = NULL; + + obc_driver_unregister(&bip_avrcp); +} diff --git a/obexd/client/bip-avrcp.h b/obexd/client/bip-avrcp.h new file mode 100644 index 000000000..acd8068f2 --- /dev/null +++ b/obexd/client/bip-avrcp.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * OBEX Client + * + * Copyright (C) 2024 Collabora Ltd. + * + * + */ + +int bip_avrcp_init(void); +void bip_avrcp_exit(void); diff --git a/obexd/client/manager.c b/obexd/client/manager.c index 52c00fb0c..5078f56da 100644 --- a/obexd/client/manager.c +++ b/obexd/client/manager.c @@ -32,6 +32,7 @@ #include "pbap.h" #include "sync.h" #include "map.h" +#include "bip-avrcp.h" #include "manager.h" #define CLIENT_INTERFACE "org.bluez.obex.Client1" @@ -258,6 +259,7 @@ static const struct obc_module { { "pbap", pbap_init, pbap_exit }, { "sync", sync_init, sync_exit }, { "map", map_init, map_exit }, + { "bip-avrcp", bip_avrcp_init, bip_avrcp_exit }, { } }; diff --git a/obexd/client/transfer.c b/obexd/client/transfer.c index a7a85a0c0..fdf32a985 100644 --- a/obexd/client/transfer.c +++ b/obexd/client/transfer.c @@ -57,6 +57,7 @@ struct obc_transfer { GObex *obex; uint8_t status; GObexApparam *apparam; + GSList *headers; guint8 op; struct transfer_callback *callback; DBusConnection *conn; @@ -820,6 +821,16 @@ static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err) g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type, strlen(transfer->type) + 1); + if (transfer->headers != NULL) { + GSList *l; + + for (l = transfer->headers; l != NULL; l = g_slist_next(l)) { + GObexHeader *hdr = l->data; + + g_obex_packet_add_header(req, hdr); + } + } + if (transfer->apparam != NULL) { hdr = g_obex_header_new_apparam(transfer->apparam); g_obex_packet_add_header(req, hdr); @@ -974,3 +985,8 @@ gint64 obc_transfer_get_size(struct obc_transfer *transfer) { return transfer->size; } + +void obc_transfer_add_header(struct obc_transfer *transfer, void *data) +{ + transfer->headers = g_slist_append(transfer->headers, data); +} diff --git a/obexd/client/transfer.h b/obexd/client/transfer.h index 323332a62..1ed195984 100644 --- a/obexd/client/transfer.h +++ b/obexd/client/transfer.h @@ -47,3 +47,5 @@ gint64 obc_transfer_get_size(struct obc_transfer *transfer); DBusMessage *obc_transfer_create_dbus_reply(struct obc_transfer *transfer, DBusMessage *message); + +void obc_transfer_add_header(struct obc_transfer *transfer, void *data);