Bluetooth: BAP: Unicast client Split start and connect

Removes the CIS connection establishment from bt_bap_stream_start
and move the behavior to a new funciton bt_bap_stream_connect.

This has 2 advantages:
1) The behavior of bt_bap_stream_start is much more clear and more aligned
with the spec's behavior for the receiver start ready opcode.
2) It is possible to connect streams in both the enabling
and the QoS configured state with bt_bap_stream_connect as
per the spec. This allows us to pass additional PTS test cases.

To implement this new behavior, samples and tests have been updated.

The CAP Initiator implementation has also been updated
to accomodate for the change in BAP, but the CAP
initiator implementation should work the same for application, except
that it's now possible to do unicast start on ASEs in any order
(https://github.com/zephyrproject-rtos/zephyr/issues/72138).

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2024-05-20 17:07:48 +02:00 committed by Alberto Escolar
commit d2fbeffaa9
17 changed files with 969 additions and 231 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -59,6 +59,7 @@ static K_SEM_DEFINE(sem_stream_configured, 0, 1);
static K_SEM_DEFINE(sem_stream_qos, 0, ARRAY_SIZE(sinks) + ARRAY_SIZE(sources));
static K_SEM_DEFINE(sem_stream_enabled, 0, 1);
static K_SEM_DEFINE(sem_stream_started, 0, 1);
static K_SEM_DEFINE(sem_stream_connected, 0, 1);
#define AUDIO_DATA_TIMEOUT_US 1000000UL /* Send data every 1 second */
@ -518,9 +519,9 @@ static void stream_enabled(struct bt_bap_stream *stream)
k_sem_give(&sem_stream_enabled);
}
static void stream_started(struct bt_bap_stream *stream)
static void stream_connected_cb(struct bt_bap_stream *stream)
{
printk("Audio Stream %p started\n", stream);
printk("Audio Stream %p connected\n", stream);
/* Reset sequence number for sinks */
for (size_t i = 0U; i < configured_sink_stream_count; i++) {
@ -530,6 +531,13 @@ static void stream_started(struct bt_bap_stream *stream)
}
}
k_sem_give(&sem_stream_connected);
}
static void stream_started(struct bt_bap_stream *stream)
{
printk("Audio Stream %p started\n", stream);
k_sem_give(&sem_stream_started);
}
@ -576,7 +584,8 @@ static struct bt_bap_stream_ops stream_ops = {
.disabled = stream_disabled,
.stopped = stream_stopped,
.released = stream_released,
.recv = stream_recv
.recv = stream_recv,
.connected = stream_connected_cb,
};
static void add_remote_source(struct bt_bap_ep *ep)
@ -1018,17 +1027,62 @@ static int enable_streams(void)
return 0;
}
static int start_streams(void)
static int connect_streams(void)
{
for (size_t i = 0U; i < configured_stream_count; i++) {
int err;
err = bt_bap_stream_start(&streams[i]);
if (err != 0) {
k_sem_reset(&sem_stream_connected);
err = bt_bap_stream_connect(&streams[i]);
if (err == -EALREADY) {
/* We have already connected a paired stream */
continue;
} else if (err != 0) {
printk("Unable to start stream: %d\n", err);
return err;
}
err = k_sem_take(&sem_stream_connected, K_FOREVER);
if (err != 0) {
printk("failed to take sem_stream_connected (err %d)\n", err);
return err;
}
}
return 0;
}
static enum bt_audio_dir stream_dir(const struct bt_bap_stream *stream)
{
struct bt_bap_ep_info ep_info;
int err;
err = bt_bap_ep_get_info(stream->ep, &ep_info);
if (err != 0) {
printk("Failed to get ep info for %p: %d\n", stream, err);
__ASSERT_NO_MSG(false);
return 0;
}
return ep_info.dir;
}
static int start_streams(void)
{
for (size_t i = 0U; i < configured_stream_count; i++) {
struct bt_bap_stream *stream = &streams[i];
int err;
if (stream_dir(stream) == BT_AUDIO_DIR_SOURCE) {
err = bt_bap_stream_start(&streams[i]);
if (err != 0) {
printk("Unable to start stream: %d\n", err);
return err;
}
} /* Sink streams are started by the unicast server */
err = k_sem_take(&sem_stream_started, K_FOREVER);
if (err != 0) {
printk("failed to take sem_stream_started (err %d)\n", err);
@ -1051,6 +1105,7 @@ static void reset_data(void)
k_sem_reset(&sem_stream_qos);
k_sem_reset(&sem_stream_enabled);
k_sem_reset(&sem_stream_started);
k_sem_reset(&sem_stream_connected);
configured_sink_stream_count = 0;
configured_source_stream_count = 0;
@ -1131,6 +1186,13 @@ int main(void)
}
printk("Streams enabled\n");
printk("Connecting streams\n");
err = connect_streams();
if (err != 0) {
return 0;
}
printk("Streams connected\n");
printk("Starting streams\n");
err = start_streams();
if (err != 0) {

View file

@ -1,7 +1,7 @@
/** @file
* @brief Bluetooth Basic Audio Profile (BAP) Unicast Server role.
*
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
* Copyright (c) 2022 Codecoup
* Copyright (c) 2023 NXP
*
@ -293,10 +293,23 @@ static void stream_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_i
static void stream_enabled(struct bt_bap_stream *stream)
{
const int err = bt_bap_stream_start(stream);
struct bt_bap_ep_info ep_info;
int err;
err = bt_bap_ep_get_info(stream->ep, &ep_info);
if (err != 0) {
printk("Failed to start stream %p: %d", stream, err);
printk("Failed to get ep info: %d\n", err);
return;
}
/* The unicast server is responsible for starting the sink streams */
if (ep_info.dir == BT_AUDIO_DIR_SINK) {
/* Automatically do the receiver start ready operation */
err = bt_bap_stream_start(stream);
if (err != 0) {
printk("Failed to start stream %p: %d", stream, err);
}
}
}