diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index d840d0c4d89..a7c35e6a653 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -1289,17 +1289,27 @@ struct bt_audio_lc3_preset { * symmetric in both directions. */ struct bt_audio_stream { + /** Stream direction */ + enum bt_audio_dir dir; + /** Connection reference */ struct bt_conn *conn; + /** Endpoint reference */ struct bt_audio_ep *ep; + /** Codec Configuration */ struct bt_codec *codec; + /** QoS Configuration */ struct bt_codec_qos *qos; + /** Audio stream operations */ struct bt_audio_stream_ops *ops; + /** Audio ISO reference */ + struct bt_audio_iso *audio_iso; + union { void *group; struct bt_audio_unicast_group *unicast_group; diff --git a/subsys/bluetooth/audio/audio_iso.c b/subsys/bluetooth/audio/audio_iso.c index 56403cf0202..0fb5c27a389 100644 --- a/subsys/bluetooth/audio/audio_iso.c +++ b/subsys/bluetooth/audio/audio_iso.c @@ -141,16 +141,12 @@ void bt_audio_iso_init(struct bt_audio_iso *iso, struct bt_iso_chan_ops *ops) void bt_audio_iso_bind_ep(struct bt_audio_iso *iso, struct bt_audio_ep *ep) { - struct bt_iso_chan_qos *qos; - __ASSERT_NO_MSG(ep != NULL); __ASSERT_NO_MSG(iso != NULL); __ASSERT(ep->iso == NULL, "ep %p bound with iso %p already", ep, ep->iso); __ASSERT(ep->dir == BT_AUDIO_DIR_SINK || ep->dir == BT_AUDIO_DIR_SOURCE, "invalid dir: %u", ep->dir); - qos = iso->chan.qos; - if (IS_ENABLED(CONFIG_BT_AUDIO_UNICAST_CLIENT) && bt_audio_ep_is_unicast_client(ep)) { /* For the unicast client, the direction and tx/rx is reversed */ @@ -180,8 +176,6 @@ void bt_audio_iso_bind_ep(struct bt_audio_iso *iso, struct bt_audio_ep *ep) void bt_audio_iso_unbind_ep(struct bt_audio_iso *iso, struct bt_audio_ep *ep) { - struct bt_iso_chan_qos *qos; - __ASSERT_NO_MSG(ep != NULL); __ASSERT_NO_MSG(iso != NULL); __ASSERT(ep->iso == iso, "ep %p not bound with iso %p, was bound to %p", @@ -189,8 +183,6 @@ void bt_audio_iso_unbind_ep(struct bt_audio_iso *iso, struct bt_audio_ep *ep) __ASSERT(ep->dir == BT_AUDIO_DIR_SINK || ep->dir == BT_AUDIO_DIR_SOURCE, "Invalid dir: %u", ep->dir); - qos = iso->chan.qos; - if (IS_ENABLED(CONFIG_BT_AUDIO_UNICAST_CLIENT) && bt_audio_ep_is_unicast_client(ep)) { /* For the unicast client, the direction and tx/rx is reversed */ @@ -242,3 +234,72 @@ struct bt_audio_ep *bt_audio_iso_get_ep(bool unicast_client, return iso->tx.ep; } } + +#if defined(CONFIG_BT_AUDIO_UNICAST_CLIENT) +void bt_audio_iso_bind_stream(struct bt_audio_iso *audio_iso, + struct bt_audio_stream *stream) +{ + struct bt_audio_iso_dir *audio_iso_ep; + + __ASSERT_NO_MSG(stream != NULL); + __ASSERT_NO_MSG(audio_iso != NULL); + __ASSERT(stream->audio_iso == NULL, + "stream %p bound with audio_iso %p already", + stream, stream->audio_iso); + + /* For the unicast client, the direction and tx/rx is reversed */ + if (stream->dir == BT_AUDIO_DIR_SOURCE) { + audio_iso_ep = &audio_iso->rx; + } else { + audio_iso_ep = &audio_iso->tx; + } + + __ASSERT(audio_iso_ep->stream == NULL, + "audio_iso %p bound with stream %p", + audio_iso, audio_iso_ep->stream); + audio_iso_ep->stream = stream; + + stream->audio_iso = bt_audio_iso_ref(audio_iso); +} + +void bt_audio_iso_unbind_stream(struct bt_audio_iso *audio_iso, + struct bt_audio_stream *stream) +{ + struct bt_audio_iso_dir *audio_iso_ep; + + __ASSERT_NO_MSG(stream != NULL); + __ASSERT_NO_MSG(audio_iso != NULL); + __ASSERT(stream->audio_iso != NULL, + "stream %p not bound with an audio_iso", + stream); + + /* For the unicast client, the direction and tx/rx is reversed */ + if (stream->dir == BT_AUDIO_DIR_SOURCE) { + audio_iso_ep = &audio_iso->rx; + } else { + audio_iso_ep = &audio_iso->tx; + } + + __ASSERT(audio_iso_ep->stream == stream, + "audio_iso %p (%p) not bound with stream %p (%p)", + audio_iso, audio_iso_ep->stream, stream, stream->audio_iso); + audio_iso_ep->stream = NULL; + + bt_audio_iso_unref(audio_iso); + stream->audio_iso = NULL; +} + +struct bt_audio_stream *bt_audio_iso_get_stream(struct bt_audio_iso *iso, + enum bt_audio_dir dir) +{ + __ASSERT(dir == BT_AUDIO_DIR_SINK || dir == BT_AUDIO_DIR_SOURCE, + "invalid dir: %u", dir); + + /* For the unicast client, the direction and tx/rx is reversed */ + if (dir == BT_AUDIO_DIR_SOURCE) { + return iso->rx.stream; + } else { + return iso->tx.stream; + } +} +#endif /* CONFIG_BT_AUDIO_UNICAST_CLIENT */ diff --git a/subsys/bluetooth/audio/audio_iso.h b/subsys/bluetooth/audio/audio_iso.h index 9298e377429..d57780ad934 100644 --- a/subsys/bluetooth/audio/audio_iso.h +++ b/subsys/bluetooth/audio/audio_iso.h @@ -9,7 +9,8 @@ #include #include -struct bt_audio_iso_ep { +struct bt_audio_iso_dir { + struct bt_audio_stream *stream; struct bt_audio_ep *ep; struct bt_iso_chan_path path; struct bt_iso_chan_io_qos qos; @@ -20,8 +21,8 @@ struct bt_audio_iso { struct bt_iso_chan chan; struct bt_iso_chan_qos qos; - struct bt_audio_iso_ep rx; - struct bt_audio_iso_ep tx; + struct bt_audio_iso_dir rx; + struct bt_audio_iso_dir tx; /* Must be at the end so that everything else in the structure can be * memset to zero without affecting the ref. @@ -43,3 +44,10 @@ void bt_audio_iso_unbind_ep(struct bt_audio_iso *iso, struct bt_audio_ep *ep); struct bt_audio_ep *bt_audio_iso_get_ep(bool unicast_client, struct bt_audio_iso *iso, enum bt_audio_dir dir); +/* Unicast client-only functions*/ +void bt_audio_iso_bind_stream(struct bt_audio_iso *audio_iso, + struct bt_audio_stream *stream); +void bt_audio_iso_unbind_stream(struct bt_audio_iso *audio_iso, + struct bt_audio_stream *stream); +struct bt_audio_stream *bt_audio_iso_get_stream(struct bt_audio_iso *iso, + enum bt_audio_dir dir); diff --git a/subsys/bluetooth/audio/stream.c b/subsys/bluetooth/audio/stream.c index eddc7298503..92aba6d3fab 100644 --- a/subsys/bluetooth/audio/stream.c +++ b/subsys/bluetooth/audio/stream.c @@ -565,11 +565,12 @@ int bt_audio_stream_qos(struct bt_conn *conn, return -EINVAL; } - if (ep->iso == NULL) { + if (stream->audio_iso == NULL) { /* This can only happen if the stream was somehow added * to a group without the audio_iso being bound to it */ - LOG_ERR("Could not find audio_iso for stream %p", stream); + LOG_ERR("Could not find audio_iso for stream %p", + stream); return -EINVAL; } } @@ -594,6 +595,11 @@ int bt_audio_stream_qos(struct bt_conn *conn, op->num_ases++; + if (stream->ep->iso == NULL) { + /* Not yet bound with the audio_iso */ + bt_audio_iso_bind_ep(stream->audio_iso, stream->ep); + } + err = bt_unicast_client_ep_qos(stream->ep, buf, stream->qos); if (err) { audio_stream_qos_cleanup(conn, group); @@ -741,18 +747,24 @@ static struct bt_audio_iso *get_new_iso(struct bt_audio_unicast_group *group, /* Check if there's already an ISO that can be used for this direction */ SYS_SLIST_FOR_EACH_CONTAINER(&group->streams, stream, _node) { - __ASSERT(stream->ep, "stream->ep is NULL"); - __ASSERT(stream->ep->iso, "ep->iso is NULL"); + __ASSERT(stream->audio_iso != NULL, "stream->audio_iso is NULL"); - if (stream->conn != acl) { + /* Don't attempt to couple streams if the ACL is either NULL, + * or the connection points differ + */ + if (acl == NULL || stream->conn != acl) { continue; } - if (bt_audio_iso_get_ep(true, stream->ep->iso, dir) == NULL) { - return bt_audio_iso_ref(stream->ep->iso); + if (bt_audio_iso_get_stream(stream->audio_iso, dir) == NULL) { + LOG_DBG("Returning existing audio_iso for group %p", + group); + + return bt_audio_iso_ref(stream->audio_iso); } } + LOG_DBG("Returning new audio_iso for group %p", group); return bt_unicast_client_new_audio_iso(); } @@ -861,8 +873,10 @@ static int unicast_group_add_stream(struct bt_audio_unicast_group *group, __ASSERT_NO_MSG(group != NULL); __ASSERT_NO_MSG(stream != NULL); - __ASSERT_NO_MSG(stream->ep != NULL); - __ASSERT_NO_MSG(stream->ep->iso == NULL); + __ASSERT_NO_MSG(stream->ep == NULL || + (stream->ep != NULL && stream->ep->iso == NULL)); + + LOG_DBG("group %p stream %p dir %u", group, stream, dir); iso = get_new_iso(group, stream->conn, dir); if (iso == NULL) { @@ -875,16 +889,20 @@ static int unicast_group_add_stream(struct bt_audio_unicast_group *group, return err; } + stream->qos = qos; + stream->dir = dir; + stream->unicast_group = group; + /* iso initialized already */ - bt_audio_iso_bind_ep(iso, stream->ep); + bt_audio_iso_bind_stream(iso, stream); + if (stream->ep != NULL) { + bt_audio_iso_bind_ep(iso, stream->ep); + } /* Store the Codec QoS in the audio_iso */ unicast_client_codec_qos_to_iso_qos(iso, qos, dir); bt_audio_iso_unref(iso); - - stream->qos = qos; - stream->unicast_group = group; sys_slist_append(&group->streams, &stream->_node); LOG_DBG("Added stream %p to group %p", stream, group); @@ -901,6 +919,10 @@ static void unicast_group_del_stream(struct bt_audio_unicast_group *group, if (sys_slist_find_and_remove(&group->streams, &stream->_node)) { struct bt_audio_ep *ep = stream->ep; + if (stream->audio_iso != NULL) { + bt_audio_iso_unbind_stream(stream->audio_iso, stream); + } + if (ep != NULL && ep->iso != NULL) { unicast_group_del_iso(group, ep->iso); @@ -941,6 +963,9 @@ static void unicast_group_free(struct bt_audio_unicast_group *group) struct bt_audio_ep *ep = stream->ep; stream->unicast_group = NULL; + if (stream->audio_iso != NULL) { + bt_audio_iso_unbind_stream(stream->audio_iso, stream); + } if (ep != NULL && ep->iso != NULL) { bt_audio_iso_unbind_ep(ep->iso, ep);