public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ 0/7] Add BIP for AVRCP covert art OBEX client
@ 2024-09-04 14:04 Frédéric Danis
  2024-09-04 14:04 ` [PATCH BlueZ 1/7] obexd: Add PSM support to session create Frédéric Danis
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Frédéric Danis @ 2024-09-04 14:04 UTC (permalink / raw)
  To: linux-bluetooth

If AVRCP Target supports Cover Art download its SDP record contains an
additional access protocol for OBEX with an LCAP PSM on which the OBEX
client session should connect to, with the specific OBEX target header
7163DD54-4A7E-11E2-B47C-0050C2490048.

Once the OBEX session is connected, the AVRCP track metadata will contain
an Image Handle which can be used to get the associated image using
GetImageThumbnail or GetImage with one of the description property found
with GetImageProperties.

Frédéric Danis (7):
  obexd: Add PSM support to session create
  player: Add OBEX PSM port for cover art support
  player: Add image handle support property
  obexd: Add BIP client for AVRCP cover art download.
  obexd: Add GetImageProperties to bip-avrcp
  obexd: Add GetImage to bip-avrcp
  doc: Add description of org.bluez.obex.BipAvrcp

 Makefile.am                     |   9 +-
 Makefile.obexd                  |   2 +
 doc/org.bluez.MediaPlayer.rst   |  10 +
 doc/org.bluez.obex.BipAvrcp.rst |  72 +++
 doc/org.bluez.obex.Client.rst   |   5 +
 doc/org.bluez.obex.Session.rst  |   5 +
 monitor/avctp.c                 |   3 +
 obexd/client/bip-avrcp.c        | 421 +++++++++++++++++
 obexd/client/bip-avrcp.h        |  12 +
 obexd/client/bip-common.c       | 769 ++++++++++++++++++++++++++++++++
 obexd/client/bip-common.h       |  25 ++
 obexd/client/manager.c          |  16 +-
 obexd/client/session.c          |  27 +-
 obexd/client/session.h          |   1 +
 obexd/client/transfer.c         |  16 +
 obexd/client/transfer.h         |   2 +
 profiles/audio/avrcp.c          |  64 ++-
 profiles/audio/avrcp.h          |   3 +-
 profiles/audio/player.c         |  29 ++
 profiles/audio/player.h         |   1 +
 tools/parser/avrcp.c            |   3 +
 21 files changed, 1476 insertions(+), 19 deletions(-)
 create mode 100644 doc/org.bluez.obex.BipAvrcp.rst
 create mode 100644 obexd/client/bip-avrcp.c
 create mode 100644 obexd/client/bip-avrcp.h
 create mode 100644 obexd/client/bip-common.c
 create mode 100644 obexd/client/bip-common.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 15+ messages in thread
* [PATCH BlueZ v2 1/7] obexd: Add PSM support to session create
@ 2024-09-12 17:49 Frédéric Danis
  2024-09-12 22:37 ` Add BIP for AVRCP covert art OBEX client bluez.test.bot
  0 siblings, 1 reply; 15+ messages in thread
From: Frédéric Danis @ 2024-09-12 17:49 UTC (permalink / raw)
  To: linux-bluetooth

An OBEX session can be connected to a RFCOMM channel or a L2CAP PSM.
---
 doc/org.bluez.obex.Client.rst  |  4 ++++
 doc/org.bluez.obex.Session.rst |  5 +++++
 obexd/client/manager.c         | 14 ++++++++++----
 obexd/client/session.c         | 27 ++++++++++++++++++++++++---
 obexd/client/session.h         |  1 +
 5 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/doc/org.bluez.obex.Client.rst b/doc/org.bluez.obex.Client.rst
index 9f77a9abc..5ae7cc5e8 100644
--- a/doc/org.bluez.obex.Client.rst
+++ b/doc/org.bluez.obex.Client.rst
@@ -52,6 +52,10 @@ object CreateSession(string destination, dict args)
 
 		Channel to be used.
 
+	:uint16 PSM:
+
+		L2CAP PSM to be used.
+
 	Possible errors:
 
 	:org.bluez.obex.Error.InvalidArguments:
diff --git a/doc/org.bluez.obex.Session.rst b/doc/org.bluez.obex.Session.rst
index 1cef9a53d..fc5f14e5d 100644
--- a/doc/org.bluez.obex.Session.rst
+++ b/doc/org.bluez.obex.Session.rst
@@ -50,6 +50,11 @@ byte Channel [readonly]
 
 	Bluetooth channel
 
