tests: Bluetooth: CAP: Ensure that unicast_start works in any state

The unicast_start procedure should take a stream in any state
and put it in the streaming state. Adds tests with streams
in various states.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2024-06-07 12:41:58 +02:00 committed by Carles Cufí
commit 4279cebcbd
4 changed files with 211 additions and 4 deletions

View file

@ -6,7 +6,16 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/audio/bap.h>
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
#include <zephyr/bluetooth/audio/cap.h>
#include <zephyr/bluetooth/conn.h>
void test_mocks_init(void);
void test_mocks_cleanup(void);
void test_conn_init(struct bt_conn *conn);
void test_unicast_set_state(struct bt_cap_stream *cap_stream, struct bt_conn *conn,
struct bt_bap_ep *ep, struct bt_bap_lc3_preset *preset,
enum bt_bap_ep_state state);

View file

@ -6,12 +6,17 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/audio/bap.h>
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
#include <zephyr/bluetooth/audio/cap.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/hci_types.h>
#include "bap_endpoint.h"
#include "cap_initiator.h"
#include "conn.h"
#include "test_common.h"
#include "ztest_assert.h"
void test_mocks_init(void)
{
@ -33,3 +38,27 @@ void test_conn_init(struct bt_conn *conn)
conn->info.security.enc_key_size = BT_ENC_KEY_SIZE_MAX;
conn->info.security.flags = BT_SECURITY_FLAG_OOB | BT_SECURITY_FLAG_SC;
}
void test_unicast_set_state(struct bt_cap_stream *cap_stream, struct bt_conn *conn,
struct bt_bap_ep *ep, struct bt_bap_lc3_preset *preset,
enum bt_bap_ep_state state)
{
struct bt_bap_stream *bap_stream = &cap_stream->bap_stream;
printk("Setting stream %p to state %d\n", bap_stream, state);
if (state == BT_BAP_EP_STATE_IDLE) {
return;
}
zassert_not_null(cap_stream);
zassert_not_null(conn);
zassert_not_null(ep);
zassert_not_null(preset);
bap_stream->conn = conn;
bap_stream->ep = ep;
bap_stream->qos = &preset->qos;
bap_stream->codec_cfg = &preset->codec_cfg;
bap_stream->ep->status.state = state;
}

View file

