diff mbox series

[BlueZ,v2,01/14] shared/bap: Allow multiple links per stream

Message ID 20241025122146.17925-2-iulia.tanasescu@nxp.com
State New
Headers show
Series bap: Add support for Broadcast Sink AC 13 | expand

Commit Message

Iulia Tanasescu Oct. 25, 2024, 12:21 p.m. UTC
This commit adds support to link multiple streams together, creating
the foundation for implementing broadcast links: for Broadcast Sinks,
the user could select multiple streams to receive audio from. All
selected streams need to be linked together and considered when
creating BIG sync.
---
 profiles/audio/transport.c |  38 ++++++--------
 src/shared/bap.c           | 104 +++++++++++++++++++++++++++++--------
 src/shared/bap.h           |   2 +-
 3 files changed, 97 insertions(+), 47 deletions(-)
diff mbox series

Patch

diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
index 68192bae6..d71013077 100644
--- a/profiles/audio/transport.c
+++ b/profiles/audio/transport.c
@@ -330,12 +330,9 @@  static void transport_bap_remove_owner(struct media_transport *transport,
 {
 	struct bap_transport *bap = transport->data;
 
-	if (bap && bap->linked) {
-		struct bt_bap_stream *link;
-
-		link = bt_bap_stream_io_get_link(bap->stream);
-		linked_transport_remove_owner(link, owner);
-	}
+	if (bap && bap->linked)
+		queue_foreach(bt_bap_stream_io_get_links(bap->stream),
+				linked_transport_remove_owner, owner);
 }
 
 static void media_transport_remove_owner(struct media_transport *transport)
@@ -581,12 +578,9 @@  static void transport_bap_set_owner(struct media_transport *transport,
 {
 	struct bap_transport *bap = transport->data;
 
-	if (bap && bap->linked) {
-		struct bt_bap_stream *link;
-
-		link = bt_bap_stream_io_get_link(bap->stream);
-		linked_transport_set_owner(link, owner);
-	}
+	if (bap && bap->linked)
+		queue_foreach(bt_bap_stream_io_get_links(bap->stream),
+				linked_transport_set_owner, owner);
 }
 
 static void media_transport_set_owner(struct media_transport *transport,
@@ -1129,14 +1123,14 @@  static gboolean get_links(const GDBusPropertyTable *property,
 {
 	struct media_transport *transport = data;
 	struct bap_transport *bap = transport->data;
-	struct bt_bap_stream *link = bt_bap_stream_io_get_link(bap->stream);
+	struct queue *links = bt_bap_stream_io_get_links(bap->stream);
 	DBusMessageIter array;
 
 	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
 					DBUS_TYPE_OBJECT_PATH_AS_STRING,
 					&array);
 
-	append_link(link, &array);
+	queue_foreach(links, append_link, &array);
 
 	dbus_message_iter_close_container(iter, &array);
 
@@ -1572,15 +1566,15 @@  static bool match_link_transport(const void *data, const void *user_data)
 static void bap_update_links(const struct media_transport *transport)
 {
 	struct bap_transport *bap = transport->data;
-	struct bt_bap_stream *link = bt_bap_stream_io_get_link(bap->stream);
+	struct queue *links = bt_bap_stream_io_get_links(bap->stream);
 
-	if (bap->linked == (!!link))
+	if (bap->linked == !queue_isempty(links))
 		return;
 
-	bap->linked = link ? true : false;
+	bap->linked = !queue_isempty(links);
 
 	/* Check if the links transport has been create yet */
-	if (bap->linked && !match_link_transport(link, NULL)) {
+	if (bap->linked && !queue_find(links, match_link_transport, NULL)) {
 		bap->linked = false;
 		return;
 	}
@@ -1757,15 +1751,13 @@  static void transport_bap_set_state(struct media_transport *transport,
 					transport_state_t state)
 {
 	struct bap_transport *bap = transport->data;
-	struct bt_bap_stream *link;
 
 	if (!bap->linked)
 		return;
 
-	link = bt_bap_stream_io_get_link(bap->stream);
-
-	/* Update link */
-	link_set_state(link, UINT_TO_PTR(state));
+	/* Update links */
+	queue_foreach(bt_bap_stream_io_get_links(bap->stream), link_set_state,
+							UINT_TO_PTR(state));
 }
 
 static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
diff --git a/src/shared/bap.c b/src/shared/bap.c
index 8d04290f8..0b234275c 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -262,7 +262,7 @@  struct bt_bap_stream {
 	struct iovec *cc;
 	struct iovec *meta;
 	struct bt_bap_qos qos;
-	struct bt_bap_stream *link;
+	struct queue *links;
 	struct bt_bap_stream_io *io;
 	const struct bt_bap_stream_ops *ops;
 	uint8_t old_state;
@@ -1101,6 +1101,14 @@  static void stream_io_unref(struct bt_bap_stream_io *io)
 	stream_io_free(io);
 }
 
+static void bap_stream_unlink(void *data, void *user_data)
+{
+	struct bt_bap_stream *stream = data;
+	struct bt_bap_stream *link = user_data;
+
+	queue_remove(stream->links, link);
+}
+
 static void bap_stream_free(void *data)
 {
 	struct bt_bap_stream *stream = data;
@@ -1110,8 +1118,8 @@  static void bap_stream_free(void *data)
 	if (stream->ep)
 		stream->ep->stream = NULL;
 
-	if (stream->link)
-		stream->link->link = NULL;
+	queue_foreach(stream->links, bap_stream_unlink, stream);
+	queue_destroy(stream->links, NULL);
 
 	stream_io_unref(stream->io);
 	util_iov_free(stream->cc, 1);
@@ -1246,6 +1254,17 @@  static void bap_stream_update_io_links(struct bt_bap_stream *stream)
 	queue_find(bap->streams, bap_stream_io_link, stream);
 }
 
+static bool match_stream_io(const void *data, const void *user_data)
+{
+	const struct bt_bap_stream *stream = data;
+	const struct bt_bap_stream_io *io = user_data;
+
+	if (!stream->io)
+		return false;
+
+	return stream->io == io;
+}
+
 static bool bap_stream_io_detach(struct bt_bap_stream *stream)
 {
 	struct bt_bap_stream *link;
@@ -1259,7 +1278,7 @@  static bool bap_stream_io_detach(struct bt_bap_stream *stream)
 	io = stream->io;
 	stream->io = NULL;
 
-	link = stream->link;
+	link = queue_find(stream->links, match_stream_io, io);
 	if (link) {
 		/* Detach link if in QoS state */
 		if (link->ep->state == BT_ASCS_ASE_STATE_QOS)
@@ -1803,6 +1822,14 @@  static unsigned int bap_bcast_config(struct bt_bap_stream *stream,
 	return 1;
 }
 
+static void bap_stream_enable_link(void *data, void *user_data)
+{
+	struct bt_bap_stream *stream = data;
+	struct iovec *metadata = user_data;
+
+	bap_stream_metadata(stream, BT_ASCS_ENABLE, metadata, NULL, NULL);
+}
+
 static unsigned int bap_ucast_enable(struct bt_bap_stream *stream,
 					bool enable_links, struct iovec *data,
 					bt_bap_stream_func_t func,
@@ -1821,9 +1848,7 @@  static unsigned int bap_ucast_enable(struct bt_bap_stream *stream,
 	if (!ret || !enable_links)
 		return ret;
 
-	if (stream->link)
-		bap_stream_metadata(stream->link, BT_ASCS_ENABLE, data,
-					NULL, NULL);
+	queue_foreach(stream->links, bap_stream_enable_link, data);
 
 	return ret;
 }
@@ -1893,6 +1918,13 @@  static uint8_t stream_disable(struct bt_bap_stream *stream, struct iovec *rsp)
 	return 0;
 }
 
+static void bap_stream_disable_link(void *data, void *user_data)
+{
+	struct bt_bap_stream *stream = data;
+
+	bt_bap_stream_disable(stream, false, NULL, NULL);
+}
+
 static unsigned int bap_ucast_disable(struct bt_bap_stream *stream,
 					bool disable_links,
 					bt_bap_stream_func_t func,
@@ -1919,7 +1951,7 @@  static unsigned int bap_ucast_disable(struct bt_bap_stream *stream,
 	}
 
 	if (disable_links)
-		bt_bap_stream_disable(stream->link, false, NULL, NULL);
+		queue_foreach(stream->links, bap_stream_disable_link, NULL);
 
 	return req->id;
 }
@@ -2351,18 +2383,30 @@  static struct bt_bap_stream_io *stream_io_new(struct bt_bap *bap, int fd)
 	return stream_io_ref(sio);
 }
 
+static void stream_find_io(void *data, void *user_data)
+{
+	struct bt_bap_stream *stream = data;
+	struct bt_bap_stream_io **io = user_data;
+
+	if (*io)
+		return;
+
+	*io = stream->io;
+}
+
 static struct bt_bap_stream_io *stream_get_io(struct bt_bap_stream *stream)
 {
+	struct bt_bap_stream_io *io = NULL;
+
 	if (!stream)
 		return NULL;
 
 	if (stream->io)
 		return stream->io;
 
-	if (stream->link)
-		return stream->link->io;
+	queue_foreach(stream->links, stream_find_io, &io);
 
-	return NULL;
+	return io;
 }
 
 static bool stream_io_disconnected(struct io *io, void *user_data);
@@ -5849,8 +5893,7 @@  bool bt_bap_stream_set_io(struct bt_bap_stream *stream, int fd)
 
 	bap_stream_set_io(stream, INT_TO_PTR(fd));
 
-	if (stream->link)
-		bap_stream_set_io(stream->link, INT_TO_PTR(fd));
+	queue_foreach(stream->links, bap_stream_set_io, INT_TO_PTR(fd));
 
 	return true;
 }
@@ -5905,7 +5948,8 @@  int bt_bap_stream_io_link(struct bt_bap_stream *stream,
 
 	bap = stream->bap;
 
-	if (stream->link || link->link)
+	if (queue_find(stream->links, NULL, link) ||
+		queue_find(link->links, NULL, stream))
 		return -EALREADY;
 
 	if (stream->client != link->client ||
@@ -5914,8 +5958,14 @@  int bt_bap_stream_io_link(struct bt_bap_stream *stream,
 			stream->ep->dir == link->ep->dir)
 		return -EINVAL;
 
-	stream->link = link;
-	link->link = stream;
+	if (!stream->links)
+		stream->links = queue_new();
+
+	if (!link->links)
+		link->links = queue_new();
+
+	queue_push_tail(stream->links, link);
+	queue_push_tail(link->links, stream);
 
 	/* Link IOs if already set on stream/link */
 	if (stream->io && !link->io)
@@ -5928,12 +5978,12 @@  int bt_bap_stream_io_link(struct bt_bap_stream *stream,
 	return 0;
 }
 
-struct bt_bap_stream *bt_bap_stream_io_get_link(struct bt_bap_stream *stream)
+struct queue *bt_bap_stream_io_get_links(struct bt_bap_stream *stream)
 {
 	if (!stream)
 		return NULL;
 
-	return stream->link;
+	return stream->links;
 }
 
 static void bap_stream_get_in_qos(void *data, void *user_data)
@@ -5976,11 +6026,11 @@  bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream,
 	switch (stream->ep->dir) {
 	case BT_BAP_SOURCE:
 		bap_stream_get_in_qos(stream, in);
-		bap_stream_get_out_qos(stream->link, out);
+		queue_foreach(stream->links, bap_stream_get_out_qos, out);
 		break;
 	case BT_BAP_SINK:
 		bap_stream_get_out_qos(stream, out);
-		bap_stream_get_in_qos(stream->link, in);
+		queue_foreach(stream->links, bap_stream_get_in_qos, in);
 		break;
 	default:
 		return false;
@@ -5991,6 +6041,14 @@  bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream,
 	return in && out;
 }
 
+static void bap_stream_get_dir(void *data, void *user_data)
+{
+	struct bt_bap_stream *stream = data;
+	uint8_t *dir = user_data;
+
+	*dir |= stream->ep->dir;
+}
+
 uint8_t bt_bap_stream_io_dir(struct bt_bap_stream *stream)
 {
 	uint8_t dir;
@@ -6010,8 +6068,7 @@  uint8_t bt_bap_stream_io_dir(struct bt_bap_stream *stream)
 
 	}
 
-	if (stream->link)
-		dir |= stream->link->ep->dir;
+	queue_foreach(stream->links, bap_stream_get_dir, &dir);
 
 	return dir;
 }
@@ -6046,7 +6103,8 @@  int bt_bap_stream_io_connecting(struct bt_bap_stream *stream, int fd)
 		return -EINVAL;
 
 	bap_stream_io_connecting(stream, INT_TO_PTR(fd));
-	bap_stream_io_connecting(stream->link, INT_TO_PTR(fd));
+
+	queue_foreach(stream->links, bap_stream_io_connecting, INT_TO_PTR(fd));
 
 	return 0;
 }
diff --git a/src/shared/bap.h b/src/shared/bap.h
index bf928bc2d..cd5ea2eba 100644
--- a/src/shared/bap.h
+++ b/src/shared/bap.h
@@ -231,7 +231,7 @@  int bt_bap_stream_cancel(struct bt_bap_stream *stream, unsigned int id);
 
 int bt_bap_stream_io_link(struct bt_bap_stream *stream,
 					struct bt_bap_stream *link);
-struct bt_bap_stream *bt_bap_stream_io_get_link(struct bt_bap_stream *stream);
+struct queue *bt_bap_stream_io_get_links(struct bt_bap_stream *stream);
 bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream,
 					struct bt_bap_qos **in,
 					struct bt_bap_qos **out);