+uint16 PSM [readonly]
+```````````````````````
+
+	Bluetooth L2CAP PSM
+
 string Target [readonly]
 ````````````````````````
 
diff --git a/obexd/client/manager.c b/obexd/client/manager.c
index ad1fbb04a..52c00fb0c 100644
--- a/obexd/client/manager.c
+++ b/obexd/client/manager.c
@@ -107,7 +107,8 @@ done:
 }
 
 static int parse_device_dict(DBusMessageIter *iter,
-		const char **source, const char **target, uint8_t *channel)
+		const char **source, const char **target, uint8_t *channel,
+		uint16_t *psm)
 {
 	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) {
 		DBusMessageIter entry, value;
@@ -130,6 +131,10 @@ static int parse_device_dict(DBusMessageIter *iter,
 			if (g_str_equal(key, "Channel") == TRUE)
 				dbus_message_iter_get_basic(&value, channel);
 			break;
+		case DBUS_TYPE_UINT16:
+			if (g_str_equal(key, "PSM") == TRUE)
+				dbus_message_iter_get_basic(&value, psm);
+			break;
 		}
 
 		dbus_message_iter_next(iter);
@@ -160,6 +165,7 @@ static DBusMessage *create_session(DBusConnection *connection,
 	struct send_data *data;
 	const char *source = NULL, *dest = NULL, *target = NULL;
 	uint8_t channel = 0;
+	uint16_t psm = 0;
 
 	dbus_message_iter_init(message, &iter);
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
@@ -175,8 +181,8 @@ static DBusMessage *create_session(DBusConnection *connection,
 
 	dbus_message_iter_recurse(&iter, &dict);
 
-	parse_device_dict(&dict, &source, &target, &channel);
-	if (dest == NULL || target == NULL)
+	parse_device_dict(&dict, &source, &target, &channel, &psm);
+	if (dest == NULL || target == NULL || (channel && psm))
 		return g_dbus_create_error(message,
 				ERROR_INTERFACE ".InvalidArguments", NULL);
 
@@ -188,7 +194,7 @@ static DBusMessage *create_session(DBusConnection *connection,
 	data->connection = dbus_connection_ref(connection);
 	data->message = dbus_message_ref(message);
 
-	session = obc_session_create(source, dest, target, channel,
+	session = obc_session_create(source, dest, target, channel, psm,
 					dbus_message_get_sender(message),
 					create_callback, data);
 	if (session != NULL) {
diff --git a/obexd/client/session.c b/obexd/client/session.c
index 7d8ebb04e..13a834e14 100644
--- a/obexd/client/session.c
+++ b/obexd/client/session.c
@@ -88,6 +88,7 @@ struct obc_session {
 	char *source;
 	char *destination;
 	uint8_t channel;
+	uint16_t psm;
 	struct obc_transport *transport;
 	struct obc_driver *driver;
 	char *path;		/* Session path */
@@ -471,6 +472,7 @@ static struct obc_session *session_find(const char *source,
 						const char *destination,
 						const char *service,
 						uint8_t channel,
+						uint16_t psm,
 						const char *owner)
 {
 	GSList *l;
@@ -490,6 +492,9 @@ static struct obc_session *session_find(const char *source,
 		if (channel && session->channel != channel)
 			continue;
 
+		if (psm && session->psm != psm)
+			continue;
+
 		if (g_strcmp0(owner, session->owner))
 			continue;
 
@@ -541,8 +546,9 @@ static int session_connect(struct obc_session *session,
 	}
 
 	session->id = transport->connect(session->source, session->destination,
-					driver->uuid, session->channel,
-					transport_func, callback);
+			driver->uuid,
+			session->channel ? session->channel : session->psm,
+			transport_func, callback);
 	if (session->id == 0) {
 		obc_session_unref(callback->session);
 		g_free(callback);
@@ -558,6 +564,7 @@ struct obc_session *obc_session_create(const char *source,
 						const char *destination,
 						const char *service,
 						uint8_t channel,
+						uint16_t psm,
 						const char *owner,
 						session_callback_t function,
 						void *user_data)
@@ -570,7 +577,8 @@ struct obc_session *obc_session_create(const char *source,
 	if (destination == NULL)
 		return NULL;
 
-	session = session_find(source, destination, service, channel, owner);
+	session = session_find(source, destination, service, channel, psm,
+				owner);
 	if (session != NULL)
 		goto proceed;
 
@@ -598,6 +606,7 @@ struct obc_session *obc_session_create(const char *source,
 	session->source = g_strdup(source);
 	session->destination = g_strdup(destination);
 	session->channel = channel;
+	session->psm = psm;
 	session->queue = g_queue_new();
 	session->folder = g_strdup("/");
 
@@ -762,6 +771,17 @@ static gboolean get_channel(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static gboolean get_psm(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct obc_session *session = data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
+							&session->psm);
+
+	return TRUE;
+}
+
 static const GDBusMethodTable session_methods[] = {
 	{ GDBUS_ASYNC_METHOD("GetCapabilities",
 				NULL, GDBUS_ARGS({ "capabilities", "s" }),
@@ -794,6 +814,7 @@ static const GDBusPropertyTable session_properties[] = {
 	{ "Source", "s", get_source, NULL, source_exists },
 	{ "Destination", "s", get_destination },
 	{ "Channel", "y", get_channel },
+	{ "PSM", "q", get_psm },
 	{ "Target", "s", get_target, NULL, target_exists },
 	{ }
 };
diff --git a/obexd/client/session.h b/obexd/client/session.h
index 2c646df1a..19c3f3687 100644
--- a/obexd/client/session.h
+++ b/obexd/client/session.h
@@ -22,6 +22,7 @@ struct obc_session *obc_session_create(const char *source,
 						const char *destination,
 						const char *service,
 						uint8_t channel,
+						uint16_t psm,
 						const char *owner,
 						session_callback_t function,
 						void *user_data);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH BlueZ v3 1/9] obexd: Add PSM support to session create
@ 2024-09-16 13:28 Frédéric Danis
  2024-09-16 18:47 ` Add BIP for AVRCP covert art OBEX client bluez.test.bot
  0 siblings, 1 reply; 15+ messages in thread
From: Frédéric Danis @ 2024-09-16 13:28 UTC (permalink / raw)
  To: linux-bluetooth

An OBEX session can be connected to a RFCOMM channel or a L2CAP PSM.
---
 doc/org.bluez.obex.Client.rst  |  4 ++++
 doc/org.bluez.obex.Session.rst |  5 +++++
 obexd/client/manager.c         | 14 ++++++++++----
 obexd/client/session.c         | 27 ++++++++++++++++++++++++---
 obexd/client/session.h         |  1 +
 5 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/doc/org.bluez.obex.Client.rst b/doc/org.bluez.obex.Client.rst
index 9f77a9abc..5ae7cc5e8 100644
--- a/doc/org.bluez.obex.Client.rst
+++ b/doc/org.bluez.obex.Client.rst
@@ -52,6 +52,10 @@ object CreateSession(string destination, dict args)
 
 		Channel to be used.
 
+	:uint16 PSM:
+
+		L2CAP PSM to be used.
+
 	Possible errors:
 
 	:org.bluez.obex.Error.InvalidArguments:
diff --git a/doc/org.bluez.obex.Session.rst b/doc/org.bluez.obex.Session.rst
index 1cef9a53d..fc5f14e5d 100644
--- a/doc/org.bluez.obex.Session.rst
+++ b/doc/org.bluez.obex.Session.rst
@@ -50,6 +50,11 @@ byte Channel [readonly]
 
 	Bluetooth channel
 
+uint16 PSM [readonly]
+```````````````````````
+
+	Bluetooth L2CAP PSM
+
 string Target [readonly]
 ````````````````````````
 
diff --git a/obexd/client/manager.c b/obexd/client/manager.c
index ad1fbb04a..52c00fb0c 100644
--- a/obexd/client/manager.c
+++ b/obexd/client/manager.c
@@ -107,7 +107,8 @@ done:
 }
 
 static int parse_device_dict(DBusMessageIter *iter,
-		const char **source, const char **target, uint8_t *channel)
+		const char **source, const char **target, uint8_t *channel,
+		uint16_t *psm)
 {
 	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) {
 		DBusMessageIter entry, value;
@@ -130,6 +131,10 @@ static int parse_device_dict(DBusMessageIter *iter,
 			if (g_str_equal(key, "Channel") == TRUE)
 				dbus_message_iter_get_basic(&value, channel);
 			break;
+		case DBUS_TYPE_UINT16:
+			if (g_str_equal(key, "PSM") == TRUE)
+				dbus_message_iter_get_basic(&value, psm);
+			break;
 		}
 
 		dbus_message_iter_next(iter);
@@ -160,6 +165,7 @@ static DBusMessage *create_session(DBusConnection *connection,
 	struct send_data *data;
 	const char *source = NULL, *dest = NULL, *target = NULL;
 	uint8_t channel = 0;
+	uint16_t psm = 0;
 
 	dbus_message_iter_init(message, &iter);
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
@@ -175,8 +181,8 @@ static DBusMessage *create_session(DBusConnection *connection,
 
 	dbus_message_iter_recurse(&iter, &dict);
 
-	parse_device_dict(&dict, &source, &target, &channel);
-	if (dest == NULL || target == NULL)
+	parse_device_dict(&dict, &source, &target, &channel, &psm);
+	if (dest == NULL || target == NULL || (channel && psm))
 		return g_dbus_create_error(message,
 				ERROR_INTERFACE ".InvalidArguments", NULL);
 
@@ -188,7 +194,7 @@ static DBusMessage *create_session(DBusConnection *connection,
 	data->connection = dbus_connection_ref(connection);
 	data->message = dbus_message_ref(message);
 
-	session = obc_session_create(source, dest, target, channel,
+	session = obc_session_create(source, dest, target, channel, psm,
 					dbus_message_get_sender(message),
 					create_callback, data);
 	if (session != NULL) {
diff --git a/obexd/client/session.c b/obexd/client/session.c
index 7d8ebb04e..13a834e14 100644
--- a/obexd/client/session.c
+++ b/obexd/client/session.c
@@ -88,6 +88,7 @@ struct obc_session {
 	char *source;
 	char *destination;
 	uint8_t channel;
+	uint16_t psm;
 	struct obc_transport *transport;
 	struct obc_driver *driver;
 	char *path;		/* Session path */
@@ -471,6 +472,7 @@ static struct obc_session *session_find(const char *source,
 						const char *destination,
 						const char *service,
 						uint8_t channel,
+						uint16_t psm,
 						const char *owner)
 {
 	GSList *l;
@@ -490,6 +492,9 @@ static struct obc_session *session_find(const char *source,
 		if (channel && session->channel != channel)
 			continue;
 
+		if (psm && session->psm != psm)
+			continue;
+
 		if (g_strcmp0(owner, session->owner))
 			continue;
 
@@ -541,8 +546,9 @@ static int session_connect(struct obc_session *session,
 	}
 
 	session->id = transport->connect(session->source, session->destination,
-					driver->uuid, session->channel,
-					transport_func, callback);
+			driver->uuid,
+			session->channel ? session->channel : session->psm,
+			transport_func, callback);
 	if (session->id == 0) {
 		obc_session_unref(callback->session);
 		g_free(callback);
@@ -558,6 +564,7 @@ struct obc_session *obc_session_create(const char *source,
 						const char *destination,
 						const char *service,
 						uint8_t channel,
+						uint16_t psm,
 						const char *owner,
 						session_callback_t function,
 						void *user_data)
@@ -570,7 +577,8 @@ struct obc_session *obc_session_create(const char *source,
 	if (destination == NULL)
 		return NULL;
 
-	session = session_find(source, destination, service, channel, owner);
+	session = session_find(source, destination, service, channel, psm,
+				owner);
 	if (session != NULL)
 		goto proceed;
 
@@ -598,6 +606,7 @@ struct obc_session *obc_session_create(const char *source,
 	session->source = g_strdup(source);
 	session->destination = g_strdup(destination);
 	session->channel = channel;
+	session->psm = psm;
 	session->queue = g_queue_new();
 	session->folder = g_strdup("/");
 
@@ -762,6 +771,17 @@ static gboolean get_channel(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static gboolean get_psm(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct obc_session *session = data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
+							&session->psm);
+
+	return TRUE;
+}
+
 static const GDBusMethodTable session_methods[] = {
 	{ GDBUS_ASYNC_METHOD("GetCapabilities",
 				NULL, GDBUS_ARGS({ "capabilities", "s" }),
@@ -794,6 +814,7 @@ static const GDBusPropertyTable session_properties[] = {
 	{ "Source", "s", get_source, NULL, source_exists },
 	{ "Destination", "s", get_destination },
 	{ "Channel", "y", get_channel },
+	{ "PSM", "q", get_psm },
 	{ "Target", "s", get_target, NULL, target_exists },
 	{ }
 };
diff --git a/obexd/client/session.h b/obexd/client/session.h
index 2c646df1a..19c3f3687 100644
--- a/obexd/client/session.h
+++ b/obexd/client/session.h
@@ -22,6 +22,7 @@ struct obc_session *obc_session_create(const char *source,
 						const char *destination,
 						const char *service,
 						uint8_t channel,
+						uint16_t psm,
 						const char *owner,
 						session_callback_t function,
 						void *user_data);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread
* [PATCH BlueZ v4 1/5] obexd: Add BIP client for AVRCP cover art download
@ 2024-09-17  7:42 Frédéric Danis
  2024-09-17 11:31 ` Add BIP for AVRCP covert art OBEX client bluez.test.bot
  0 siblings, 1 reply; 15+ messages in thread