@ -92,6 +92,9 @@ static void cap_initiator_test_unicast_start_after(void *f)
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
mock_bt_conn_disconnected(&fixture->conns[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
}
/* In the case of a test failing, we cancel the procedure so that subsequent won't fail */
bt_cap_initiator_unicast_audio_cancel();
}
static void cap_initiator_test_unicast_start_teardown(void *f)
@ -117,6 +120,7 @@ static ZTEST_F(cap_initiator_test_unicast_start, test_initiator_unicast_start)
for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) {
stream_params[i].stream = &fixture->cap_streams[i];
stream_params[i].codec_cfg = &fixture->preset.codec_cfg;
/* Distribute the streams equally among the connections */
stream_params[i].member.member = &fixture->conns[i % ARRAY_SIZE(fixture->conns)];
stream_params[i].ep = &fixture->eps[i];
}
@ -128,11 +132,11 @@ static ZTEST_F(cap_initiator_test_unicast_start, test_initiator_unicast_start)
mock_cap_initiator_unicast_start_complete_cb_fake.call_count);
for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) {
const enum bt_bap_ep_state state =
fixture->cap_streams[i].bap_stream.ep->status.state;
const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
const enum bt_bap_ep_state state = bap_stream->ep->status.state;
zassert_equal(state, BT_BAP_EP_STATE_STREAMING, "[%zu] Unexpected state: %d", i,
state);
zassert_equal(state, BT_BAP_EP_STATE_STREAMING,
"[%zu]: Stream %p unexpected state: %d", i, bap_stream, state);
}
}
@ -384,3 +388,115 @@ static ZTEST_F(cap_initiator_test_unicast_start,
zexpect_call_count("bt_cap_initiator_cb.unicast_start_complete_cb", 0,
mock_cap_initiator_unicast_start_complete_cb_fake.call_count);
}
static ZTEST_F(cap_initiator_test_unicast_start,
test_initiator_unicast_start_state_codec_configured)
{
struct bt_cap_unicast_audio_start_stream_param
stream_params[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
const struct bt_cap_unicast_audio_start_param param = {
.type = BT_CAP_SET_TYPE_AD_HOC,
.count = ARRAY_SIZE(stream_params),
.stream_params = stream_params,
};
int err;
for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) {
stream_params[i].stream = &fixture->cap_streams[i];
stream_params[i].codec_cfg = &fixture->preset.codec_cfg;
stream_params[i].member.member = &fixture->conns[i % ARRAY_SIZE(fixture->conns)];
stream_params[i].ep = &fixture->eps[i];
test_unicast_set_state(stream_params[i].stream, stream_params[i].member.member,
stream_params[i].ep, &fixture->preset,
BT_BAP_EP_STATE_CODEC_CONFIGURED);
}
err = bt_cap_initiator_unicast_audio_start(&param);
zassert_equal(err, 0, "Unexpected return value %d", err);
zexpect_call_count("bt_cap_initiator_cb.unicast_start_complete_cb", 1,
mock_cap_initiator_unicast_start_complete_cb_fake.call_count);
for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) {
const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
const enum bt_bap_ep_state state = bap_stream->ep->status.state;
zassert_equal(state, BT_BAP_EP_STATE_STREAMING,
"[%zu]: Stream %p unexpected state: %d", i, bap_stream, state);
}
}
static ZTEST_F(cap_initiator_test_unicast_start, test_initiator_unicast_start_state_qos_configured)
{
struct bt_cap_unicast_audio_start_stream_param
stream_params[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
const struct bt_cap_unicast_audio_start_param param = {
.type = BT_CAP_SET_TYPE_AD_HOC,
.count = ARRAY_SIZE(stream_params),
.stream_params = stream_params,
};
int err;
for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) {
stream_params[i].stream = &fixture->cap_streams[i];
stream_params[i].codec_cfg = &fixture->preset.codec_cfg;
stream_params[i].member.member = &fixture->conns[i % ARRAY_SIZE(fixture->conns)];
stream_params[i].ep = &fixture->eps[i];
test_unicast_set_state(stream_params[i].stream, stream_params[i].member.member,
stream_params[i].ep, &fixture->preset,
BT_BAP_EP_STATE_QOS_CONFIGURED);
}
err = bt_cap_initiator_unicast_audio_start(&param);
zassert_equal(err, 0, "Unexpected return value %d", err);
zexpect_call_count("bt_cap_initiator_cb.unicast_start_complete_cb", 1,
mock_cap_initiator_unicast_start_complete_cb_fake.call_count);
for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) {
const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
const enum bt_bap_ep_state state = bap_stream->ep->status.state;
zassert_equal(state, BT_BAP_EP_STATE_STREAMING,
"[%zu]: Stream %p unexpected state: %d", i, bap_stream, state);
}
}
static ZTEST_F(cap_initiator_test_unicast_start, test_initiator_unicast_start_state_enabling)
{
struct bt_cap_unicast_audio_start_stream_param
stream_params[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0};
const struct bt_cap_unicast_audio_start_param param = {
.type = BT_CAP_SET_TYPE_AD_HOC,
.count = ARRAY_SIZE(stream_params),
.stream_params = stream_params,
};
int err;
for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) {
stream_params[i].stream = &fixture->cap_streams[i];
stream_params[i].codec_cfg = &fixture->preset.codec_cfg;
stream_params[i].member.member = &fixture->conns[i % ARRAY_SIZE(fixture->conns)];
stream_params[i].ep = &fixture->eps[i];
test_unicast_set_state(stream_params[i].stream, stream_params[i].member.member,
stream_params[i].ep, &fixture->preset,
BT_BAP_EP_STATE_ENABLING);
}
err = bt_cap_initiator_unicast_audio_start(&param);
zassert_equal(err, 0, "Unexpected return value %d", err);
zexpect_call_count("bt_cap_initiator_cb.unicast_start_complete_cb", 1,
mock_cap_initiator_unicast_start_complete_cb_fake.call_count);
for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) {
const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream;
const enum bt_bap_ep_state state = bap_stream->ep->status.state;
zassert_equal(state, BT_BAP_EP_STATE_STREAMING,
"[%zu]: Stream %p unexpected state: %d", i, bap_stream, state);
}
}

View file

@ -12,7 +12,9 @@
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/bap.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/slist.h>
#include <sys/errno.h>
#include "bap_endpoint.h"
#include "ztest_assert.h"
@ -29,6 +31,14 @@ int bt_bap_unicast_client_config(struct bt_bap_stream *stream,
return -EINVAL;
}
switch (stream->ep->status.state) {
case BT_BAP_EP_STATE_IDLE:
case BT_BAP_EP_STATE_CODEC_CONFIGURED:
break;
default:
return -EINVAL;
}
stream->ep->status.state = BT_BAP_EP_STATE_CODEC_CONFIGURED;
if (stream->ops != NULL && stream->ops->configured != NULL) {
@ -48,6 +58,18 @@ int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group
return -EINVAL;
}
SYS_SLIST_FOR_EACH_CONTAINER(&group->streams, stream, _node) {
if (stream->conn == conn) {
switch (stream->ep->status.state) {
case BT_BAP_EP_STATE_CODEC_CONFIGURED:
case BT_BAP_EP_STATE_QOS_CONFIGURED:
break;
default:
return -EINVAL;
}
}
}
SYS_SLIST_FOR_EACH_CONTAINER(&group->streams, stream, _node) {
if (stream->conn == conn) {
stream->ep->status.state = BT_BAP_EP_STATE_QOS_CONFIGURED;
@ -68,6 +90,13 @@ int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, const uint8_t met
return -EINVAL;
}
switch (stream->ep->status.state) {
case BT_BAP_EP_STATE_QOS_CONFIGURED:
break;
default:
return -EINVAL;
}
stream->ep->status.state = BT_BAP_EP_STATE_ENABLING;
if (stream->ops != NULL && stream->ops->enabled != NULL) {
@ -84,6 +113,14 @@ int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, const uint8_t m
return -EINVAL;
}
switch (stream->ep->status.state) {
case BT_BAP_EP_STATE_ENABLING:
case BT_BAP_EP_STATE_STREAMING:
break;
default:
return -EINVAL;
}
if (stream->ops != NULL && stream->ops->metadata_updated != NULL) {
stream->ops->metadata_updated(stream);
}
@ -97,6 +134,14 @@ int bt_bap_unicast_client_connect(struct bt_bap_stream *stream)
return -EINVAL;
}
switch (stream->ep->status.state) {
case BT_BAP_EP_STATE_QOS_CONFIGURED:
case BT_BAP_EP_STATE_ENABLING:
break;
default:
return -EINVAL;
}
if (stream->ops != NULL && stream->ops->connected != NULL) {
stream->ops->connected(stream);
}
@ -104,6 +149,7 @@ int bt_bap_unicast_client_connect(struct bt_bap_stream *stream)
if (stream->ep != NULL && stream->ep->dir == BT_AUDIO_DIR_SINK) {
/* Mocking that the unicast server automatically starts the stream */
stream->ep->status.state = BT_BAP_EP_STATE_STREAMING;
printk("A %s %p\n", __func__, stream);
if (stream->ops != NULL && stream->ops->started != NULL) {
stream->ops->started(stream);
@ -120,6 +166,13 @@ int bt_bap_unicast_client_start(struct bt_bap_stream *stream)
return -EINVAL;
}
switch (stream->ep->status.state) {
case BT_BAP_EP_STATE_ENABLING:
break;
default:
return -EINVAL;
}
stream->ep->status.state = BT_BAP_EP_STATE_STREAMING;
if (stream->ops != NULL && stream->ops->started != NULL) {