Skip to content

Commit

Permalink
Bluetooth: CAP: Add support for handling ASE errors
Browse files Browse the repository at this point in the history
If we get an error/rejection from the CAP acceptor when
performing the Unicast Audio Start or Stop procedure then
we need to abort the procedure and let the application determine
what the next step is.

This change triggered a corner case when connecting to multiple
CAP acceptors as the CAP initiatior. This was also fixed as part
of this.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
  • Loading branch information
Thalley authored and carlescufi committed Oct 23, 2024
1 parent 756f5f9 commit 2dc1113
Show file tree
Hide file tree
Showing 8 changed files with 410 additions and 67 deletions.
228 changes: 178 additions & 50 deletions subsys/bluetooth/audio/cap_initiator.c

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions subsys/bluetooth/audio/cap_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ void bt_cap_initiator_disabled(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_stopped(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_released(struct bt_cap_stream *cap_stream);
void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream);
void bt_cap_initiator_cp_cb(struct bt_cap_stream *cap_stream, enum bt_bap_ascs_rsp_code rsp_code,
enum bt_bap_ascs_reason reason);

enum bt_cap_common_proc_state {
BT_CAP_COMMON_PROC_STATE_ACTIVE,
Expand Down Expand Up @@ -88,6 +90,7 @@ struct bt_cap_initiator_proc_param {
bool release;
} stop;
};
bool in_progress;
};

#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
Expand Down
33 changes: 33 additions & 0 deletions subsys/bluetooth/audio/cap_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <zephyr/bluetooth/iso.h>
#include <zephyr/logging/log.h>
#include <zephyr/net_buf.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/check.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/util_macro.h>
Expand Down Expand Up @@ -280,9 +281,41 @@ static struct bt_bap_stream_ops bap_stream_ops = {
.disconnected = cap_stream_disconnected_cb,
};

static void unicast_client_cp_cb(struct bt_bap_stream *bap_stream,
enum bt_bap_ascs_rsp_code rsp_code, enum bt_bap_ascs_reason reason)
{
if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
stream_is_central(bap_stream)) {
struct bt_cap_stream *cap_stream =
CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);

bt_cap_initiator_cp_cb(cap_stream, rsp_code, reason);
}
}

void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream)
{
bt_bap_stream_cb_register(&cap_stream->bap_stream, &bap_stream_ops);

if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT)) {
/* The CAP initiator can use the same callback for all of these as the result is the
* same: Abort current procedure
*/
static struct bt_bap_unicast_client_cb unicast_client_cb = {
.config = unicast_client_cp_cb,
.qos = unicast_client_cp_cb,
.enable = unicast_client_cp_cb,
.start = unicast_client_cp_cb,
.stop = unicast_client_cp_cb,
.disable = unicast_client_cp_cb,
.metadata = unicast_client_cp_cb,
.release = unicast_client_cp_cb,
};
int err;

err = bt_bap_unicast_client_register_cb(&unicast_client_cb);
__ASSERT_NO_MSG(err == 0 || err == -EEXIST);
}
}

void bt_cap_stream_ops_register(struct bt_cap_stream *stream,
Expand Down
3 changes: 2 additions & 1 deletion tests/bluetooth/audio/cap_initiator/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ CONFIG_BT_BAP_UNICAST_CLIENT=y
CONFIG_BT_CSIP_SET_COORDINATOR=y

CONFIG_BT_CAP_INITIATOR=y
CONFIG_BT_CAP_INITIATOR_LOG_LEVEL_DBG=y

# Support setting up a sink and source stream on 2 acceptors
CONFIG_BT_MAX_CONN=2
Expand All @@ -26,3 +25,5 @@ CONFIG_ASSERT_LEVEL=2
CONFIG_ASSERT_VERBOSE=y

CONFIG_BT_BAP_STREAM_LOG_LEVEL_DBG=y
CONFIG_BT_CAP_COMMON_LOG_LEVEL_DBG=y
CONFIG_BT_CAP_INITIATOR_LOG_LEVEL_DBG=y
75 changes: 75 additions & 0 deletions tests/bluetooth/audio/cap_initiator/uut/bap_unicast_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@

#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/bap.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/slist.h>
#include <sys/errno.h>

#include "bap_endpoint.h"
#include "bap_iso.h"
#include "ztest_assert.h"

static struct bt_bap_unicast_client_cb *unicast_client_cb;

bool bt_bap_ep_is_unicast_client(const struct bt_bap_ep *ep)
{
return false;
Expand All @@ -40,6 +44,11 @@ int bt_bap_unicast_client_config(struct bt_bap_stream *stream,
return -EINVAL;
}

if (unicast_client_cb != NULL && unicast_client_cb->config != NULL) {
unicast_client_cb->config(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
}

stream->ep->status.state = BT_BAP_EP_STATE_CODEC_CONFIGURED;

if (stream->ops != NULL && stream->ops->configured != NULL) {
Expand Down Expand Up @@ -73,6 +82,11 @@ int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group

SYS_SLIST_FOR_EACH_CONTAINER(&group->streams, stream, _node) {
if (stream->conn == conn) {
if (unicast_client_cb != NULL && unicast_client_cb->qos != NULL) {
unicast_client_cb->qos(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
}

stream->ep->status.state = BT_BAP_EP_STATE_QOS_CONFIGURED;

if (stream->ops != NULL && stream->ops->qos_set != NULL) {
Expand All @@ -98,6 +112,11 @@ int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, const uint8_t met
return -EINVAL;
}

if (unicast_client_cb != NULL && unicast_client_cb->enable != NULL) {
unicast_client_cb->enable(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
}

stream->ep->status.state = BT_BAP_EP_STATE_ENABLING;

if (stream->ops != NULL && stream->ops->enabled != NULL) {
Expand All @@ -122,6 +141,11 @@ int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, const uint8_t m
return -EINVAL;
}

if (unicast_client_cb != NULL && unicast_client_cb->metadata != NULL) {
unicast_client_cb->metadata(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
}

if (stream->ops != NULL && stream->ops->metadata_updated != NULL) {
stream->ops->metadata_updated(stream);
}
Expand Down Expand Up @@ -173,6 +197,11 @@ int bt_bap_unicast_client_start(struct bt_bap_stream *stream)
return -EINVAL;
}

if (unicast_client_cb != NULL && unicast_client_cb->start != NULL) {
unicast_client_cb->start(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
}

stream->ep->status.state = BT_BAP_EP_STATE_STREAMING;

if (stream->ops != NULL && stream->ops->started != NULL) {
Expand Down Expand Up @@ -203,6 +232,11 @@ int bt_bap_unicast_client_disable(struct bt_bap_stream *stream)
* when leaving the streaming state in a non-release manner
*/

if (unicast_client_cb != NULL && unicast_client_cb->disable != NULL) {
unicast_client_cb->disable(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
}

/* Disabled sink ASEs go directly to the QoS configured state */
if (stream->ep->dir == BT_AUDIO_DIR_SINK) {
stream->ep->status.state = BT_BAP_EP_STATE_QOS_CONFIGURED;
Expand Down Expand Up @@ -245,6 +279,11 @@ int bt_bap_unicast_client_stop(struct bt_bap_stream *stream)
return -EINVAL;
}

if (unicast_client_cb != NULL && unicast_client_cb->stop != NULL) {
unicast_client_cb->stop(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
}

stream->ep->status.state = BT_BAP_EP_STATE_QOS_CONFIGURED;

if (stream->ops != NULL && stream->ops->stopped != NULL) {
Expand All @@ -255,6 +294,30 @@ int bt_bap_unicast_client_stop(struct bt_bap_stream *stream)
stream->ops->qos_set(stream);
}

/* If the stream can be disconnected, BAP will disconnect the stream once it reaches the
* QoS Configured state. We simulator that behavior here, and if the stream is disconnected,
* then the Unicast Server will set any paired stream to the QoS Configured state
* autonomously as well.
*/
if (bt_bap_stream_can_disconnect(stream)) {
struct bt_bap_ep *pair_ep = bt_bap_iso_get_paired_ep(stream->ep);

if (pair_ep != NULL && pair_ep->stream != NULL) {
struct bt_bap_stream *pair_stream = pair_ep->stream;

pair_stream->ep->status.state = BT_BAP_EP_STATE_QOS_CONFIGURED;

if (pair_stream->ops != NULL && pair_stream->ops->stopped != NULL) {
pair_stream->ops->stopped(pair_stream,
BT_HCI_ERR_LOCALHOST_TERM_CONN);
}

if (pair_stream->ops != NULL && pair_stream->ops->qos_set != NULL) {
pair_stream->ops->qos_set(pair_stream);
}
}
}

return 0;
}

Expand All @@ -277,6 +340,11 @@ int bt_bap_unicast_client_release(struct bt_bap_stream *stream)
return -EINVAL;
}

if (unicast_client_cb != NULL && unicast_client_cb->release != NULL) {
unicast_client_cb->release(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
}

stream->ep->status.state = BT_BAP_EP_STATE_IDLE;
bt_bap_stream_reset(stream);

Expand All @@ -286,3 +354,10 @@ int bt_bap_unicast_client_release(struct bt_bap_stream *stream)

return 0;
}

int bt_bap_unicast_client_register_cb(struct bt_bap_unicast_client_cb *cb)
{
unicast_client_cb = cb;

return 0;
}
28 changes: 14 additions & 14 deletions tests/bsim/bluetooth/audio/src/cap_acceptor_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,12 +503,25 @@ static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_bap_
return 0;
}

static bool ascs_data_func_cb(struct bt_data *data, void *user_data)
{
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;

if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
return false;
}

return true;
}

static int unicast_server_enable(struct bt_bap_stream *stream, const uint8_t meta[],
size_t meta_len, struct bt_bap_ascs_rsp *rsp)
{
printk("Enable: stream %p meta_len %zu\n", stream, meta_len);

return 0;
return bt_audio_data_parse(meta, meta_len, ascs_data_func_cb, rsp);
}

static int unicast_server_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
Expand All @@ -518,19 +531,6 @@ static int unicast_server_start(struct bt_bap_stream *stream, struct bt_bap_ascs
return 0;
}

static bool ascs_data_func_cb(struct bt_data *data, void *user_data)
{
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;

if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
return false;
}

return true;
}

static int unicast_server_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
size_t meta_len, struct bt_bap_ascs_rsp *rsp)
{
Expand Down
Loading

0 comments on commit 2dc1113

Please sign in to comment.