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

@ -44,6 +44,12 @@ int bt_bap_unicast_client_disable(struct bt_bap_stream *stream)
return 0;
}
int bt_bap_unicast_client_connect(struct bt_bap_stream *stream)
{
zassert_unreachable("Unexpected call to '%s()' occurred", __func__);
return 0;
}
int bt_bap_unicast_client_start(struct bt_bap_stream *stream)
{
zassert_unreachable("Unexpected call to '%s()' occurred", __func__);

View file

@ -13,6 +13,7 @@
#include <zephyr/kernel.h>
#include <zephyr/sys/ring_buffer.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/hci_types.h>
#include <hci_core.h>
#include "bap_endpoint.h"
@ -636,6 +637,26 @@ static void stream_started(struct bt_bap_stream *stream)
btp_send_ascs_ase_state_changed_ev(stream->conn, u_stream->ase_id, info.state);
}
static void stream_connected(struct bt_bap_stream *stream)
{
struct bt_conn_info conn_info;
struct bt_bap_ep_info ep_info;
int err;
LOG_DBG("Connected stream %p", stream);
(void)bt_bap_ep_get_info(stream->ep, &ep_info);
(void)bt_conn_get_info(stream->conn, &conn_info);
if (conn_info.role == BT_HCI_ROLE_CENTRAL && ep_info.dir == BT_AUDIO_DIR_SOURCE) {
/* Automatically do the receiver start ready operation for source ASEs as the client
*/
err = bt_bap_stream_start(stream);
if (err != 0) {
LOG_ERR("Failed to start stream %p", stream);
}
}
}
static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason)
{
struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
@ -703,6 +724,7 @@ static struct bt_bap_stream_ops stream_ops = {
.stopped = stream_stopped,
.recv = stream_recv,
.sent = stream_sent,
.connected = stream_connected,
};
struct btp_bap_unicast_stream *btp_bap_unicast_stream_alloc(
@ -1419,7 +1441,7 @@ uint8_t btp_ascs_receiver_start_ready(const void *cmd, uint16_t cmd_len,
LOG_DBG("Starting stream %p, ep %u, dir %u", bap_stream, cp->ase_id, info.dir);
while (true) {
err = bt_bap_stream_start(bap_stream);
err = bt_bap_stream_connect(bap_stream);
if (err == -EBUSY) {
/* TODO: How to determine if a controller is ready again after
* bt_bap_stream_start? In AC 6(i) tests the PTS sends Receiver Start Ready
@ -1427,8 +1449,8 @@ uint8_t btp_ascs_receiver_start_ready(const void *cmd, uint16_t cmd_len,
*/
k_sleep(K_MSEC(1000));
continue;
} else if (err != 0) {
LOG_DBG("Could not start stream: %d", err);
} else if (err != 0 && err != -EALREADY) {
LOG_DBG("Could not connect stream: %d", err);
return BTP_STATUS_FAILED;
}

View file

@ -159,6 +159,7 @@ CONFIG_BT_PBP=y
# DEBUGGING
CONFIG_LOG=y
CONFIG_BT_ISO_LOG_LEVEL_DBG=y
CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y
CONFIG_LOG_FUNC_NAME_PREFIX_WRN=y
CONFIG_BT_VCP_VOL_REND_LOG_LEVEL_DBG=y

View file

@ -752,6 +752,64 @@ static void metadata_update_streams(size_t stream_cnt)
}
}
static int connect_stream(struct bt_bap_stream *stream)
{
int err;
UNSET_FLAG(flag_stream_started);
do {
err = bt_bap_stream_connect(stream);
if (err == -EALREADY) {
SET_FLAG(flag_stream_started);
} else if (err != 0) {
FAIL("Could not start stream %p: %d\n", stream, err);
return err;
}
} while (err == -EBUSY);
WAIT_FOR_FLAG(flag_stream_started);
return 0;
}
static void connect_streams(void)
{
struct bt_bap_stream *source_stream;
struct bt_bap_stream *sink_stream;
/* We only support a single CIS so far, so only start one. We can use the group pair
* params to start both a sink and source stream that use the same CIS
*/
source_stream = pair_params[0].rx_param == NULL ? NULL : pair_params[0].rx_param->stream;
sink_stream = pair_params[0].tx_param == NULL ? NULL : pair_params[0].tx_param->stream;
UNSET_FLAG(flag_stream_connected);
if (sink_stream != NULL) {
const int err = connect_stream(sink_stream);
if (err != 0) {
FAIL("Unable to connect sink: %d", err);
return;
}
}
if (source_stream != NULL) {
const int err = connect_stream(source_stream);
if (err != 0) {
FAIL("Unable to connect source stream: %d", err);
return;
}
}
WAIT_FOR_FLAG(flag_stream_connected);
}
static int start_stream(struct bt_bap_stream *stream)
{
int err;
@ -776,26 +834,8 @@ static int start_stream(struct bt_bap_stream *stream)
static void start_streams(void)
{
struct bt_bap_stream *source_stream;
struct bt_bap_stream *sink_stream;
/* We only support a single CIS so far, so only start one. We can use the group pair
* params to start both a sink and source stream that use the same CIS
*/
source_stream = pair_params[0].rx_param == NULL ? NULL : pair_params[0].rx_param->stream;
sink_stream = pair_params[0].tx_param == NULL ? NULL : pair_params[0].tx_param->stream;
UNSET_FLAG(flag_stream_connected);
if (sink_stream != NULL) {
const int err = start_stream(sink_stream);
if (err != 0) {
FAIL("Unable to start sink: %d", err);
return;
}
}
if (source_stream != NULL) {
const int err = start_stream(source_stream);
@ -806,8 +846,6 @@ static void start_streams(void)
return;
}
}
WAIT_FOR_FLAG(flag_stream_connected);
}
static void transceive_streams(void)
@ -1051,6 +1089,9 @@ static void test_main(void)
printk("Metadata update streams\n");
metadata_update_streams(stream_cnt);
printk("Connecting streams\n");
connect_streams();
printk("Starting streams\n");
start_streams();
@ -1109,6 +1150,9 @@ static void test_main_acl_disconnect(void)
printk("Metadata update streams\n");
metadata_update_streams(stream_cnt);
printk("Connecting streams\n");
connect_streams();
printk("Starting streams\n");
start_streams();