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 --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 00c3b9ff6..1b70df4d5 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; } @@ -1872,6 +1897,13 @@ static unsigned int bap_ucast_start(struct bt_bap_stream *stream, return req->id; } +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, @@ -1895,7 +1927,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; } @@ -2327,18 +2359,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); @@ -5846,8 +5890,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; } @@ -5902,7 +5945,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 || @@ -5911,8 +5955,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) @@ -5925,12 +5975,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) @@ -5973,11 +6023,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; @@ -5988,6 +6038,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; @@ -6007,8 +6065,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; } @@ -6043,7 +6100,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); -- 2.43.0