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:
parent
5b0cc42968
commit
d2fbeffaa9
17 changed files with 969 additions and 231 deletions
|
@ -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__);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue