Message ID | 20240916132813.165731-6-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 | success | Gitlint PASS |
tedd_an/IncrementalBuild | success | Incremental Build PASS |
Hi Frédéric, On Mon, Sep 16, 2024 at 9:28 AM 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.c | 171 +++++++++++++++++++++++++++++++++++++++++ > obexd/client/bip.h | 12 +++ > obexd/client/manager.c | 2 + > 4 files changed, 186 insertions(+) > create mode 100644 obexd/client/bip.c > create mode 100644 obexd/client/bip.h > > diff --git a/Makefile.obexd b/Makefile.obexd > index 4cdce73af..866147dd1 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.h obexd/client/bip.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.c b/obexd/client/bip.c > new file mode 100644 > index 000000000..f4af2834b > --- /dev/null > +++ b/obexd/client/bip.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.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" I'd go with org.bluez.obex.Image and then work the details of BIP vs BIP-AVRCP internally. > +#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); > + return reply; > + } > + > + 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", If we rename the interface to Image then this can be just "GetThumbnail". > + 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_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_exit(void) > +{ > + DBG(""); > + > + dbus_connection_unref(conn); > + conn = NULL; > + > + obc_driver_unregister(&bip_avrcp); > +} > diff --git a/obexd/client/bip.h b/obexd/client/bip.h > new file mode 100644 > index 000000000..18e3360f3 > --- /dev/null > +++ b/obexd/client/bip.h > @@ -0,0 +1,12 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * > + * OBEX Client > + * > + * Copyright (C) 2024 Collabora Ltd. > + * > + * > + */ > + > +int bip_init(void); > +void bip_exit(void); > diff --git a/obexd/client/manager.c b/obexd/client/manager.c > index 52c00fb0c..52f4d0179 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.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", bip_init, bip_exit }, > { } > }; > > -- > 2.34.1 > >
diff --git a/Makefile.obexd b/Makefile.obexd index 4cdce73af..866147dd1 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.h obexd/client/bip.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.c b/obexd/client/bip.c new file mode 100644 index 000000000..f4af2834b --- /dev/null +++ b/obexd/client/bip.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.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); + return reply; + } + + 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_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_exit(void) +{ + DBG(""); + + dbus_connection_unref(conn); + conn = NULL; + + obc_driver_unregister(&bip_avrcp); +} diff --git a/obexd/client/bip.h b/obexd/client/bip.h new file mode 100644 index 000000000..18e3360f3 --- /dev/null +++ b/obexd/client/bip.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * OBEX Client + * + * Copyright (C) 2024 Collabora Ltd. + * + * + */ + +int bip_init(void); +void bip_exit(void); diff --git a/obexd/client/manager.c b/obexd/client/manager.c index 52c00fb0c..52f4d0179 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.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", bip_init, bip_exit }, { } };