From: Frédéric Danis @ 2024-09-17  7:42 UTC (permalink / raw)
  To: linux-bluetooth

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 +
 doc/org.bluez.obex.Client.rst |   1 +
 obexd/client/bip.c            | 171 ++++++++++++++++++++++++++++++++++
 obexd/client/bip.h            |  12 +++
 obexd/client/manager.c        |   2 +
 5 files changed, 187 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/doc/org.bluez.obex.Client.rst b/doc/org.bluez.obex.Client.rst
index 5ae7cc5e8..f20dd5baa 100644
--- a/doc/org.bluez.obex.Client.rst
+++ b/doc/org.bluez.obex.Client.rst
@@ -43,6 +43,7 @@ object CreateSession(string destination, dict args)
 		:"opp":
 		:"pbap":
 		:"sync":
+		:"bip-avrcp":
 
 	:string Source:
 
diff --git a/obexd/client/bip.c b/obexd/client/bip.c
new file mode 100644
index 000000000..252bc4cec
--- /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 IMAGE_INTERFACE "org.bluez.obex.Image1"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+#define IMAGE_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_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("GetThumbnail",
+		GDBUS_ARGS({ "file", "s" }, { "handle", "s"}),
+		GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+		get_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, IMAGE_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, IMAGE_INTERFACE);
+}
+
+static struct obc_driver bip_avrcp = {
+	.service = "BIP-AVRCP",
+	.uuid = IMAGE_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


^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2024-09-17 11:31 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-04 14:04 [PATCH BlueZ 0/7] Add BIP for AVRCP covert art OBEX client Frédéric Danis
2024-09-04 14:04 ` [PATCH BlueZ 1/7] obexd: Add PSM support to session create Frédéric Danis
2024-09-04 17:22   ` Add BIP for AVRCP covert art OBEX client bluez.test.bot
2024-09-04 14:04 ` [PATCH BlueZ 2/7] player: Add OBEX PSM port for cover art support Frédéric Danis
2024-09-04 15:14   ` Luiz Augusto von Dentz
2024-09-04 17:08     ` Frédéric Danis
2024-09-04 14:04 ` [PATCH BlueZ 3/7] player: Add image handle support property Frédéric Danis
2024-09-04 15:07   ` Luiz Augusto von Dentz
2024-09-04 14:04 ` [PATCH BlueZ 4/7] obexd: Add BIP client for AVRCP cover art download Frédéric Danis
2024-09-04 14:04 ` [PATCH BlueZ 5/7] obexd: Add GetImageProperties to bip-avrcp Frédéric Danis
2024-09-04 14:04 ` [PATCH BlueZ 6/7] obexd: Add GetImage " Frédéric Danis
2024-09-04 14:04 ` [PATCH BlueZ 7/7] doc: Add description of org.bluez.obex.BipAvrcp Frédéric Danis
  -- strict thread matches above, loose matches on Subject: below --
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-16 13:28 [PATCH BlueZ v3 1/9] obexd: Add PSM support to session create Frédéric Danis
2024-09-16 18:47 ` Add BIP for AVRCP covert art OBEX client bluez.test.bot
2024-09-17  7:42 [PATCH BlueZ v4 1/5] obexd: Add BIP client for AVRCP cover art download Frédéric Danis
2024-09-17 11:31 ` Add BIP for AVRCP covert art OBEX client bluez.test.bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox