Bluetooth: Audio: Add (un)bind of audio iso for streams

This allows us to allocate and bind the Audio ISO structs
to Audio Streams, thus allowing us to create the unicast group
before they have been configured.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2022-12-22 12:29:29 +01:00 committed by Carles Cufí
commit 32ff1b671b
4 changed files with 128 additions and 24 deletions

View file

@ -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 */

View file

@ -9,7 +9,8 @@
#include <zephyr/bluetooth/iso.h>
#include <zephyr/bluetooth/audio/audio.h>
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);

View file

@ -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);