public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ v1 01/13] bass: Only attach client if initiator
@ 2025-10-16 21:00 Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 02/13] device: Add initial support for setting DEVICE_FLAG_PAST Luiz Augusto von Dentz
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This makes calling to bt_bass_attach conditional to being the initiator
of the connection, otherwise both device may act as both roles which is
not recommended.
---
 profiles/audio/bass.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index d42740ca4afb..e4d343a1fc02 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -1735,7 +1735,11 @@ static int bass_accept(struct btd_service *service)
 		return -EINVAL;
 	}
 
-	if (!bt_bass_attach(data->bass, client)) {
+	/* Only attach client if initiator of the connection otherwise act as
+	 * delegator.
+	 */
+	if (btd_service_is_initiator(service) &&
+			!bt_bass_attach(data->bass, client)) {
 		error("BASS unable to attach");
 		return -EINVAL;
 	}
-- 
2.51.0


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

* [PATCH BlueZ v1 02/13] device: Add initial support for setting DEVICE_FLAG_PAST
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 03/13] bass: Add " Luiz Augusto von Dentz
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This introduces device_set_past_support which can be used by drivers
to indicate that DEVICE_FLAG_PAST shall be changed.
---
 src/adapter.c | 31 +++++++++++++++++++++++--------
 src/adapter.h |  2 +-
 src/device.c  | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 src/device.h  |  3 +++
 4 files changed, 74 insertions(+), 9 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 1ee2f3a08164..4452034630f8 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -5640,6 +5640,8 @@ static void add_device_complete(uint8_t status, uint16_t length,
 	struct btd_adapter *adapter = user_data;
 	struct btd_device *dev;
 	char addr[18];
+	uint32_t flags;
+
 
 	if (length < sizeof(*rp)) {
 		btd_error(adapter->dev_id,
@@ -5669,8 +5671,7 @@ static void add_device_complete(uint8_t status, uint16_t length,
 	DBG("%s (%u) added to kernel connect list", addr, rp->addr.type);
 
 	if (btd_opts.device_privacy) {
-		uint32_t flags = btd_device_get_current_flags(dev);
-
+		flags = btd_device_get_current_flags(dev);
 		/* Set Device Privacy Mode if it has not set the flag yet. */
 		if (!(flags & DEVICE_FLAG_DEVICE_PRIVACY)) {
 			/* Include the pending flags, or they may get
@@ -5682,8 +5683,18 @@ static void add_device_complete(uint8_t status, uint16_t length,
 						DEVICE_FLAG_DEVICE_PRIVACY,
 						set_device_privacy_complete,
 						dev);
+			return;
 		}
 	}
+
+	/* Check if any flag was marked as pending before ADD_DEVICE
+	 * complete then set it now
+	 */
+	flags = btd_device_get_pending_flags(dev);
+	if (flags)
+		adapter_set_device_flags(adapter, dev, flags,
+						set_device_privacy_complete,
+						dev);
 }
 
 void adapter_auto_connect_add(struct btd_adapter *adapter,
@@ -5725,7 +5736,7 @@ void adapter_auto_connect_add(struct btd_adapter *adapter,
 	adapter->connect_list = g_slist_append(adapter->connect_list, device);
 }
 
-void adapter_set_device_flags(struct btd_adapter *adapter,
+int adapter_set_device_flags(struct btd_adapter *adapter,
 				struct btd_device *device, uint32_t flags,
 				mgmt_request_func_t func, void *user_data)
 {
@@ -5737,14 +5748,15 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
 	uint8_t bdaddr_type;
 	bool ll_privacy = btd_adapter_has_settings(adapter,
 						MGMT_SETTING_LL_PRIVACY);
+	unsigned int id;
 
 	if (!btd_has_kernel_features(KERNEL_CONN_CONTROL) ||
-				(supported | flags) != supported)
-		return;
+			(supported && (supported | flags) != supported))
+		return -EINVAL;
 
 	/* Check if changing flags are pending */
 	if ((current ^ flags) == (flags & pending))
-		return;
+		return -EINPROGRESS;
 
 	/* Set Device Privacy Mode if it has not set the flag yet. */
 	if (btd_opts.device_privacy && !(flags & DEVICE_FLAG_DEVICE_PRIVACY))
@@ -5764,9 +5776,12 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
 	cp.addr.type = bdaddr_type;
 	cp.current_flags = cpu_to_le32(flags);
 
-	if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id,
-		  sizeof(cp), &cp, func, user_data, NULL))
+	id = mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id,
+			  sizeof(cp), &cp, func, user_data, NULL);
+	if (id != 0)
 		btd_device_set_pending_flags(device, flags);
+
+	return id == 0 ? -EBUSY : 0;
 }
 
 static void device_flags_changed_callback(uint16_t index, uint16_t length,
diff --git a/src/adapter.h b/src/adapter.h
index ad81a10b1bb1..dd0c90d9cb3a 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -237,7 +237,7 @@ void adapter_connect_list_remove(struct btd_adapter *adapter,
 typedef void (*adapter_set_device_flags_func_t)(uint8_t status, uint16_t length,
 						const void *param,
 						void *user_data);
-void adapter_set_device_flags(struct btd_adapter *adapter,
+int adapter_set_device_flags(struct btd_adapter *adapter,
 				struct btd_device *device, uint32_t flags,
 				adapter_set_device_flags_func_t func,
 				void *user_data);
diff --git a/src/device.c b/src/device.c
index 8d74ae0ea0ff..3e907858b9d3 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1733,6 +1733,53 @@ void device_set_wake_allowed(struct btd_device *device, bool wake_allowed,
 					set_wake_allowed_complete, device);
 }
 
+static void set_past_complete(uint8_t status, uint16_t length,
+					 const void *param, void *user_data)
+{
+	const struct mgmt_rp_set_device_flags *rp = param;
+	struct btd_device *dev = user_data;
+
+	if (status != MGMT_STATUS_SUCCESS) {
+		error("Set device flags return status: %s",
+					mgmt_errstr(status));
+		return;
+	}
+
+	if (length < sizeof(*rp)) {
+		error("Too small Set Device Flags complete event: %d", length);
+		return;
+	}
+
+	btd_device_flags_changed(dev, dev->supported_flags, dev->pending_flags);
+}
+
+void device_set_past_support(struct btd_device *device, bool value)
+{
+	uint32_t flags;
+	int err;
+
+	if (btd_device_flags_enabled(device, DEVICE_FLAG_PAST) == value)
+		return;
+
+	DBG("value %s", value ? "true" : "false");
+
+	flags = device->current_flags;
+
+	/* Include the pending flags, or they may get overwritten. */
+	flags |= device->pending_flags;
+
+	if (value)
+		flags |= DEVICE_FLAG_PAST;
+	else
+		flags &= ~DEVICE_FLAG_PAST;
+
+	err = adapter_set_device_flags(device->adapter, device, flags,
+					set_past_complete, device);
+
+	if (err)
+		error("Failed to set past support: %s", strerror(-err));
+}
+
 static gboolean
 dev_property_get_wake_allowed(const GDBusPropertyTable *property,
 			     DBusMessageIter *iter, void *data)
diff --git a/src/device.h b/src/device.h
index 9ff9cdfefc28..6ed8affa0d4a 100644
--- a/src/device.h
+++ b/src/device.h
@@ -158,6 +158,9 @@ void device_set_wake_support(struct btd_device *device, bool wake_support);
 void device_set_wake_override(struct btd_device *device, bool wake_override);
 void device_set_wake_allowed(struct btd_device *device, bool wake_allowed,
 			     guint32 id);
+
+void device_set_past_support(struct btd_device *device, bool value);
+
 void device_set_refresh_discovery(struct btd_device *dev, bool refresh);
 
 typedef void (*disconnect_watch) (struct btd_device *device, gboolean removal,
-- 
2.51.0


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

* [PATCH BlueZ v1 03/13] bass: Add support for setting DEVICE_FLAG_PAST
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 02/13] device: Add initial support for setting DEVICE_FLAG_PAST Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 04/13] MediaAssistant: Add Device option to Push Luiz Augusto von Dentz
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This attempts to check if setting DEVICE_FLAG_PAST is possible based on
the MGMT settings.
---
 profiles/audio/bass.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index e4d343a1fc02..73bdf52128f9 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -30,6 +30,7 @@
 #include "bluetooth/bluetooth.h"
 #include "bluetooth/uuid.h"
 #include "bluetooth/iso.h"
+#include "bluetooth/mgmt.h"
 
 #include "src/dbus-common.h"
 #include "src/shared/util.h"
@@ -1253,8 +1254,17 @@ static void bass_data_add(struct bass_data *data)
 
 	queue_push_tail(sessions, data);
 
-	if (data->service)
+	if (data->service) {
+		struct btd_adapter *adapter = device_get_adapter(data->device);
+		bool initiator = btd_service_is_initiator(data->service);
+
 		btd_service_set_user_data(data->service, data);
+		if ((!initiator && btd_adapter_has_settings(adapter,
+				MGMT_SETTING_PAST_RECEIVER)) || (initiator &&
+				btd_adapter_has_settings(adapter,
+				MGMT_SETTING_PAST_SENDER)))
+			device_set_past_support(data->device, true);
+	}
 }
 
 static bool match_data(const void *data, const void *match_data)
-- 
2.51.0


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

* [PATCH BlueZ v1 04/13] MediaAssistant: Add Device option to Push
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 02/13] device: Add initial support for setting DEVICE_FLAG_PAST Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 03/13] bass: Add " Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 05/13] shared/bap: Add bt_bap_get_db Luiz Augusto von Dentz
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This enables MediaAssistant.Push to work with local broadcast sources.
---
 doc/org.bluez.MediaAssistant.rst | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/doc/org.bluez.MediaAssistant.rst b/doc/org.bluez.MediaAssistant.rst
index 64e689f8621d..8650d8abb379 100644
--- a/doc/org.bluez.MediaAssistant.rst
+++ b/doc/org.bluez.MediaAssistant.rst
@@ -40,6 +40,11 @@ Values:
 
 		See QoS property.
 
+	:object Device [ISO only, State=local only]:
+
+		Push to a specific device. Device must be connected and with
+		an active BASS session.
+
 Properties
 ----------
 
@@ -52,6 +57,7 @@ Indicates the state of the assistant object. Possible values are:
 :"pending": assistant object was pushed (stream information was sent to the peer)
 :"requesting": remote device requires Broadcast_Code
 :"active": remote device started receiving stream
+:"local": assistant object was created for a local stream
 
 array{byte} Metadata [readwrite, ISO Only, experimental]
 ````````````````````````````````````````````````````````
@@ -59,7 +65,7 @@ array{byte} Metadata [readwrite, ISO Only, experimental]
 Indicates stream Metadata.
 
 dict QoS [readwrite, ISO only, experimental]
-`````````````````````````````````````````````````````
+````````````````````````````````````````````
 
 Indicates stream QoS capabilities.
 
-- 
2.51.0


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

* [PATCH BlueZ v1 05/13] shared/bap: Add bt_bap_get_db
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 04/13] MediaAssistant: Add Device option to Push Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 06/13] shared/bap: Fix no calling attach callback on bt_bap_attach_broadcast Luiz Augusto von Dentz
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds bt_bap_get_db which can be used to access the gatt_db passed
to bt_bap_new.
---
 src/shared/bap.c | 11 +++++++++++
 src/shared/bap.h |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/src/shared/bap.c b/src/shared/bap.c
index fd52db3160a2..c564297518d6 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -4653,6 +4653,17 @@ struct bt_att *bt_bap_get_att(struct bt_bap *bap)
 	return bt_gatt_client_get_att(bap->client);
 }
 
+struct gatt_db *bt_bap_get_db(struct bt_bap *bap, bool remote)
+{
+	if (!bap)
+		return NULL;
+
+	if (remote)
+		return bap->rdb ? bap->rdb->db : NULL;
+
+	return bap->ldb ? bap->ldb->db : NULL;
+}
+
 struct bt_bap *bt_bap_ref(struct bt_bap *bap)
 {
 	if (!bap)
diff --git a/src/shared/bap.h b/src/shared/bap.h
index fba8b6b17884..efeed604dcaa 100644
--- a/src/shared/bap.h
+++ b/src/shared/bap.h
@@ -128,6 +128,8 @@ void *bt_bap_get_user_data(struct bt_bap *bap);
 
 struct bt_att *bt_bap_get_att(struct bt_bap *bap);
 
+struct gatt_db *bt_bap_get_db(struct bt_bap *bap, bool remote);
+
 struct bt_bap *bt_bap_ref(struct bt_bap *bap);
 void bt_bap_unref(struct bt_bap *bap);
 
-- 
2.51.0


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

* [PATCH BlueZ v1 06/13] shared/bap: Fix no calling attach callback on bt_bap_attach_broadcast
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 05/13] shared/bap: Add bt_bap_get_db Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 07/13] shared/bap: Fix bt_bap_stream_io_get_qos for broadcast streams Luiz Augusto von Dentz
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

bt_bap_attach_broadcast shall call the attach callback just as any
other instance of bt_bap_attach.
---
 src/shared/bap.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/shared/bap.c b/src/shared/bap.c
index c564297518d6..6573ea39c93b 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -5684,6 +5684,8 @@ bool bt_bap_attach_broadcast(struct bt_bap *bap)
 
 	queue_push_tail(sessions, bap);
 
+	queue_foreach(bap_cbs, bap_attached, bap);
+
 	ep = bap_get_endpoint_bcast(bap->remote_eps, bap->ldb,
 				BT_BAP_BCAST_SOURCE);
 	if (ep)
-- 
2.51.0


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

* [PATCH BlueZ v1 07/13] shared/bap: Fix bt_bap_stream_io_get_qos for broadcast streams
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 06/13] shared/bap: Fix no calling attach callback on bt_bap_attach_broadcast Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 08/13] gatt-database: Add btd_gatt_database_get and btd_gatt_database_get_adapter Luiz Augusto von Dentz
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This makes bt_bap_stream_io_get_qos work with broadcast streams.
---
 src/shared/bap.c | 38 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/src/shared/bap.c b/src/shared/bap.c
index 6573ea39c93b..427d18627def 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -6800,6 +6800,36 @@ static void bap_stream_get_out_qos(void *data, void *user_data)
 	*qos = &stream->qos;
 }
 
+static void bap_stream_bcast_get_out_qos(void *data, void *user_data)
+{
+	struct bt_bap_stream *stream = data;
+	struct bt_bap_qos **qos = user_data;
+
+	if (!stream)
+		return;
+
+	if (!qos || *qos || stream->ep->dir != BT_BAP_BCAST_SINK ||
+				!stream->qos.bcast.io_qos.sdu)
+		return;
+
+	*qos = &stream->qos;
+}
+
+static void bap_stream_bcast_get_in_qos(void *data, void *user_data)
+{
+	struct bt_bap_stream *stream = data;
+	struct bt_bap_qos **qos = user_data;
+
+	if (!stream)
+		return;
+
+	if (!qos || *qos || stream->ep->dir != BT_BAP_BCAST_SOURCE ||
+				!stream->qos.bcast.io_qos.sdu)
+		return;
+
+	*qos = &stream->qos;
+}
+
 bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream,
 					struct bt_bap_qos **in,
 					struct bt_bap_qos **out)
@@ -6816,13 +6846,19 @@ bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream,
 		bap_stream_get_out_qos(stream, out);
 		queue_foreach(stream->links, bap_stream_get_in_qos, in);
 		break;
+	case BT_BAP_BCAST_SOURCE:
+		bap_stream_bcast_get_in_qos(stream, in);
+		break;
+	case BT_BAP_BCAST_SINK:
+		bap_stream_bcast_get_out_qos(stream, out);
+		break;
 	default:
 		return false;
 	}
 
 	DBG(stream->bap, "in %p out %p", in ? *in : NULL, out ? *out : NULL);
 
-	return in && out;
+	return (in && *in) || (out && *out);
 }
 
 static void bap_stream_get_dir(void *data, void *user_data)
-- 
2.51.0


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

* [PATCH BlueZ v1 08/13] gatt-database: Add btd_gatt_database_get and btd_gatt_database_get_adapter
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (5 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 07/13] shared/bap: Fix bt_bap_stream_io_get_qos for broadcast streams Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 09/13] bass: Implement Device option for Push Luiz Augusto von Dentz
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds btd_gatt_database_get and btd_gatt_database_get_adapter
that makes it possible to resolve the btd_gatt_database and btd_adapter
respectively when only the gatt_db is available.
---
 src/gatt-database.c | 35 +++++++++++++++++++++++++++++++++++
 src/gatt-database.h |  4 ++++
 2 files changed, 39 insertions(+)

diff --git a/src/gatt-database.c b/src/gatt-database.c
index eea3f600a8b0..ff5fa3bcc8b2 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -209,6 +209,8 @@ struct device_info {
 	uint8_t bdaddr_type;
 };
 
+static struct queue *dbs = NULL;
+
 static void ccc_cb_free(void *data)
 {
 	struct ccc_cb_data *ccc_cb = data;
@@ -4123,6 +4125,11 @@ bredr:
 	if (!database->db_id)
 		goto fail;
 
+	if (!dbs)
+		dbs = queue_new();
+
+	queue_push_tail(dbs, database);
+
 	return database;
 
 fail:
@@ -4143,6 +4150,34 @@ void btd_gatt_database_destroy(struct btd_gatt_database *database)
 	gatt_database_free(database);
 }
 
+static bool match_db(const void *data, const void *user_data)
+{
+	const struct btd_gatt_database *database = data;
+	const struct gatt_db *db = user_data;
+
+	return database->db == db;
+}
+
+struct btd_gatt_database *btd_gatt_database_get(struct gatt_db *db)
+{
+	struct btd_gatt_database *database;
+
+	database = queue_find(dbs, match_db, db);
+	if (!database)
+		return NULL;
+
+	return database;
+}
+
+struct btd_adapter *
+btd_gatt_database_get_adapter(struct btd_gatt_database *database)
+{
+	if (!database)
+		return NULL;
+
+	return database->adapter;
+}
+
 struct gatt_db *btd_gatt_database_get_db(struct btd_gatt_database *database)
 {
 	if (!database)
diff --git a/src/gatt-database.h b/src/gatt-database.h
index 30ae68e7e9a0..998e3c452b16 100644
--- a/src/gatt-database.h
+++ b/src/gatt-database.h
@@ -13,7 +13,11 @@ struct btd_gatt_database;
 struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter);
 void btd_gatt_database_destroy(struct btd_gatt_database *database);
 
+struct btd_gatt_database *btd_gatt_database_get(struct gatt_db *db);
 struct gatt_db *btd_gatt_database_get_db(struct btd_gatt_database *database);
+struct btd_adapter *
+btd_gatt_database_get_adapter(struct btd_gatt_database *database);
+
 void btd_gatt_database_att_disconnected(struct btd_gatt_database *database,
 						struct btd_device *device);
 void btd_gatt_database_server_connected(struct btd_gatt_database *database,
-- 
2.51.0


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

* [PATCH BlueZ v1 09/13] bass: Implement Device option for Push
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (6 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 08/13] gatt-database: Add btd_gatt_database_get and btd_gatt_database_get_adapter Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 10/13] client/assistant: Handle assistant.push to own broadcasts Luiz Augusto von Dentz
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This implements support for MediaAssistant.Push with local broadcast
sources.
---
 profiles/audio/bap.c  |  25 +-
 profiles/audio/bass.c | 854 +++++++++++++++++++++++++++++-------------
 src/shared/bass.c     |   7 +-
 src/shared/bass.h     |   4 +-
 4 files changed, 599 insertions(+), 291 deletions(-)

diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index 2994881ccc1d..4b85da2a43d5 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -139,7 +139,6 @@ struct bap_data {
 	GIOChannel *listen_io;
 	unsigned int io_id;
 	unsigned int cig_update_id;
-	void *user_data;
 };
 
 static struct queue *sessions;
@@ -152,16 +151,6 @@ static void setup_create_io(struct bap_data *data, struct bap_setup *setup,
 				struct bt_bap_stream *stream, int defer);
 static void bap_update_cigs(struct bap_data *data);
 
-static bool bap_data_set_user_data(struct bap_data *data, void *user_data)
-{
-	if (!data)
-		return false;
-
-	data->user_data = user_data;
-
-	return true;
-}
-
 static void bap_debug(const char *str, void *user_data)
 {
 	DBG_IDX(0xffff, "%s", str);
@@ -1527,12 +1516,12 @@ static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
 								user_data);
 }
 
-static bool match_data_bap_data(const void *data, const void *match_data)
+static bool match_adapter(const void *data, const void *match_data)
 {
 	const struct bap_data *bdata = data;
 	const struct btd_adapter *adapter = match_data;
 
-	return bdata->user_data == adapter;
+	return bdata->adapter == adapter;
 }
 
 static const GDBusMethodTable ep_methods[] = {
@@ -2630,7 +2619,7 @@ static void setup_connect_io_broadcast(struct bap_data *data,
 					struct bt_bap_stream *stream,
 					struct bt_iso_qos *qos, int defer)
 {
-	struct btd_adapter *adapter = data->user_data;
+	struct btd_adapter *adapter = data->adapter;
 	GIOChannel *io = NULL;
 	GError *err = NULL;
 	bdaddr_t dst_addr = {0};
@@ -3828,23 +3817,19 @@ static int bap_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter)
 		return -EINVAL;
 	}
 
+	data->adapter = adapter;
 	data->state_id = bt_bap_state_register(data->bap, bap_state_bcast_src,
 					bap_connecting_bcast, data, NULL);
 	data->pac_id = bt_bap_pac_register(data->bap, pac_added_broadcast,
 					pac_removed_broadcast, data, NULL);
 
-	bap_data_set_user_data(data, adapter);
-
-	data->adapter = adapter;
-
 	return 0;
 }
 
 static void bap_adapter_remove(struct btd_profile *p,
 					struct btd_adapter *adapter)
 {
-	struct bap_data *data = queue_find(sessions, match_data_bap_data,
-						adapter);
+	struct bap_data *data = queue_find(sessions, match_adapter, adapter);
 	char addr[18];
 
 	ba2str(btd_adapter_get_address(adapter), addr);
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index 73bdf52128f9..e059401864f6 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -43,6 +43,7 @@
 #include "src/shared/bass.h"
 #include "src/shared/bap.h"
 #include "src/shared/ad.h"
+#include "src/shared/io.h"
 
 #include "btio/btio.h"
 #include "src/plugin.h"
@@ -69,6 +70,9 @@ enum assistant_state {
 	ASSISTANT_STATE_ACTIVE,		/* Remote device started receiving
 					 * stream
 					 */
+	ASSISTANT_STATE_LOCAL,		/* Assistant object was created for
+					 * local stream
+					 */
 };
 
 static const char *const str_state[] = {
@@ -76,18 +80,24 @@ static const char *const str_state[] = {
 	"ASSISTANT_STATE_PENDING",
 	"ASSISTANT_STATE_REQUESTING",
 	"ASSISTANT_STATE_ACTIVE",
+	"ASSISTANT_STATE_LOCAL",
 };
 
 struct bass_data {
+	struct btd_adapter *adapter;
 	struct btd_device *device;
 	struct btd_service *service;
+	struct bt_bap *bap;
 	struct bt_bass *bass;
+	struct bt_bap_stream *stream;
 	unsigned int src_id;
 	unsigned int cp_id;
 	unsigned int bis_id;
+	unsigned int state_id;
 };
 
 struct bass_assistant {
+	struct btd_adapter *adapter;	/* Broadcast source device */
 	struct btd_device *device;	/* Broadcast source device */
 	struct bass_data *data;		/* BASS session with peer device */
 	uint8_t sgrp;
@@ -140,7 +150,8 @@ static struct queue *delegators;
 
 static const char *state2str(enum assistant_state state);
 
-static struct bass_data *bass_data_new(struct btd_device *device);
+static struct bass_data *bass_data_new(struct btd_adapter *adapter,
+					struct btd_device *device);
 static void bass_data_add(struct bass_data *data);
 static void bass_data_remove(struct bass_data *data);
 
@@ -626,169 +637,74 @@ static void confirm_cb(GIOChannel *io, void *user_data)
 	dg->io_id = g_io_add_watch(io, G_IO_OUT, big_info_cb, dg);
 }
 
-static void bap_attached(struct bt_bap *bap, void *user_data)
+static void src_ad_search_bid(void *data, void *user_data)
 {
-	struct btd_service *service;
-	struct btd_profile *p;
-	struct btd_device *device;
-	struct btd_adapter *adapter;
-	struct bass_delegator *dg;
-	struct bass_data *data;
-	GError *err = NULL;
+	struct bt_ad_service_data *sd = data;
+	struct bass_assistant *assistant = user_data;
+	struct iovec iov;
 
-	DBG("%p", bap);
-
-	service = bt_bap_get_user_data(bap);
-	if (!service)
+	if (sd->uuid.type != BT_UUID16 || sd->uuid.value.u16 != BCAA_SERVICE)
 		return;
 
-	p = btd_service_get_profile(service);
-	if (!p)
-		return;
+	iov.iov_base = sd->data;
+	iov.iov_len = sd->len;
 
-	/* Only handle sessions with Broadcast Sources */
-	if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR))
-		return;
-
-	device = btd_service_get_device(service);
-	adapter = device_get_adapter(device);
-
-	/* Create BASS session with the Broadcast Source */
-	data = bass_data_new(device);
-	data->bis_id = bt_bap_bis_cb_register(bap, bis_probe,
-					bis_remove, device, NULL);
-
-	bass_data_add(data);
-
-	dg = queue_find(delegators, delegator_match_device, device);
-	if (!dg)
-		/* Only probe devices added via Broadcast Assistants */
-		return;
-
-	if (dg->service)
-		/* Service has already been probed */
-		return;
-
-	dg->service = service;
-	dg->bap = bap;
-
-	dg->io = bt_io_listen(NULL, confirm_cb, dg,
-		NULL, &err,
-		BT_IO_OPT_SOURCE_BDADDR,
-		btd_adapter_get_address(adapter),
-		BT_IO_OPT_SOURCE_TYPE,
-		btd_adapter_get_address_type(adapter),
-		BT_IO_OPT_DEST_BDADDR,
-		device_get_address(device),
-		BT_IO_OPT_DEST_TYPE,
-		btd_device_get_bdaddr_type(device),
-		BT_IO_OPT_MODE, BT_IO_MODE_ISO,
-		BT_IO_OPT_QOS, &bap_sink_pa_qos,
-		BT_IO_OPT_ISO_BC_SID, dg->sid,
-		BT_IO_OPT_INVALID);
-	if (!dg->io) {
-		error("%s", err->message);
-		g_error_free(err);
-		return;
-	}
-
-	/* Take ownership for the service by setting the user data. */
-	btd_service_set_user_data(service, dg);
+	util_iov_pull_le24(&iov, &assistant->bid);
 }
 
-static void setup_free(void *data)
+static struct bass_assistant *
+assistant_new(struct btd_adapter *adapter,
+		struct btd_device *device, struct bass_data *data,
+		uint8_t sgrp, uint8_t sid, uint8_t bis, struct bt_bap_qos *qos,
+		struct iovec *meta, struct iovec *caps)
 {
-	struct bass_setup *setup = data;
+	struct bass_assistant *assistant;
+	char src_addr[18];
 
-	DBG("setup %p", setup);
+	assistant = new0(struct bass_assistant, 1);
+	if (!assistant)
+		return NULL;
 
-	util_iov_free(setup->qos.bcast.bcode, 1);
-	util_iov_free(setup->meta, 1);
-	util_iov_free(setup->config, 1);
-	free(setup->path);
+	DBG("assistant %p", assistant);
 
-	/* Clear bis index from the bis sync bitmask, if it
-	 * has been previously set.
-	 */
-	bt_bass_clear_bis_sync(setup->dg->src, setup->bis);
-}
+	assistant->adapter = adapter;
+	assistant->device = device;
+	assistant->data = data;
+	assistant->sgrp = sgrp;
+	assistant->sid = sid;
+	assistant->bis = bis;
+	assistant->qos = *qos;
 
-static bool match_device(const void *data, const void *match_data)
-{
-	const struct bass_data *bdata = data;
-	const struct btd_device *device = match_data;
+	/* Create an internal copy for bcode */
+	assistant->qos.bcast.bcode = util_iov_dup(qos->bcast.bcode, 1);
 
-	return bdata->device == device;
-}
+	assistant->meta = util_iov_dup(meta, 1);
+	assistant->caps = util_iov_dup(caps, 1);
 
-static void bap_detached(struct bt_bap *bap, void *user_data)
-{
-	struct btd_service *service;
-	struct btd_profile *p;
-	struct btd_device *device;
-	struct bass_delegator *dg;
-	struct bass_data *data;
+	if (device) {
+		btd_device_foreach_service_data(device, src_ad_search_bid,
+							assistant);
 
-	DBG("%p", bap);
+		ba2str(device_get_address(device), src_addr);
 
-	service = bt_bap_get_user_data(bap);
-	if (!service)
-		return;
-
-	p = btd_service_get_profile(service);
-	if (!p)
-		return;
-
-	/* Only handle sessions with Broadcast Sources */
-	if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR))
-		return;
-
-	device = btd_service_get_device(service);
-
-	/* Remove BASS session with the Broadcast Source device */
-	data = queue_find(sessions, match_device, device);
-	if (data) {
-		bt_bap_bis_cb_unregister(bap, data->bis_id);
-		bass_data_remove(data);
+		assistant->path = g_strdup_printf("%s/src_%s/sid%d/bis%d",
+						device_get_path(data->device),
+						src_addr, sid, bis);
+	} else {
+		assistant->path = g_strdup_printf("%s/sid%d/bis%d",
+						adapter_get_path(data->adapter),
+						sid, bis);
+		assistant->state = ASSISTANT_STATE_LOCAL;
 	}
 
-	dg = queue_remove_if(delegators, delegator_match_device, device);
-	if (!dg)
-		return;
+	g_strdelimit(assistant->path, ":", '_');
 
-	DBG("%p", dg);
+	if (!assistants)
+		assistants = queue_new();
 
-	if (dg->io_id)
-		g_source_remove(dg->io_id);
+	queue_push_tail(assistants, assistant);
 
-	if (dg->io) {
-		g_io_channel_shutdown(dg->io, TRUE, NULL);
-		g_io_channel_unref(dg->io);
-	}
-
-	queue_destroy(dg->setups, setup_free);
-
-	/* Update Broadcast Receive State characteristic value and notify
-	 * peers.
-	 */
-	if (bt_bass_set_pa_sync(dg->src, BT_BASS_NOT_SYNCHRONIZED_TO_PA))
-		DBG("Failed to update Broadcast Receive State characteristic");
-
-	/* Unregister BAP stream state changed callback. */
-	bt_bap_state_unregister(dg->bap, dg->state_id);
-
-	bt_bap_bcode_cb_unregister(dg->bap, dg->bcode_id);
-
-	if (dg->timeout)
-		g_source_remove(dg->timeout);
-
-	queue_destroy(dg->bcode_reqs, free);
-
-	free(dg->bcode);
-
-	free(dg);
-
-	btd_service_set_user_data(service, NULL);
+	return assistant;
 }
 
 static void assistant_set_state(struct bass_assistant *assistant,
@@ -797,7 +713,7 @@ static void assistant_set_state(struct bass_assistant *assistant,
 	enum assistant_state old_state = assistant->state;
 	const char *str;
 
-	if (old_state == state)
+	if (old_state == state || old_state == ASSISTANT_STATE_LOCAL)
 		return;
 
 	assistant->state = state;
@@ -864,11 +780,21 @@ static int assistant_parse_qos(struct bass_assistant *assistant,
 	return 0;
 }
 
+static bool match_device(const void *data, const void *match_data)
+{
+	const struct bass_data *bdata = data;
+	const struct btd_device *device = match_data;
+
+	return bdata->device == device;
+}
+
 static int assistant_parse_props(struct bass_assistant *assistant,
 					DBusMessageIter *props)
 {
 	DBusMessageIter value, entry, array;
-	const char *key;
+	const char *key, *path;
+	struct btd_device *device;
+	struct bass_data *data;
 
 	while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) {
 		dbus_message_iter_recurse(props, &entry);
@@ -901,6 +827,44 @@ static int assistant_parse_props(struct bass_assistant *assistant,
 				goto fail;
 
 			DBG("Parsed QoS");
+		} else if (!strcasecmp(key, "Device")) {
+			if (assistant->state != ASSISTANT_STATE_LOCAL) {
+				error("Device property is for local assistant "
+				      "only");
+				goto fail;
+			}
+
+			if (dbus_message_iter_get_arg_type(&value) !=
+							DBUS_TYPE_OBJECT_PATH)
+				goto fail;
+
+			dbus_message_iter_get_basic(&value, &path);
+
+			device = btd_adapter_find_device_by_path(
+							assistant->adapter,
+							path);
+			if (!device) {
+				error("Unable to find device %s", path);
+				goto fail;
+			}
+
+			data = queue_find(sessions, match_device, device);
+			if (!data) {
+				error("Unable to find data for device %s",
+					path);
+				goto fail;
+			}
+
+			if (!data->bass) {
+				error("Unable to find bass for device %s",
+					path);
+				goto fail;
+			}
+
+			if (assistant->data->bass)
+				bt_bass_unref(assistant->data->bass);
+
+			assistant->data->bass = bt_bass_ref(data->bass);
 		}
 
 		dbus_message_iter_next(props);
@@ -914,6 +878,67 @@ fail:
 	return -EINVAL;
 }
 
+static bool match_bass(const void *data, const void *match_data)
+{
+	const struct bass_data *bdata = data;
+	const struct bt_bass *bass = match_data;
+
+	/* Ignore data from own broadcast source */
+	if (!bdata->device)
+		return false;
+
+	return bdata->bass == bass;
+}
+
+static void assistant_past(struct bass_assistant *assistant)
+{
+	struct io *io = bt_bap_stream_get_io(assistant->data->stream);
+	struct btd_device *device = assistant->device;
+	int sk;
+	struct sockaddr_iso *addr;
+	int err;
+
+	DBG("");
+
+	if (!io) {
+		error("stream io not set");
+		return;
+	}
+
+	sk = io_get_fd(io);
+	if (sk < 0)
+		return;
+
+	if (!device) {
+		struct bt_bass *bass = assistant->data->bass;
+		struct bass_data *data;
+
+		data = queue_find(sessions, match_bass, bass);
+		if (!data) {
+			error("Unable to find data for bass %p", bass);
+			return;
+		}
+
+		device = data->device;
+		if (!device) {
+			error("Unable to find device for bass %p", bass);
+			return;
+		}
+	}
+
+	addr = malloc(sizeof(*addr) + sizeof(*addr->iso_bc));
+	memset(addr, 0, sizeof(*addr) + sizeof(*addr->iso_bc));
+	addr->iso_family = AF_BLUETOOTH;
+
+	bacpy(&addr->iso_bc->bc_bdaddr, (void *) device_get_address(device));
+	addr->iso_bc->bc_bdaddr_type = device_get_le_address_type(device);
+
+	err = bind(sk, (struct sockaddr *) addr, sizeof(*addr) +
+						sizeof(*addr->iso_bc));
+	if (err)
+		error("bind: %s", strerror(errno));
+}
+
 static DBusMessage *push(DBusConnection *conn, DBusMessage *msg,
 							  void *user_data)
 {
@@ -925,6 +950,7 @@ static DBusMessage *push(DBusConnection *conn, DBusMessage *msg,
 	uint8_t meta_len = 0;
 	int err;
 	DBusMessageIter props, dict;
+	struct io *io;
 
 	DBG("");
 
@@ -944,17 +970,63 @@ static DBusMessage *push(DBusConnection *conn, DBusMessage *msg,
 
 	hdr.op = BT_BASS_ADD_SRC;
 
-	if (device_get_le_address_type(assistant->device) == BDADDR_LE_PUBLIC)
-		params.addr_type = BT_BASS_ADDR_PUBLIC;
-	else
-		params.addr_type = BT_BASS_ADDR_RANDOM;
+	if (assistant->device) {
+		if (device_get_le_address_type(assistant->device) ==
+						BDADDR_LE_PUBLIC)
+			params.addr_type = BT_BASS_ADDR_PUBLIC;
+		else
+			params.addr_type = BT_BASS_ADDR_RANDOM;
 
-	bacpy(&params.addr, device_get_address(assistant->device));
-	params.sid = assistant->sid;
-	put_le24(assistant->bid, params.bid);
-	params.pa_sync = PA_SYNC_NO_PAST;
-	params.pa_interval = PA_INTERVAL_UNKNOWN;
-	params.num_subgroups = assistant->sgrp + 1;
+		bacpy(&params.addr, device_get_address(assistant->device));
+		params.sid = assistant->sid;
+		put_le24(assistant->bid, params.bid);
+		params.pa_sync = PA_SYNC_NO_PAST;
+		params.pa_interval = PA_INTERVAL_UNKNOWN;
+		params.num_subgroups = assistant->sgrp + 1;
+	} else {
+		io = bt_bap_stream_get_io(assistant->data->stream);
+		if (io) {
+			int fd = io_get_fd(io);
+			struct sockaddr_iso addr;
+			socklen_t olen = sizeof(addr);
+
+			if (getsockname(fd, (struct sockaddr *) &addr,
+					&olen) < 0) {
+				error("getsockname: %s", strerror(errno));
+				return btd_error_invalid_args(msg);
+			}
+
+			if (addr.iso_bdaddr_type == BDADDR_LE_PUBLIC)
+				params.addr_type = BT_BASS_ADDR_PUBLIC;
+			else
+				params.addr_type = BT_BASS_ADDR_RANDOM;
+
+			bacpy(&params.addr, &addr.iso_bdaddr);
+		} else {
+			if (btd_adapter_get_address_type(assistant->adapter) ==
+							BDADDR_LE_PUBLIC)
+				params.addr_type = BT_BASS_ADDR_PUBLIC;
+			else
+				params.addr_type = BT_BASS_ADDR_RANDOM;
+
+			bacpy(&params.addr,
+				btd_adapter_get_address(assistant->adapter));
+		}
+
+		params.sid = assistant->sid;
+		/* TODO: Add a way to recover BID */
+		put_le24(assistant->bid, params.bid);
+
+		if (assistant->data->stream &&
+				btd_adapter_has_settings(assistant->adapter,
+						MGMT_SETTING_PAST_SENDER))
+			params.pa_sync = PA_SYNC_PAST;
+		else
+			params.pa_sync = PA_SYNC_NO_SYNC;
+
+		params.pa_interval = PA_INTERVAL_UNKNOWN;
+		params.num_subgroups = assistant->sgrp + 1;
+	}
 
 	util_iov_append(&iov, &params, sizeof(params));
 
@@ -1009,6 +1081,8 @@ static const char *state2str(enum assistant_state state)
 		return "requesting";
 	case ASSISTANT_STATE_ACTIVE:
 		return "active";
+	case ASSISTANT_STATE_LOCAL:
+		return "local";
 	}
 
 	return NULL;
@@ -1093,65 +1167,290 @@ static void assistant_free(void *data)
 	free(assistant);
 }
 
-static void src_ad_search_bid(void *data, void *user_data)
+static void bis_src_handler(uint8_t sid, uint8_t bis, uint8_t sgrp,
+				struct iovec *caps, struct iovec *meta,
+				struct bt_bap_qos *qos, void *user_data)
 {
-	struct bt_ad_service_data *sd = data;
-	struct bass_assistant *assistant = user_data;
-	struct iovec iov;
+	struct bass_data *data = user_data;
+	struct bass_assistant *assistant;
+	char addr[18];
 
-	if (sd->uuid.type != BT_UUID16 || sd->uuid.value.u16 != BCAA_SERVICE)
-		return;
+	ba2str(btd_adapter_get_address(data->adapter), addr);
 
-	iov.iov_base = sd->data;
-	iov.iov_len = sd->len;
+	DBG("%s data %p BIS %d", addr, data, bis);
 
-	util_iov_pull_le24(&iov, &assistant->bid);
+	assistant = assistant_new(data->adapter, NULL, data, sgrp, sid, bis,
+					qos, meta, caps);
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+					assistant->path,
+					MEDIA_ASSISTANT_INTERFACE,
+					assistant_methods, NULL,
+					assistant_properties,
+					assistant,
+					assistant_free))
+		DBG("Could not register path %s", assistant->path);
 }
 
-static struct bass_assistant *assistant_new(struct btd_adapter *adapter,
-		struct btd_device *device, struct bass_data *data,
-		uint8_t sgrp, uint8_t sid, uint8_t bis, struct bt_bap_qos *qos,
-		struct iovec *meta, struct iovec *caps)
+static bool assistant_match_data(const void *data, const void *match_data)
 {
-	struct bass_assistant *assistant;
-	char src_addr[18];
+	const struct bass_assistant *assistant = data;
+	const struct bass_data *bdata = match_data;
 
-	assistant = new0(struct bass_assistant, 1);
-	if (!assistant)
-		return NULL;
+	return (assistant->data == bdata);
+}
 
-	DBG("assistant %p", assistant);
+static void unregister_assistant(void *data)
+{
+	struct bass_assistant *assistant = data;
 
-	assistant->device = device;
-	assistant->data = data;
-	assistant->sgrp = sgrp;
-	assistant->sid = sid;
-	assistant->bis = bis;
-	assistant->qos = *qos;
+	DBG("%p", assistant);
 
-	/* Create an internal copy for bcode */
-	assistant->qos.bcast.bcode = util_iov_dup(qos->bcast.bcode, 1);
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+				assistant->path, MEDIA_ASSISTANT_INTERFACE);
+}
 
-	assistant->meta = util_iov_dup(meta, 1);
-	assistant->caps = util_iov_dup(caps, 1);
+static void bap_state_src_changed(struct bt_bap_stream *stream,
+				uint8_t old_state, uint8_t new_state,
+				void *user_data)
+{
+	struct bass_data *data = user_data;
+	struct assistant *assistant;
+	struct bt_bap_qos *qos = NULL;
+	struct iovec *base;
 
-	btd_device_foreach_service_data(assistant->device, src_ad_search_bid,
-							assistant);
+	DBG("stream %p: %s(%u) -> %s(%u)", stream,
+			bt_bap_stream_statestr(old_state), old_state,
+			bt_bap_stream_statestr(new_state), new_state);
 
-	ba2str(device_get_address(device), src_addr);
+	switch (new_state) {
+	case BT_BAP_STREAM_STATE_IDLE:
+		/* Unregister assistant object if one exists */
+		assistant = queue_remove_if(assistants, assistant_match_data,
+						data);
+		if (assistant)
+			unregister_assistant(assistant);
+		data->stream = NULL;
+		break;
+	case BT_BAP_STREAM_STATE_STREAMING:
+		base = bt_bap_stream_get_base(stream);
+		if (!base) {
+			error("Unable to read BASE of stream %p", stream);
+			break;
+		}
 
-	assistant->path = g_strdup_printf("%s/src_%s/sid%d/bis%d",
-					device_get_path(data->device), src_addr,
-					sid, bis);
+		if (!bt_bap_stream_io_get_qos(stream, NULL, &qos)) {
+			error("Unable to read QoS of stream %p", stream);
+			break;
+		}
 
-	g_strdelimit(assistant->path, ":", '_');
+		bt_bap_parse_base(0x00, base, qos, bass_debug, bis_src_handler,
+					data);
+		data->stream = stream;
+		break;
+	}
+}
 
-	if (!assistants)
-		assistants = queue_new();
+static void bap_bc_attached(struct bt_bap *bap, void *user_data)
+{
+	struct btd_gatt_database *db;
+	struct btd_adapter *adapter;
+	struct bass_data *data;
 
-	queue_push_tail(assistants, assistant);
+	DBG("%p", bap);
 
-	return assistant;
+	db = btd_gatt_database_get(bt_bap_get_db(bap, false));
+	if (!db)
+		return;
+
+	adapter = btd_gatt_database_get_adapter(db);
+	if (!adapter)
+		return;
+
+	/* Create BASS session with the local Broadcast Source */
+	data = bass_data_new(adapter, NULL);
+	data->bap = bap;
+	data->state_id = bt_bap_state_register(bap, bap_state_src_changed,
+						NULL, data, NULL);
+
+	bass_data_add(data);
+}
+
+static void bap_attached(struct bt_bap *bap, void *user_data)
+{
+	struct btd_service *service;
+	struct btd_profile *p;
+	struct btd_device *device;
+	struct btd_adapter *adapter;
+	struct bass_delegator *dg;
+	struct bass_data *data;
+	GError *err = NULL;
+
+	service = bt_bap_get_user_data(bap);
+	if (!service)
+		return bap_bc_attached(bap, user_data);
+
+	DBG("%p", bap);
+
+	p = btd_service_get_profile(service);
+	if (!p)
+		return;
+
+	/* Only handle sessions with Broadcast Sources */
+	if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR))
+		return;
+
+	device = btd_service_get_device(service);
+	adapter = device_get_adapter(device);
+
+	/* Create BASS session with the Broadcast Source */
+	data = bass_data_new(adapter, device);
+	data->bis_id = bt_bap_bis_cb_register(bap, bis_probe,
+					bis_remove, device, NULL);
+
+	bass_data_add(data);
+
+	dg = queue_find(delegators, delegator_match_device, device);
+	if (!dg)
+		/* Only probe devices added via Broadcast Assistants */
+		return;
+
+	if (dg->service)
+		/* Service has already been probed */
+		return;
+
+	dg->service = service;
+	dg->bap = bap;
+
+	dg->io = bt_io_listen(NULL, confirm_cb, dg,
+		NULL, &err,
+		BT_IO_OPT_SOURCE_BDADDR,
+		btd_adapter_get_address(adapter),
+		BT_IO_OPT_SOURCE_TYPE,
+		btd_adapter_get_address_type(adapter),
+		BT_IO_OPT_DEST_BDADDR,
+		device_get_address(device),
+		BT_IO_OPT_DEST_TYPE,
+		btd_device_get_bdaddr_type(device),
+		BT_IO_OPT_MODE, BT_IO_MODE_ISO,
+		BT_IO_OPT_QOS, &bap_sink_pa_qos,
+		BT_IO_OPT_ISO_BC_SID, dg->sid,
+		BT_IO_OPT_INVALID);
+	if (!dg->io) {
+		error("%s", err->message);
+		g_error_free(err);
+		return;
+	}
+
+	/* Take ownership for the service by setting the user data. */
+	btd_service_set_user_data(service, dg);
+}
+
+static void setup_free(void *data)
+{
+	struct bass_setup *setup = data;
+
+	DBG("setup %p", setup);
+
+	util_iov_free(setup->qos.bcast.bcode, 1);
+	util_iov_free(setup->meta, 1);
+	util_iov_free(setup->config, 1);
+	free(setup->path);
+
+	/* Clear bis index from the bis sync bitmask, if it
+	 * has been previously set.
+	 */
+	bt_bass_clear_bis_sync(setup->dg->src, setup->bis);
+}
+
+static bool match_bap(const void *data, const void *match_data)
+{
+	const struct bass_data *d = data;
+	const struct bt_bap *bap = match_data;
+
+	return (d->bap == bap);
+}
+
+static void bap_bc_detached(struct bt_bap *bap, struct bass_data *data)
+{
+	DBG("%p", bap);
+
+	bt_bap_state_unregister(bap, data->state_id);
+	bass_data_remove(data);
+}
+
+static void bap_detached(struct bt_bap *bap, void *user_data)
+{
+	struct btd_service *service;
+	struct btd_profile *p;
+	struct btd_device *device;
+	struct bass_delegator *dg;
+	struct bass_data *data;
+
+	data = queue_find(sessions, match_bap, bap);
+	if (data)
+		return bap_bc_detached(bap, data);
+
+	DBG("%p", bap);
+
+	service = bt_bap_get_user_data(bap);
+	if (!service)
+		return;
+
+	p = btd_service_get_profile(service);
+	if (!p)
+		return;
+
+	/* Only handle sessions with Broadcast Sources */
+	if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR))
+		return;
+
+	device = btd_service_get_device(service);
+
+	/* Remove BASS session with the Broadcast Source device */
+	data = queue_find(sessions, match_device, device);
+	if (data) {
+		bt_bap_bis_cb_unregister(bap, data->bis_id);
+		bt_bap_state_unregister(bap, data->state_id);
+		bass_data_remove(data);
+	}
+
+	dg = queue_remove_if(delegators, delegator_match_device, device);
+	if (!dg)
+		return;
+
+	DBG("%p", dg);
+
+	if (dg->io_id)
+		g_source_remove(dg->io_id);
+
+	if (dg->io) {
+		g_io_channel_shutdown(dg->io, TRUE, NULL);
+		g_io_channel_unref(dg->io);
+	}
+
+	queue_destroy(dg->setups, setup_free);
+
+	/* Update Broadcast Receive State characteristic value and notify
+	 * peers.
+	 */
+	if (bt_bass_set_pa_sync(dg->src, BT_BASS_NOT_SYNCHRONIZED_TO_PA))
+		DBG("Failed to update Broadcast Receive State characteristic");
+
+	/* Unregister BAP stream state changed callback. */
+	bt_bap_state_unregister(dg->bap, dg->state_id);
+
+	bt_bap_bcode_cb_unregister(dg->bap, dg->bcode_id);
+
+	if (dg->timeout)
+		g_source_remove(dg->timeout);
+
+	queue_destroy(dg->bcode_reqs, free);
+
+	free(dg->bcode);
+
+	free(dg);
+
+	btd_service_set_user_data(service, NULL);
 }
 
 static void bis_probe(uint8_t sid, uint8_t bis, uint8_t sgrp,
@@ -1210,16 +1509,6 @@ static bool assistant_match_device(const void *data, const void *match_data)
 	return (assistant->device == device);
 }
 
-static void unregister_assistant(void *data)
-{
-	struct bass_assistant *assistant = data;
-
-	DBG("%p", assistant);
-
-	g_dbus_unregister_interface(btd_get_dbus_connection(),
-				assistant->path, MEDIA_ASSISTANT_INTERFACE);
-}
-
 static void bis_remove(struct bt_bap *bap, void *user_data)
 {
 	struct btd_device *device = user_data;
@@ -1228,11 +1517,13 @@ static void bis_remove(struct bt_bap *bap, void *user_data)
 		device, unregister_assistant);
 }
 
-static struct bass_data *bass_data_new(struct btd_device *device)
+static struct bass_data *bass_data_new(struct btd_adapter *adapter,
+					struct btd_device *device)
 {
 	struct bass_data *data;
 
 	data = new0(struct bass_data, 1);
+	data->adapter = adapter;
 	data->device = device;
 
 	return data;
@@ -1240,6 +1531,8 @@ static struct bass_data *bass_data_new(struct btd_device *device)
 
 static void bass_data_add(struct bass_data *data)
 {
+	bool initiator = false;
+
 	DBG("data %p", data);
 
 	if (queue_find(sessions, NULL, data)) {
@@ -1254,33 +1547,14 @@ static void bass_data_add(struct bass_data *data)
 
 	queue_push_tail(sessions, data);
 
-	if (data->service) {
-		struct btd_adapter *adapter = device_get_adapter(data->device);
-		bool initiator = btd_service_is_initiator(data->service);
-
+	if (data->service)
 		btd_service_set_user_data(data->service, data);
-		if ((!initiator && btd_adapter_has_settings(adapter,
+
+	if ((!initiator && btd_adapter_has_settings(data->adapter,
 				MGMT_SETTING_PAST_RECEIVER)) || (initiator &&
-				btd_adapter_has_settings(adapter,
+				btd_adapter_has_settings(data->adapter,
 				MGMT_SETTING_PAST_SENDER)))
-			device_set_past_support(data->device, true);
-	}
-}
-
-static bool match_data(const void *data, const void *match_data)
-{
-	const struct bass_data *bdata = data;
-	const struct bt_bass *bass = match_data;
-
-	return bdata->bass == bass;
-}
-
-static bool assistant_match_data(const void *data, const void *match_data)
-{
-	const struct bass_assistant *assistant = data;
-	const struct bass_data *bdata = match_data;
-
-	return (assistant->data == bdata);
+		device_set_past_support(data->device, true);
 }
 
 static void bass_data_free(struct bass_data *data)
@@ -1322,7 +1596,7 @@ static void bass_detached(struct bt_bass *bass, void *user_data)
 
 	DBG("%p", bass);
 
-	data = queue_find(sessions, match_data, bass);
+	data = queue_find(sessions, match_bass, bass);
 	if (!data) {
 		error("Unable to find bass session");
 		return;
@@ -1337,42 +1611,19 @@ static void bass_detached(struct bt_bass *bass, void *user_data)
 	bass_data_remove(data);
 }
 
-static int handle_add_src_req(struct bt_bcast_src *bcast_src,
-			struct bt_bass_add_src_params *params,
-			struct bass_data *data)
+static struct bass_delegator *
+bass_delegator_new(struct btd_device *device, struct bt_bcast_src *src,
+			uint8_t sid)
 {
-	struct btd_adapter *adapter = device_get_adapter(data->device);
-	struct btd_device *device;
 	struct bass_delegator *dg;
 
-	/* Create device for Broadcast Source using the parameters
-	 * provided by Broadcast Assistant.
-	 */
-	device = btd_adapter_get_device(adapter, &params->addr,
-						params->addr_type);
-	if (!device) {
-		DBG("Unable to get device");
-		return -EINVAL;
-	}
-
-	DBG("device %p", device);
-
-	/* Probe Broadcast Source, if it has not already been
-	 * autonomously probed inside BAP.
-	 */
-	if (!btd_device_get_service(device, BCAAS_UUID_STR))
-		goto probe;
-
-	return 0;
-
-probe:
 	dg = new0(struct bass_delegator, 1);
 	if (!dg)
-		return -ENOMEM;
+		return NULL;
 
 	dg->device = device;
-	dg->src = bcast_src;
-	dg->sid = params->sid;
+	dg->src = src;
+	dg->sid = sid;
 	dg->bcode_reqs = queue_new();
 	dg->setups = queue_new();
 
@@ -1388,6 +1639,59 @@ probe:
 	 */
 	btd_device_add_uuid(device, BCAAS_UUID_STR);
 
+	return dg;
+}
+
+static int handle_add_src_req(struct bt_bcast_src *bcast_src,
+			struct bt_bass_add_src_params *params,
+			struct bass_data *data)
+{
+	struct btd_adapter *adapter = device_get_adapter(data->device);
+	struct btd_device *device;
+	struct bass_delegator *dg;
+
+	/* Detect if PAST can be used then it can be used as destination since
+	 * PAST Receiver uses the ACL connection itself.
+	 */
+	if (params->pa_sync == PA_SYNC_PAST) {
+		/* Check if MGMT_SETTING_PAST_RECEIVER is supported then set
+		 * DEVICE_FLAG_PAST since the device is requesting PAST to be
+		 * used.
+		 */
+		if (btd_adapter_has_settings(data->adapter,
+						MGMT_SETTING_PAST_RECEIVER)) {
+			device_set_past_support(data->device, true);
+			bt_bass_set_pa_sync(bcast_src, BT_BASS_SYNC_INFO_RE);
+			device = data->device;
+			goto done;
+		}
+
+		bt_bass_set_pa_sync(bcast_src, BT_BASS_NO_PAST);
+	}
+
+	/* Create device for Broadcast Source using the parameters
+	 * provided by Broadcast Assistant.
+	 */
+	device = btd_adapter_get_device(adapter, &params->addr,
+						params->addr_type);
+
+	if (!device) {
+		DBG("Unable to get device");
+		return -EINVAL;
+	}
+
+done:
+	DBG("device %p", device);
+
+	/* Probe Broadcast Source, if it has not already been
+	 * autonomously probed inside BAP.
+	 */
+	if (!btd_device_get_service(device, BCAAS_UUID_STR)) {
+		dg = bass_delegator_new(device, bcast_src, params->sid);
+		if (!dg)
+			return -ENOMEM;
+	}
+
 	return 0;
 }
 
@@ -1556,7 +1860,7 @@ static void bass_attached(struct bt_bass *bass, void *user_data)
 
 	DBG("%p", bass);
 
-	data = queue_find(sessions, match_data, bass);
+	data = queue_find(sessions, match_bass, bass);
 	if (data)
 		return;
 
@@ -1570,7 +1874,7 @@ static void bass_attached(struct bt_bass *bass, void *user_data)
 		return;
 	}
 
-	data = bass_data_new(device);
+	data = bass_data_new(device_get_adapter(device), device);
 	data->bass = bass;
 
 	data->cp_id = bt_bass_cp_handler_register(data->bass,
@@ -1612,8 +1916,8 @@ static void bass_handle_bcode_req(struct bass_assistant *assistant, int id)
 	free(iov.iov_base);
 }
 
-static void bass_src_changed(uint8_t id, uint32_t bid, uint8_t enc,
-					uint32_t bis_sync, void *user_data)
+static void bass_src_changed(uint8_t id, uint32_t bid, uint8_t state,
+				uint8_t enc, uint32_t bis_sync, void *user_data)
 {
 	const struct queue_entry *entry;
 
@@ -1622,15 +1926,27 @@ static void bass_src_changed(uint8_t id, uint32_t bid, uint8_t enc,
 		struct bass_assistant *assistant = entry->data;
 		uint32_t bis = 1 << (assistant->bis - 1);
 
-		if (assistant->bid != bid)
+		if (bid && assistant->bid != bid)
 			/* Only handle assistant objects
 			 * that match the source
 			 */
 			continue;
 
+		/* If BID is not set it may happen to be local stream so ignore
+		 * non-local assistants.
+		 */
+		if (!bid && assistant->state != ASSISTANT_STATE_LOCAL)
+			continue;
+
+		if (state == BT_BASS_SYNC_INFO_RE) {
+			assistant_past(assistant);
+			return;
+		}
+
 		switch (enc) {
 		case BT_BASS_BIG_ENC_STATE_BCODE_REQ:
-			if (assistant->state != ASSISTANT_STATE_PENDING)
+			if (assistant->state != ASSISTANT_STATE_PENDING &&
+				assistant->state != ASSISTANT_STATE_LOCAL)
 				/* Only handle assistant objects that
 				 * have been pushed by the user
 				 */
@@ -1638,6 +1954,10 @@ static void bass_src_changed(uint8_t id, uint32_t bid, uint8_t enc,
 
 			/* Provide Broadcast Code to peer */
 			bass_handle_bcode_req(assistant, id);
+
+			if (assistant->state == ASSISTANT_STATE_LOCAL)
+				return;
+
 			break;
 		case BT_BASS_BIG_ENC_STATE_NO_ENC:
 			if (assistant->state != ASSISTANT_STATE_PENDING)
@@ -1686,7 +2006,7 @@ static int bass_probe(struct btd_service *service)
 		return -EINVAL;
 	}
 
-	data = bass_data_new(device);
+	data = bass_data_new(adapter, device);
 	data->service = service;
 
 	data->bass = bt_bass_new(btd_gatt_database_get_db(database),
diff --git a/src/shared/bass.c b/src/shared/bass.c
index 36bb9ea66523..19cc9531d617 100644
--- a/src/shared/bass.c
+++ b/src/shared/bass.c
@@ -1319,8 +1319,9 @@ static void notify_src_changed(void *data, void *user_data)
 	}
 
 	if (changed->cb)
-		changed->cb(bcast_src->id, bcast_src->bid, bcast_src->enc,
-					bis_sync, changed->data);
+		changed->cb(bcast_src->id, bcast_src->bid,
+			    bcast_src->sync_state, bcast_src->enc,
+			    bis_sync, changed->data);
 }
 
 static void bcast_recv_state_notify(struct bt_bass *bass, uint16_t value_handle,
@@ -1681,7 +1682,7 @@ static struct bt_bass_db *bass_get_db(struct gatt_db *db,
 	return bass_db_new(db, adapter_bdaddr);
 }
 
-static struct bt_bass *bt_bass_ref(struct bt_bass *bass)
+struct bt_bass *bt_bass_ref(struct bt_bass *bass)
 {
 	if (!bass)
 		return NULL;
diff --git a/src/shared/bass.h b/src/shared/bass.h
index f39ed7dad41d..a7b7741db3b7 100644
--- a/src/shared/bass.h
+++ b/src/shared/bass.h
@@ -97,7 +97,8 @@ typedef void (*bt_bass_func_t)(struct bt_bass *bass, void *user_data);
 typedef void (*bt_bass_destroy_func_t)(void *user_data);
 typedef void (*bt_bass_debug_func_t)(const char *str, void *user_data);
 typedef void (*bt_bass_src_func_t)(uint8_t id, uint32_t bid, uint8_t enc,
-					uint32_t bis_sync, void *user_data);
+				   uint8_t state, uint32_t bis_sync,
+				   void *user_data);
 
 typedef int (*bt_bass_cp_handler_func_t)(struct bt_bcast_src *bcast_src,
 		uint8_t op, void *params, void *user_data);
@@ -112,6 +113,7 @@ bool bt_bass_set_debug(struct bt_bass *bass, bt_bass_debug_func_t func,
 struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb,
 			const bdaddr_t *adapter_bdaddr);
 bool bt_bass_set_user_data(struct bt_bass *bass, void *user_data);
+struct bt_bass *bt_bass_ref(struct bt_bass *bass);
 void bt_bass_unref(struct bt_bass *bass);
 bool bt_bass_attach(struct bt_bass *bass, struct bt_gatt_client *client);
 bool bt_bass_set_att(struct bt_bass *bass, struct bt_att *att);
-- 
2.51.0


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

* [PATCH BlueZ v1 10/13] client/assistant: Handle assistant.push to own broadcasts
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (7 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 09/13] bass: Implement Device option for Push Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 11/13] client/assistant: Detect if object already contains a valid BCode Luiz Augusto von Dentz
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 client/assistant.c | 114 ++++++++++++++++++++++++++++++++++-----------
 client/mgmt.c      |   5 +-
 2 files changed, 92 insertions(+), 27 deletions(-)

diff --git a/client/assistant.c b/client/assistant.c
index 3551aaad8a16..1ff8001d7216 100644
--- a/client/assistant.c
+++ b/client/assistant.c
@@ -47,6 +47,8 @@
 
 struct assistant_config {
 	GDBusProxy *proxy;	/* DBus object reference */
+	char *state;		/* Assistant state */
+	char *device;		/* Device address */
 	struct iovec *meta;	/* Stream metadata LTVs */
 	struct bt_iso_qos qos;	/* Stream QoS parameters */
 };
@@ -223,6 +225,10 @@ static void push_setup(DBusMessageIter *iter, void *user_data)
 				DBUS_TYPE_BYTE, &cfg->meta->iov_base,
 				cfg->meta->iov_len);
 
+	if (cfg->device)
+		g_dbus_dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH,
+						&cfg->device);
+
 	if (cfg->qos.bcast.encryption)
 		append_qos(&dict, cfg);
 
@@ -285,11 +291,43 @@ fail:
 	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
+static bool assistant_get_qos(struct assistant_config *cfg)
+{
+	DBusMessageIter iter, dict, entry, value;
+	const char *key;
+
+	/* Get QoS property to check if the stream is encrypted */
+	if (!g_dbus_proxy_get_property(cfg->proxy, "QoS", &iter))
+		return false;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return false;
+
+	dbus_message_iter_recurse(&iter, &dict);
+
+	if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
+		return false;
+
+	dbus_message_iter_recurse(&dict, &entry);
+	dbus_message_iter_get_basic(&entry, &key);
+
+	if (strcasecmp(key, "Encryption") != 0)
+		return false;
+
+	dbus_message_iter_next(&entry);
+	dbus_message_iter_recurse(&entry, &value);
+
+	if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
+		return false;
+
+	dbus_message_iter_get_basic(&value, &cfg->qos.bcast.encryption);
+
+	return true;
+}
+
 static void assistant_set_metadata_cfg(const char *input, void *user_data)
 {
 	struct assistant_config *cfg = user_data;
-	DBusMessageIter iter, dict, entry, value;
-	const char *key;
 
 	if (!strcasecmp(input, "a") || !strcasecmp(input, "auto"))
 		goto done;
@@ -305,32 +343,9 @@ static void assistant_set_metadata_cfg(const char *input, void *user_data)
 	}
 
 done:
-	/* Get QoS property to check if the stream is encrypted */
-	if (!g_dbus_proxy_get_property(cfg->proxy, "QoS", &iter))
+	if (!assistant_get_qos(cfg))
 		goto fail;
 
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
-		goto fail;
-
-	dbus_message_iter_recurse(&iter, &dict);
-
-	if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
-		goto fail;
-
-	dbus_message_iter_recurse(&dict, &entry);
-	dbus_message_iter_get_basic(&entry, &key);
-
-	if (strcasecmp(key, "Encryption") != 0)
-		goto fail;
-
-	dbus_message_iter_next(&entry);
-	dbus_message_iter_recurse(&entry, &value);
-
-	if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
-		goto fail;
-
-	dbus_message_iter_get_basic(&value, &cfg->qos.bcast.encryption);
-
 	if (cfg->qos.bcast.encryption)
 		/* Prompt user to enter the Broadcast Code to decrypt
 		 * the stream
@@ -355,9 +370,45 @@ fail:
 	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
+static void assistant_set_device_cfg(const char *input, void *user_data)
+{
+	struct assistant_config *cfg = user_data;
+
+	cfg->device = strdup(input);
+
+	if (!assistant_get_qos(cfg))
+		goto fail;
+
+	if (cfg->qos.bcast.encryption) {
+		/* Prompt user to enter the Broadcast Code to decrypt
+		 * the stream
+		 */
+		bt_shell_prompt_input("Assistant",
+				"Enter Broadcast Code (auto/value):",
+				assistant_set_bcode_cfg, cfg);
+	} else {
+		if (!g_dbus_proxy_method_call(cfg->proxy, "Push",
+						push_setup, push_reply,
+						cfg, NULL)) {
+			bt_shell_printf("Failed to push assistant\n");
+			goto fail;
+		}
+	}
+
+	return;
+
+fail:
+	free(cfg->device);
+	free(cfg->meta);
+	g_free(cfg);
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
+}
+
 static void cmd_push_assistant(int argc, char *argv[])
 {
 	struct assistant_config *cfg;
+	DBusMessageIter iter;
 
 	cfg = new0(struct assistant_config, 1);
 	if (!cfg)
@@ -371,6 +422,17 @@ static void cmd_push_assistant(int argc, char *argv[])
 		goto fail;
 	}
 
+	if (g_dbus_proxy_get_property(cfg->proxy, "State", &iter)) {
+		dbus_message_iter_get_basic(&iter, &cfg->state);
+
+		if (!strcmp(cfg->state, "local")) {
+			/* Prompt user to enter metadata */
+			bt_shell_prompt_input("Assistant",
+					"Enter Device (path):",
+					assistant_set_device_cfg, cfg);
+			return;
+		}
+	}
 	/* Prompt user to enter metadata */
 	bt_shell_prompt_input("Assistant",
 			"Enter Metadata (auto/value):",
diff --git a/client/mgmt.c b/client/mgmt.c
index 255155e41873..968efdbca5b0 100644
--- a/client/mgmt.c
+++ b/client/mgmt.c
@@ -369,7 +369,10 @@ static const char *settings_str[] = {
 				"cis-central",
 				"cis-peripheral",
 				"iso-broadcaster",
-				"sync-receiver"
+				"sync-receiver",
+				"ll-privacy",
+				"past-sender",
+				"past-receiver"
 };
 
 static const char *settings2str(uint32_t settings)
-- 
2.51.0


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

* [PATCH BlueZ v1 11/13] client/assistant: Detect if object already contains a valid BCode
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (8 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 10/13] client/assistant: Handle assistant.push to own broadcasts Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 12/13] client: Add script that setup a broadcast source with 2 BIS Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

If assistant object already contains a valid (non-zero) BCode
(e.g state=local) use it instead of always request the user to
re-enter.
---
 client/assistant.c | 55 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 41 insertions(+), 14 deletions(-)

diff --git a/client/assistant.c b/client/assistant.c
index 1ff8001d7216..ed0c8cdd6c7a 100644
--- a/client/assistant.c
+++ b/client/assistant.c
@@ -293,7 +293,7 @@ fail:
 
 static bool assistant_get_qos(struct assistant_config *cfg)
 {
-	DBusMessageIter iter, dict, entry, value;
+	DBusMessageIter iter, dict;
 	const char *key;
 
 	/* Get QoS property to check if the stream is encrypted */
@@ -305,22 +305,45 @@ static bool assistant_get_qos(struct assistant_config *cfg)
 
 	dbus_message_iter_recurse(&iter, &dict);
 
-	if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
-		return false;
+	while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY) {
+		DBusMessageIter entry, value;
+		int var;
 
-	dbus_message_iter_recurse(&dict, &entry);
-	dbus_message_iter_get_basic(&entry, &key);
+		dbus_message_iter_recurse(&dict, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
 
-	if (strcasecmp(key, "Encryption") != 0)
-		return false;
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &value);
 
-	dbus_message_iter_next(&entry);
-	dbus_message_iter_recurse(&entry, &value);
+		var = dbus_message_iter_get_arg_type(&value);
 
-	if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
-		return false;
+		if (!strcasecmp(key, "Encryption")) {
+			if (var != DBUS_TYPE_BYTE)
+				return false;
 
-	dbus_message_iter_get_basic(&value, &cfg->qos.bcast.encryption);
+			dbus_message_iter_get_basic(&value,
+						&cfg->qos.bcast.encryption);
+		} else if (!strcasecmp(key, "BCode")) {
+			DBusMessageIter array;
+			struct iovec iov = {0};
+
+			if (var != DBUS_TYPE_ARRAY)
+				return false;
+
+			dbus_message_iter_recurse(&value, &array);
+			dbus_message_iter_get_fixed_array(&array,
+							&iov.iov_base,
+							(int *)&iov.iov_len);
+
+			if (iov.iov_len != 16) {
+				bt_shell_printf("Invalid size for BCode: "
+						"%zu != 16\n", iov.iov_len);
+				return false;
+			}
+
+			memcpy(cfg->qos.bcast.bcode, iov.iov_base, iov.iov_len);
+		}
+	}
 
 	return true;
 }
@@ -328,6 +351,7 @@ static bool assistant_get_qos(struct assistant_config *cfg)
 static void assistant_set_metadata_cfg(const char *input, void *user_data)
 {
 	struct assistant_config *cfg = user_data;
+	uint8_t no_bcode[16] = {};
 
 	if (!strcasecmp(input, "a") || !strcasecmp(input, "auto"))
 		goto done;
@@ -346,7 +370,8 @@ done:
 	if (!assistant_get_qos(cfg))
 		goto fail;
 
-	if (cfg->qos.bcast.encryption)
+	if (cfg->qos.bcast.encryption &&
+			!memcmp(cfg->qos.bcast.bcode, no_bcode, 16))
 		/* Prompt user to enter the Broadcast Code to decrypt
 		 * the stream
 		 */
@@ -373,13 +398,15 @@ fail:
 static void assistant_set_device_cfg(const char *input, void *user_data)
 {
 	struct assistant_config *cfg = user_data;
+	uint8_t no_bcode[16] = {};
 
 	cfg->device = strdup(input);
 
 	if (!assistant_get_qos(cfg))
 		goto fail;
 
-	if (cfg->qos.bcast.encryption) {
+	if (cfg->qos.bcast.encryption &&
+			!memcmp(cfg->qos.bcast.bcode, no_bcode, 16)) {
 		/* Prompt user to enter the Broadcast Code to decrypt
 		 * the stream
 		 */
-- 
2.51.0


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

* [PATCH BlueZ v1 12/13] client: Add script that setup a broadcast source with 2 BIS
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (9 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 11/13] client/assistant: Detect if object already contains a valid BCode Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 21:00 ` [PATCH BlueZ v1 13/13] client: Add script for testing Broadcast Delegator Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds a testing script which setups 2 BIS Broadcast Source, one
for the left and another for right location.
---
 client/scripts/broadcast-source-2bis.bt | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 client/scripts/broadcast-source-2bis.bt

diff --git a/client/scripts/broadcast-source-2bis.bt b/client/scripts/broadcast-source-2bis.bt
new file mode 100644
index 000000000000..35b1846334be
--- /dev/null
+++ b/client/scripts/broadcast-source-2bis.bt
@@ -0,0 +1,19 @@
+power on
+endpoint.register 00001852-0000-1000-8000-00805f9b34fb 0x06
+y
+a
+3
+4
+endpoint.config /org/bluez/hci0/pac_bcast0 /local/endpoint/ep0 16_2_1
+1
+a
+a
+1
+0x03 0x02 0x04 0x00
+endpoint.config /org/bluez/hci0/pac_bcast0 /local/endpoint/ep0 16_2_1
+1
+a
+a
+2
+0x03 0x02 0x04 0x00
+transport.acquire /org/bluez/hci0/pac_bcast0/fd0 /org/bluez/hci0/pac_bcast0/fd1
-- 
2.51.0


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

* [PATCH BlueZ v1 13/13] client: Add script for testing Broadcast Delegator
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (10 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 12/13] client: Add script that setup a broadcast source with 2 BIS Luiz Augusto von Dentz
@ 2025-10-16 21:00 ` Luiz Augusto von Dentz
  2025-10-16 22:28 ` [BlueZ,v1,01/13] bass: Only attach client if initiator bluez.test.bot
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-16 21:00 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds a script for testing Broadcast Delagator role.
---
 client/scripts/broadcast-delegator.bt | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 client/scripts/broadcast-delegator.bt

diff --git a/client/scripts/broadcast-delegator.bt b/client/scripts/broadcast-delegator.bt
new file mode 100644
index 000000000000..e42db7335c24
--- /dev/null
+++ b/client/scripts/broadcast-delegator.bt
@@ -0,0 +1,9 @@
+power on
+endpoint.register 00001851-0000-1000-8000-00805f9b34fb 0x06
+y
+a
+3
+4
+transport.select auto
+transport.acquire auto
+advertise on
-- 
2.51.0


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

* RE: [BlueZ,v1,01/13] bass: Only attach client if initiator
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (11 preceding siblings ...)
  2025-10-16 21:00 ` [PATCH BlueZ v1 13/13] client: Add script for testing Broadcast Delegator Luiz Augusto von Dentz
@ 2025-10-16 22:28 ` bluez.test.bot
  2025-10-24 20:30 ` [PATCH BlueZ v1 01/13] " patchwork-bot+bluetooth
  2025-10-27 13:50 ` patchwork-bot+bluetooth
  14 siblings, 0 replies; 16+ messages in thread
From: bluez.test.bot @ 2025-10-16 22:28 UTC (permalink / raw)
  To: linux-bluetooth, luiz.dentz

[-- Attachment #1: Type: text/plain, Size: 2867 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1012546

---Test result---

Test Summary:
CheckPatch                    PENDING   0.28 seconds
GitLint                       PENDING   0.37 seconds
BuildEll                      PASS      20.29 seconds
BluezMake                     PASS      2700.81 seconds
MakeCheck                     PASS      21.09 seconds
MakeDistcheck                 PASS      189.20 seconds
CheckValgrind                 PASS      237.29 seconds
CheckSmatch                   WARNING   313.82 seconds
bluezmakeextell               PASS      128.70 seconds
IncrementalBuild              PENDING   0.22 seconds
ScanBuild                     PASS      932.41 seconds

Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:

##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:

##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
src/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:317:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structures
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:



---
Regards,
Linux Bluetooth


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

* Re: [PATCH BlueZ v1 01/13] bass: Only attach client if initiator
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (12 preceding siblings ...)
  2025-10-16 22:28 ` [BlueZ,v1,01/13] bass: Only attach client if initiator bluez.test.bot
@ 2025-10-24 20:30 ` patchwork-bot+bluetooth
  2025-10-27 13:50 ` patchwork-bot+bluetooth
  14 siblings, 0 replies; 16+ messages in thread
From: patchwork-bot+bluetooth @ 2025-10-24 20:30 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Thu, 16 Oct 2025 17:00:07 -0400 you wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This makes calling to bt_bass_attach conditional to being the initiator
> of the connection, otherwise both device may act as both roles which is
> not recommended.
> ---
>  profiles/audio/bass.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)

Here is the summary with links:
  - [BlueZ,v1,01/13] bass: Only attach client if initiator
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=43aed48c30da
  - [BlueZ,v1,02/13] device: Add initial support for setting DEVICE_FLAG_PAST
    (no matching commit)
  - [BlueZ,v1,03/13] bass: Add support for setting DEVICE_FLAG_PAST
    (no matching commit)
  - [BlueZ,v1,04/13] MediaAssistant: Add Device option to Push
    (no matching commit)
  - [BlueZ,v1,05/13] shared/bap: Add bt_bap_get_db
    (no matching commit)
  - [BlueZ,v1,06/13] shared/bap: Fix no calling attach callback on bt_bap_attach_broadcast
    (no matching commit)
  - [BlueZ,v1,07/13] shared/bap: Fix bt_bap_stream_io_get_qos for broadcast streams
    (no matching commit)
  - [BlueZ,v1,08/13] gatt-database: Add btd_gatt_database_get and btd_gatt_database_get_adapter
    (no matching commit)
  - [BlueZ,v1,09/13] bass: Implement Device option for Push
    (no matching commit)
  - [BlueZ,v1,10/13] client/assistant: Handle assistant.push to own broadcasts
    (no matching commit)
  - [BlueZ,v1,11/13] client/assistant: Detect if object already contains a valid BCode
    (no matching commit)
  - [BlueZ,v1,12/13] client: Add script that setup a broadcast source with 2 BIS
    (no matching commit)
  - [BlueZ,v1,13/13] client: Add script for testing Broadcast Delegator
    (no matching commit)

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



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

* Re: [PATCH BlueZ v1 01/13] bass: Only attach client if initiator
  2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
                   ` (13 preceding siblings ...)
  2025-10-24 20:30 ` [PATCH BlueZ v1 01/13] " patchwork-bot+bluetooth
@ 2025-10-27 13:50 ` patchwork-bot+bluetooth
  14 siblings, 0 replies; 16+ messages in thread
From: patchwork-bot+bluetooth @ 2025-10-27 13:50 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Thu, 16 Oct 2025 17:00:07 -0400 you wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This makes calling to bt_bass_attach conditional to being the initiator
> of the connection, otherwise both device may act as both roles which is
> not recommended.
> ---
>  profiles/audio/bass.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)

Here is the summary with links:
  - [BlueZ,v1,01/13] bass: Only attach client if initiator
    (no matching commit)
  - [BlueZ,v1,02/13] device: Add initial support for setting DEVICE_FLAG_PAST
    (no matching commit)
  - [BlueZ,v1,03/13] bass: Add support for setting DEVICE_FLAG_PAST
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=a5ceeb414c86
  - [BlueZ,v1,04/13] MediaAssistant: Add Device option to Push
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=1452790f1489
  - [BlueZ,v1,05/13] shared/bap: Add bt_bap_get_db
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=3c67d49258ca
  - [BlueZ,v1,06/13] shared/bap: Fix no calling attach callback on bt_bap_attach_broadcast
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=603ffaf50af1
  - [BlueZ,v1,07/13] shared/bap: Fix bt_bap_stream_io_get_qos for broadcast streams
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=c560149e1afb
  - [BlueZ,v1,08/13] gatt-database: Add btd_gatt_database_get and btd_gatt_database_get_adapter
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=bde3c34fd7ef
  - [BlueZ,v1,09/13] bass: Implement Device option for Push
    (no matching commit)
  - [BlueZ,v1,10/13] client/assistant: Handle assistant.push to own broadcasts
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=667db9a82a3f
  - [BlueZ,v1,11/13] client/assistant: Detect if object already contains a valid BCode
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=fdf49338d97d
  - [BlueZ,v1,12/13] client: Add script that setup a broadcast source with 2 BIS
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=e52f05e1d664
  - [BlueZ,v1,13/13] client: Add script for testing Broadcast Delegator
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=f80a2a57c910

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



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

end of thread, other threads:[~2025-10-27 13:50 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-16 21:00 [PATCH BlueZ v1 01/13] bass: Only attach client if initiator Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 02/13] device: Add initial support for setting DEVICE_FLAG_PAST Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 03/13] bass: Add " Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 04/13] MediaAssistant: Add Device option to Push Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 05/13] shared/bap: Add bt_bap_get_db Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 06/13] shared/bap: Fix no calling attach callback on bt_bap_attach_broadcast Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 07/13] shared/bap: Fix bt_bap_stream_io_get_qos for broadcast streams Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 08/13] gatt-database: Add btd_gatt_database_get and btd_gatt_database_get_adapter Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 09/13] bass: Implement Device option for Push Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 10/13] client/assistant: Handle assistant.push to own broadcasts Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 11/13] client/assistant: Detect if object already contains a valid BCode Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 12/13] client: Add script that setup a broadcast source with 2 BIS Luiz Augusto von Dentz
2025-10-16 21:00 ` [PATCH BlueZ v1 13/13] client: Add script for testing Broadcast Delegator Luiz Augusto von Dentz
2025-10-16 22:28 ` [BlueZ,v1,01/13] bass: Only attach client if initiator bluez.test.bot
2025-10-24 20:30 ` [PATCH BlueZ v1 01/13] " patchwork-bot+bluetooth
2025-10-27 13:50 ` patchwork-bot+bluetooth

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