tests: Bluetooth: Split CAP initiator tests to unicast and broadcast
Split the cap_initiator_test.c to two new files cap_initiator_broadcast_test.c and cap_initiator_unicast_test.c as the two barely had any common functionality, and the file was getting too large. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
a8ed28ab6f
commit
8eaeb73753
4 changed files with 1267 additions and 1238 deletions
585
tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c
Normal file
585
tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c
Normal file
|
@ -0,0 +1,585 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/byteorder.h>
|
||||
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
|
||||
#include <zephyr/bluetooth/audio/cap.h>
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include "common.h"
|
||||
|
||||
#define BROADCAST_STREMT_CNT CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT
|
||||
#define BROADCAST_ENQUEUE_COUNT 2U
|
||||
#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * BROADCAST_STREMT_CNT)
|
||||
|
||||
BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED,
|
||||
"CONFIG_BT_ISO_TX_BUF_COUNT should be at least "
|
||||
"BROADCAST_ENQUEUE_COUNT * BROADCAST_STREMT_CNT");
|
||||
|
||||
NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
|
||||
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
static struct bt_cap_stream broadcast_source_streams[BROADCAST_STREMT_CNT];
|
||||
static struct bt_cap_stream *broadcast_streams[ARRAY_SIZE(broadcast_source_streams)];
|
||||
static struct bt_bap_lc3_preset broadcast_preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA);
|
||||
|
||||
static K_SEM_DEFINE(sem_broadcast_started, 0U, ARRAY_SIZE(broadcast_streams));
|
||||
static K_SEM_DEFINE(sem_broadcast_stopped, 0U, ARRAY_SIZE(broadcast_streams));
|
||||
|
||||
CREATE_FLAG(flag_broadcast_stopping);
|
||||
|
||||
static void broadcast_started_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Stream %p started\n", stream);
|
||||
k_sem_give(&sem_broadcast_started);
|
||||
}
|
||||
|
||||
static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
|
||||
k_sem_give(&sem_broadcast_stopped);
|
||||
}
|
||||
|
||||
static void broadcast_sent_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU];
|
||||
static bool mock_data_initialized;
|
||||
static uint32_t seq_num;
|
||||
struct net_buf *buf;
|
||||
int ret;
|
||||
|
||||
if (broadcast_preset_16_2_1.qos.sdu > CONFIG_BT_ISO_TX_MTU) {
|
||||
FAIL("Invalid SDU %u for the MTU: %d", broadcast_preset_16_2_1.qos.sdu,
|
||||
CONFIG_BT_ISO_TX_MTU);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TEST_FLAG(flag_broadcast_stopping)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mock_data_initialized) {
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) {
|
||||
/* Initialize mock data */
|
||||
mock_data[i] = (uint8_t)i;
|
||||
}
|
||||
mock_data_initialized = true;
|
||||
}
|
||||
|
||||
buf = net_buf_alloc(&tx_pool, K_FOREVER);
|
||||
if (buf == NULL) {
|
||||
printk("Could not allocate buffer when sending on %p\n", stream);
|
||||
return;
|
||||
}
|
||||
|
||||
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
|
||||
net_buf_add_mem(buf, mock_data, broadcast_preset_16_2_1.qos.sdu);
|
||||
ret = bt_bap_stream_send(stream, buf, seq_num++, BT_ISO_TIMESTAMP_NONE);
|
||||
if (ret < 0) {
|
||||
/* This will end broadcasting on this stream. */
|
||||
printk("Unable to broadcast data on %p: %d\n", stream, ret);
|
||||
net_buf_unref(buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_bap_stream_ops broadcast_stream_ops = {
|
||||
.started = broadcast_started_cb,
|
||||
.stopped = broadcast_stopped_cb,
|
||||
.sent = broadcast_sent_cb,
|
||||
};
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
(void)memset(broadcast_source_streams, 0, sizeof(broadcast_source_streams));
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
broadcast_streams[i] = &broadcast_source_streams[i];
|
||||
bt_cap_stream_ops_register(broadcast_streams[i], &broadcast_stream_ops);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_extended_adv(struct bt_le_ext_adv **adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Create a non-connectable non-scannable advertising set */
|
||||
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to create extended advertising set: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set periodic advertising parameters */
|
||||
err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT);
|
||||
if (err) {
|
||||
FAIL("Failed to set periodic advertising parameters: %d\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_extended_adv_data(struct bt_cap_broadcast_source *source,
|
||||
struct bt_le_ext_adv *adv)
|
||||
{
|
||||
/* Broadcast Audio Streaming Endpoint advertising data */
|
||||
NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE(base_buf, 128);
|
||||
struct bt_data ext_ad;
|
||||
struct bt_data per_ad;
|
||||
uint32_t broadcast_id;
|
||||
int err;
|
||||
|
||||
err = bt_cap_initiator_broadcast_get_id(source, &broadcast_id);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to get broadcast ID: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup extended advertising data */
|
||||
net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL);
|
||||
net_buf_simple_add_le24(&ad_buf, broadcast_id);
|
||||
ext_ad.type = BT_DATA_SVC_DATA16;
|
||||
ext_ad.data_len = ad_buf.len + sizeof(ext_ad.type);
|
||||
ext_ad.data = ad_buf.data;
|
||||
err = bt_le_ext_adv_set_data(adv, &ext_ad, 1, NULL, 0);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to set extended advertising data: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup periodic advertising data */
|
||||
err = bt_cap_initiator_broadcast_get_base(source, &base_buf);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to get encoded BASE: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
per_ad.type = BT_DATA_SVC_DATA16;
|
||||
per_ad.data_len = base_buf.len;
|
||||
per_ad.data = base_buf.data;
|
||||
err = bt_le_per_adv_set_data(adv, &per_ad, 1);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to set periodic advertising data: %d\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void start_extended_adv(struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Start extended advertising */
|
||||
err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
|
||||
if (err) {
|
||||
FAIL("Failed to start extended advertising: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable Periodic Advertising */
|
||||
err = bt_le_per_adv_start(adv);
|
||||
if (err) {
|
||||
FAIL("Failed to enable periodic advertising: %d\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void stop_and_delete_extended_adv(struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Stop extended advertising */
|
||||
err = bt_le_per_adv_stop(adv);
|
||||
if (err) {
|
||||
FAIL("Failed to stop periodic advertising: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_ext_adv_stop(adv);
|
||||
if (err) {
|
||||
FAIL("Failed to stop extended advertising: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_ext_adv_delete(adv);
|
||||
if (err) {
|
||||
FAIL("Failed to delete extended advertising: %d\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_create_inval(void)
|
||||
{
|
||||
struct bt_codec_data bis_codec_data =
|
||||
BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, BT_CODEC_CONFIG_LC3_FREQ_16KHZ);
|
||||
struct bt_cap_initiator_broadcast_stream_param
|
||||
stream_params[ARRAY_SIZE(broadcast_source_streams)];
|
||||
struct bt_cap_initiator_broadcast_subgroup_param subgroup_param;
|
||||
struct bt_cap_initiator_broadcast_create_param create_param;
|
||||
struct bt_cap_broadcast_source *broadcast_source;
|
||||
struct bt_codec invalid_codec =
|
||||
BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA);
|
||||
int err;
|
||||
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
stream_params[i].stream = &broadcast_source_streams[i];
|
||||
stream_params[i].data_count = 1U;
|
||||
stream_params[i].data = &bis_codec_data;
|
||||
}
|
||||
|
||||
subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams);
|
||||
subgroup_param.stream_params = stream_params;
|
||||
subgroup_param.codec = &broadcast_preset_16_2_1.codec;
|
||||
|
||||
create_param.subgroup_count = 1U;
|
||||
create_param.subgroup_params = &subgroup_param;
|
||||
create_param.qos = &broadcast_preset_16_2_1.qos;
|
||||
create_param.packing = BT_ISO_PACKING_SEQUENTIAL;
|
||||
create_param.encryption = false;
|
||||
|
||||
/* Test NULL parameters */
|
||||
err = bt_cap_initiator_broadcast_audio_create(NULL, &broadcast_source);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_create with NULL param did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_create(&create_param, NULL);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_create with NULL broadcast source did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear metadata so that it does not contain the mandatory stream context */
|
||||
memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta));
|
||||
subgroup_param.codec = &invalid_codec;
|
||||
err = bt_cap_initiator_broadcast_audio_create(&create_param, NULL);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_create with invalid metadata did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Since we are just casting the CAP parameters to BAP parameters,
|
||||
* we can rely on the BAP tests to verify the values
|
||||
*/
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadcast_source)
|
||||
{
|
||||
struct bt_codec_data bis_codec_data =
|
||||
BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, BT_CODEC_CONFIG_LC3_FREQ_16KHZ);
|
||||
struct bt_cap_initiator_broadcast_stream_param
|
||||
stream_params[ARRAY_SIZE(broadcast_source_streams)];
|
||||
struct bt_cap_initiator_broadcast_subgroup_param subgroup_param;
|
||||
struct bt_cap_initiator_broadcast_create_param create_param;
|
||||
int err;
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
stream_params[i].stream = &broadcast_source_streams[i];
|
||||
stream_params[i].data_count = 1U;
|
||||
stream_params[i].data = &bis_codec_data;
|
||||
}
|
||||
|
||||
subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams);
|
||||
subgroup_param.stream_params = stream_params;
|
||||
subgroup_param.codec = &broadcast_preset_16_2_1.codec;
|
||||
|
||||
create_param.subgroup_count = 1U;
|
||||
create_param.subgroup_params = &subgroup_param;
|
||||
create_param.qos = &broadcast_preset_16_2_1.qos;
|
||||
create_param.packing = BT_ISO_PACKING_SEQUENTIAL;
|
||||
create_param.encryption = false;
|
||||
|
||||
printk("Creating broadcast source with %zu broadcast_streams\n",
|
||||
ARRAY_SIZE(broadcast_streams));
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_create(&create_param, broadcast_source);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to start broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Broadcast source created with %zu broadcast_streams\n",
|
||||
ARRAY_SIZE(broadcast_streams));
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_start_inval(struct bt_cap_broadcast_source *broadcast_source,
|
||||
struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Test NULL parameters */
|
||||
err = bt_cap_initiator_broadcast_audio_start(NULL, adv);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_start with NULL broadcast source did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_start(broadcast_source, NULL);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_start with NULL adv did not fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_start(struct bt_cap_broadcast_source *broadcast_source,
|
||||
struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_start(broadcast_source, adv);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to start broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Broadcast source created with %zu broadcast_streams\n",
|
||||
ARRAY_SIZE(broadcast_streams));
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *broadcast_source)
|
||||
{
|
||||
const uint16_t mock_ccid = 0x1234;
|
||||
const struct bt_codec_data new_metadata[] = {
|
||||
BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)),
|
||||
BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU),
|
||||
((mock_ccid >> 8) & 0xFFU)),
|
||||
};
|
||||
const struct bt_codec_data invalid_metadata[] = {
|
||||
BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU),
|
||||
((mock_ccid >> 8) & 0xFFU)),
|
||||
};
|
||||
int err;
|
||||
|
||||
/* Test NULL parameters */
|
||||
err = bt_cap_initiator_broadcast_audio_update(NULL, new_metadata, ARRAY_SIZE(new_metadata));
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_update with NULL broadcast source did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_update(broadcast_source, NULL,
|
||||
ARRAY_SIZE(new_metadata));
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_update with NULL metadata did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_update(broadcast_source, new_metadata, 0);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_update with 0 metadata count did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test with metadata without streaming context */
|
||||
err = bt_cap_initiator_broadcast_audio_update(broadcast_source, invalid_metadata,
|
||||
ARRAY_SIZE(invalid_metadata));
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_update with invalid metadata did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Broadcast metadata updated\n");
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source)
|
||||
{
|
||||
const uint16_t mock_ccid = 0x1234;
|
||||
const struct bt_codec_data new_metadata[] = {
|
||||
BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
|
||||
BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, BT_BYTES_LIST_LE16(mock_ccid)),
|
||||
};
|
||||
int err;
|
||||
|
||||
printk("Updating broadcast metadata\n");
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_update(broadcast_source, new_metadata,
|
||||
ARRAY_SIZE(new_metadata));
|
||||
if (err != 0) {
|
||||
FAIL("Failed to update broadcast source metadata: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Broadcast metadata updated\n");
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_stop_inval(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Test NULL parameters */
|
||||
err = bt_cap_initiator_broadcast_audio_stop(NULL);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_stop with NULL broadcast source did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Stopping broadcast metadata\n");
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_stop(broadcast_source);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to stop broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for all to be stopped */
|
||||
printk("Waiting for broadcast_streams to be stopped\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
k_sem_take(&sem_broadcast_stopped, K_FOREVER);
|
||||
}
|
||||
|
||||
printk("Broadcast metadata stopped\n");
|
||||
|
||||
/* Verify that it cannot be stopped twice */
|
||||
err = bt_cap_initiator_broadcast_audio_stop(broadcast_source);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_stop with already-stopped broadcast source "
|
||||
"did not fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_delete_inval(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Test NULL parameters */
|
||||
err = bt_cap_initiator_broadcast_audio_delete(NULL);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_delete with NULL broadcast source did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_broadcast_audio_delete(struct bt_cap_broadcast_source *broadcast_source)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Stopping broadcast metadata\n");
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_delete(broadcast_source);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to stop broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Broadcast metadata stopped\n");
|
||||
|
||||
/* Verify that it cannot be deleted twice */
|
||||
err = bt_cap_initiator_broadcast_audio_delete(broadcast_source);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_broadcast_audio_delete with already-deleted broadcast "
|
||||
"source did not fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_main_cap_initiator_broadcast(void)
|
||||
{
|
||||
struct bt_cap_broadcast_source *broadcast_source;
|
||||
struct bt_le_ext_adv *adv;
|
||||
|
||||
(void)memset(broadcast_source_streams, 0, sizeof(broadcast_source_streams));
|
||||
|
||||
init();
|
||||
|
||||
setup_extended_adv(&adv);
|
||||
|
||||
test_broadcast_audio_create_inval();
|
||||
test_broadcast_audio_create(&broadcast_source);
|
||||
|
||||
test_broadcast_audio_start_inval(broadcast_source, adv);
|
||||
test_broadcast_audio_start(broadcast_source, adv);
|
||||
|
||||
setup_extended_adv_data(broadcast_source, adv);
|
||||
|
||||
start_extended_adv(adv);
|
||||
|
||||
/* Wait for all to be started */
|
||||
printk("Waiting for broadcast_streams to be started\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
k_sem_take(&sem_broadcast_started, K_FOREVER);
|
||||
}
|
||||
|
||||
/* Initialize sending */
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) {
|
||||
broadcast_sent_cb(&broadcast_streams[i]->bap_stream);
|
||||
}
|
||||
}
|
||||
|
||||
/* Keeping running for a little while */
|
||||
k_sleep(K_SECONDS(5));
|
||||
|
||||
test_broadcast_audio_update_inval(broadcast_source);
|
||||
test_broadcast_audio_update(broadcast_source);
|
||||
|
||||
/* Keeping running for a little while */
|
||||
k_sleep(K_SECONDS(5));
|
||||
|
||||
test_broadcast_audio_stop_inval();
|
||||
test_broadcast_audio_stop(broadcast_source);
|
||||
|
||||
test_broadcast_audio_delete_inval();
|
||||
test_broadcast_audio_delete(broadcast_source);
|
||||
broadcast_source = NULL;
|
||||
|
||||
stop_and_delete_extended_adv(adv);
|
||||
adv = NULL;
|
||||
|
||||
PASS("CAP initiator broadcast passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_cap_initiator_broadcast[] = {
|
||||
{
|
||||
.test_id = "cap_initiator_broadcast",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main_cap_initiator_broadcast,
|
||||
},
|
||||
BSTEST_END_MARKER,
|
||||
};
|
||||
|
||||
struct bst_test_list *test_cap_initiator_broadcast_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_cap_initiator_broadcast);
|
||||
}
|
||||
|
||||
#else /* !(defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_BROADCAST_SOURCE)) */
|
||||
|
||||
struct bst_test_list *test_cap_initiator_broadcast_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_BROADCAST_SOURCE) */
|
File diff suppressed because it is too large
Load diff
677
tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c
Normal file
677
tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c
Normal file
|
@ -0,0 +1,677 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_UNICAST_CLIENT)
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/byteorder.h>
|
||||
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
|
||||
#include <zephyr/bluetooth/audio/cap.h>
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include "common.h"
|
||||
#include "bap_unicast_common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
static struct bt_bap_lc3_preset unicast_preset_16_2_1 = BT_BAP_LC3_UNICAST_PRESET_16_2_1(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
|
||||
|
||||
static struct bt_cap_stream unicast_client_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
|
||||
static struct bt_bap_ep *unicast_sink_eps[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
|
||||
|
||||
CREATE_FLAG(flag_discovered);
|
||||
CREATE_FLAG(flag_codec_found);
|
||||
CREATE_FLAG(flag_endpoint_found);
|
||||
CREATE_FLAG(flag_started);
|
||||
CREATE_FLAG(flag_updated);
|
||||
CREATE_FLAG(flag_stopped);
|
||||
CREATE_FLAG(flag_mtu_exchanged);
|
||||
CREATE_FLAG(flag_sink_discovered);
|
||||
|
||||
static void unicast_stream_configured(struct bt_bap_stream *stream,
|
||||
const struct bt_codec_qos_pref *pref)
|
||||
{
|
||||
printk("Configured stream %p\n", stream);
|
||||
|
||||
/* TODO: The preference should be used/taken into account when
|
||||
* setting the QoS
|
||||
*/
|
||||
}
|
||||
|
||||
static void unicast_stream_qos_set(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("QoS set stream %p\n", stream);
|
||||
}
|
||||
|
||||
static void unicast_stream_enabled(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Enabled stream %p\n", stream);
|
||||
}
|
||||
|
||||
static void unicast_stream_started(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Started stream %p\n", stream);
|
||||
}
|
||||
|
||||
static void unicast_stream_metadata_updated(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Metadata updated stream %p\n", stream);
|
||||
}
|
||||
|
||||
static void unicast_stream_disabled(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Disabled stream %p\n", stream);
|
||||
}
|
||||
|
||||
static void unicast_stream_stopped(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Stopped stream with reason 0x%02X%p\n", stream, reason);
|
||||
}
|
||||
|
||||
static void unicast_stream_released(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Released stream %p\n", stream);
|
||||
}
|
||||
|
||||
static struct bt_bap_stream_ops unicast_stream_ops = {
|
||||
.configured = unicast_stream_configured,
|
||||
.qos_set = unicast_stream_qos_set,
|
||||
.enabled = unicast_stream_enabled,
|
||||
.started = unicast_stream_started,
|
||||
.metadata_updated = unicast_stream_metadata_updated,
|
||||
.disabled = unicast_stream_disabled,
|
||||
.stopped = unicast_stream_stopped,
|
||||
.released = unicast_stream_released,
|
||||
};
|
||||
|
||||
static void cap_discovery_complete_cb(struct bt_conn *conn, int err,
|
||||
const struct bt_csip_set_coordinator_csis_inst *csis_inst)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Failed to discover CAS: %d", err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) {
|
||||
if (csis_inst == NULL) {
|
||||
FAIL("Failed to discover CAS CSIS");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Found CAS with CSIS %p\n", csis_inst);
|
||||
} else {
|
||||
printk("Found CAS\n");
|
||||
}
|
||||
|
||||
SET_FLAG(flag_discovered);
|
||||
}
|
||||
|
||||
static void unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_group, int err,
|
||||
struct bt_conn *conn)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Failed to start (failing conn %p): %d", conn, err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SET_FLAG(flag_started);
|
||||
}
|
||||
|
||||
static void unicast_update_complete_cb(int err, struct bt_conn *conn)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Failed to update (failing conn %p): %d", conn, err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SET_FLAG(flag_updated);
|
||||
}
|
||||
|
||||
static void unicast_stop_complete_cb(struct bt_bap_unicast_group *unicast_group, int err,
|
||||
struct bt_conn *conn)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Failed to stop (failing conn %p): %d", conn, err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SET_FLAG(flag_stopped);
|
||||
}
|
||||
|
||||
static struct bt_cap_initiator_cb cap_cb = {
|
||||
.unicast_discovery_complete = cap_discovery_complete_cb,
|
||||
.unicast_start_complete = unicast_start_complete_cb,
|
||||
.unicast_update_complete = unicast_update_complete_cb,
|
||||
.unicast_stop_complete = unicast_stop_complete_cb,
|
||||
};
|
||||
|
||||
static void add_remote_sink(struct bt_bap_ep *ep)
|
||||
{
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(unicast_sink_eps); i++) {
|
||||
if (unicast_sink_eps[i] == NULL) {
|
||||
printk("Sink #%zu: ep %p\n", i, ep);
|
||||
unicast_sink_eps[i] = ep;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FAIL("Could not add source ep\n");
|
||||
}
|
||||
|
||||
static void print_remote_codec(const struct bt_codec *codec, enum bt_audio_dir dir)
|
||||
{
|
||||
printk("codec %p dir 0x%02x\n", codec, dir);
|
||||
|
||||
print_codec(codec);
|
||||
}
|
||||
|
||||
static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, const struct bt_codec *codec)
|
||||
{
|
||||
print_remote_codec(codec, dir);
|
||||
SET_FLAG(flag_codec_found);
|
||||
}
|
||||
|
||||
static void discover_sink_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Discovery failed: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Sink discover complete\n");
|
||||
|
||||
SET_FLAG(flag_sink_discovered);
|
||||
}
|
||||
|
||||
static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep)
|
||||
{
|
||||
if (dir == BT_AUDIO_DIR_SINK) {
|
||||
add_remote_sink(ep);
|
||||
SET_FLAG(flag_endpoint_found);
|
||||
} else {
|
||||
FAIL("Invalid param dir: %u\n", dir);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct bt_bap_unicast_client_cb unicast_client_cbs = {
|
||||
.discover = discover_sink_cb,
|
||||
.pac_record = pac_record_cb,
|
||||
.endpoint = endpoint_cb,
|
||||
};
|
||||
|
||||
static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
|
||||
{
|
||||
printk("MTU exchanged\n");
|
||||
SET_FLAG(flag_mtu_exchanged);
|
||||
}
|
||||
|
||||
static struct bt_gatt_cb gatt_callbacks = {
|
||||
.att_mtu_updated = att_mtu_updated,
|
||||
};
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_gatt_cb_register(&gatt_callbacks);
|
||||
|
||||
err = bt_bap_unicast_client_register_cb(&unicast_client_cbs);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to register BAP unicast client callbacks (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_register_cb(&cap_cb);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to register CAP callbacks (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(unicast_client_streams); i++) {
|
||||
bt_cap_stream_ops_register(&unicast_client_streams[i], &unicast_stream_ops);
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_and_connect(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||
if (err != 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Scanning successfully started\n");
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
}
|
||||
|
||||
static void discover_sink(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_sink_discovered);
|
||||
UNSET_FLAG(flag_codec_found);
|
||||
UNSET_FLAG(flag_endpoint_found);
|
||||
|
||||
err = bt_bap_unicast_client_discover(default_conn, BT_AUDIO_DIR_SINK);
|
||||
if (err != 0) {
|
||||
printk("Failed to discover sink: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(unicast_sink_eps, 0, sizeof(unicast_sink_eps));
|
||||
|
||||
WAIT_FOR_FLAG(flag_sink_discovered);
|
||||
WAIT_FOR_FLAG(flag_endpoint_found);
|
||||
WAIT_FOR_FLAG(flag_codec_found);
|
||||
}
|
||||
|
||||
static void discover_cas_inval(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_cap_initiator_unicast_discover(NULL);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_discover with NULL conn did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test if it handles concurrent request for same connection */
|
||||
UNSET_FLAG(flag_discovered);
|
||||
|
||||
err = bt_cap_initiator_unicast_discover(default_conn);
|
||||
if (err != 0) {
|
||||
printk("Failed to discover CAS: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_unicast_discover(default_conn);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_discover while previous discovery has not completed "
|
||||
"did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_discovered);
|
||||
}
|
||||
|
||||
static void discover_cas(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_discovered);
|
||||
|
||||
err = bt_cap_initiator_unicast_discover(default_conn);
|
||||
if (err != 0) {
|
||||
printk("Failed to discover CAS: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_discovered);
|
||||
}
|
||||
|
||||
static void unicast_group_create(struct bt_bap_unicast_group **out_unicast_group)
|
||||
{
|
||||
struct bt_bap_unicast_group_stream_param group_stream_params;
|
||||
struct bt_bap_unicast_group_stream_pair_param pair_params;
|
||||
struct bt_bap_unicast_group_param group_param;
|
||||
int err;
|
||||
|
||||
group_stream_params.qos = &unicast_preset_16_2_1.qos;
|
||||
group_stream_params.stream = &unicast_client_streams[0].bap_stream;
|
||||
pair_params.tx_param = &group_stream_params;
|
||||
pair_params.rx_param = NULL;
|
||||
|
||||
group_param.packing = BT_ISO_PACKING_SEQUENTIAL;
|
||||
group_param.params_count = 1;
|
||||
group_param.params = &pair_params;
|
||||
|
||||
err = bt_bap_unicast_group_create(&group_param, out_unicast_group);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to create group: %d\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group)
|
||||
{
|
||||
struct bt_codec invalid_codec =
|
||||
BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA);
|
||||
struct bt_cap_unicast_audio_start_stream_param invalid_stream_param;
|
||||
struct bt_cap_unicast_audio_start_stream_param valid_stream_param;
|
||||
struct bt_cap_unicast_audio_start_param invalid_start_param;
|
||||
struct bt_cap_unicast_audio_start_param valid_start_param;
|
||||
int err;
|
||||
|
||||
valid_start_param.type = BT_CAP_SET_TYPE_AD_HOC;
|
||||
valid_start_param.count = 1u;
|
||||
valid_start_param.stream_params = &valid_stream_param;
|
||||
|
||||
valid_stream_param.member.member = default_conn;
|
||||
valid_stream_param.stream = &unicast_client_streams[0];
|
||||
valid_stream_param.ep = unicast_sink_eps[0];
|
||||
valid_stream_param.codec = &unicast_preset_16_2_1.codec;
|
||||
valid_stream_param.qos = &unicast_preset_16_2_1.qos;
|
||||
|
||||
/* Test NULL parameters */
|
||||
err = bt_cap_initiator_unicast_audio_start(NULL, unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with NULL param did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_unicast_audio_start(&valid_start_param, NULL);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with NULL group did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test invalid parameters */
|
||||
memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param));
|
||||
memcpy(&invalid_start_param, &valid_start_param, sizeof(valid_start_param));
|
||||
invalid_start_param.stream_params = &invalid_stream_param;
|
||||
|
||||
/* Test invalid stream_start parameters */
|
||||
invalid_start_param.count = 0U;
|
||||
err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with 0 count did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&invalid_start_param, &valid_start_param, sizeof(valid_start_param));
|
||||
invalid_start_param.stream_params = &invalid_stream_param;
|
||||
|
||||
invalid_start_param.stream_params = NULL;
|
||||
err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&invalid_start_param, &valid_start_param, sizeof(valid_start_param));
|
||||
invalid_start_param.stream_params = &invalid_stream_param;
|
||||
|
||||
/* Test invalid stream_param parameters */
|
||||
invalid_stream_param.member.member = NULL;
|
||||
err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params member did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param));
|
||||
|
||||
invalid_stream_param.stream = NULL;
|
||||
err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params stream did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param));
|
||||
|
||||
invalid_stream_param.ep = NULL;
|
||||
err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params ep did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param));
|
||||
|
||||
invalid_stream_param.codec = NULL;
|
||||
err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params codec did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param));
|
||||
|
||||
invalid_stream_param.qos = NULL;
|
||||
err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params qos did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear metadata so that it does not contain the mandatory stream context */
|
||||
memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param));
|
||||
memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta));
|
||||
|
||||
invalid_stream_param.codec = &invalid_codec;
|
||||
err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_start with invalid Codec metadata did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group)
|
||||
{
|
||||
struct bt_cap_unicast_audio_start_stream_param stream_param[1];
|
||||
struct bt_cap_unicast_audio_start_param param;
|
||||
int err;
|
||||
|
||||
param.type = BT_CAP_SET_TYPE_AD_HOC;
|
||||
param.count = 1u;
|
||||
param.stream_params = stream_param;
|
||||
stream_param[0].member.member = default_conn;
|
||||
stream_param[0].stream = &unicast_client_streams[0];
|
||||
stream_param[0].ep = unicast_sink_eps[0];
|
||||
stream_param[0].codec = &unicast_preset_16_2_1.codec;
|
||||
stream_param[0].qos = &unicast_preset_16_2_1.qos;
|
||||
|
||||
UNSET_FLAG(flag_started);
|
||||
|
||||
err = bt_cap_initiator_unicast_audio_start(¶m, unicast_group);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to start unicast audio: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_started);
|
||||
}
|
||||
|
||||
static void unicast_audio_update_inval(void)
|
||||
{
|
||||
struct bt_codec invalid_codec =
|
||||
BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA);
|
||||
struct bt_cap_unicast_audio_update_param param;
|
||||
int err;
|
||||
|
||||
param.stream = &unicast_client_streams[0];
|
||||
param.meta = unicast_preset_16_2_1.codec.meta;
|
||||
param.meta_count = unicast_preset_16_2_1.codec.meta_count;
|
||||
|
||||
err = bt_cap_initiator_unicast_audio_update(NULL, 1);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_update with NULL params did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_unicast_audio_update(¶m, 0);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_update with 0 param count did not fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear metadata so that it does not contain the mandatory stream context */
|
||||
memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta));
|
||||
param.meta = invalid_codec.meta;
|
||||
|
||||
err = bt_cap_initiator_unicast_audio_update(¶m, 1);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_update with invalid Codec metadata did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void unicast_audio_update(void)
|
||||
{
|
||||
struct bt_cap_unicast_audio_update_param param;
|
||||
int err;
|
||||
|
||||
param.stream = &unicast_client_streams[0];
|
||||
param.meta = unicast_preset_16_2_1.codec.meta;
|
||||
param.meta_count = unicast_preset_16_2_1.codec.meta_count;
|
||||
|
||||
UNSET_FLAG(flag_updated);
|
||||
|
||||
err = bt_cap_initiator_unicast_audio_update(¶m, 1);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to update unicast audio: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_updated);
|
||||
}
|
||||
|
||||
static void unicast_audio_stop_inval(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_cap_initiator_unicast_audio_stop(NULL);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_stop with NULL group did not fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void unicast_audio_stop(struct bt_bap_unicast_group *unicast_group)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_stopped);
|
||||
|
||||
err = bt_cap_initiator_unicast_audio_stop(unicast_group);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to start unicast audio: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_stopped);
|
||||
|
||||
/* Verify that it cannot be stopped twice */
|
||||
err = bt_cap_initiator_unicast_audio_stop(unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_cap_initiator_unicast_audio_stop with already-stopped unicast group did "
|
||||
"not fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void unicast_group_delete_inval(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_bap_unicast_group_delete(NULL);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_unicast_group_delete with NULL group did not fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void unicast_group_delete(struct bt_bap_unicast_group *unicast_group)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_bap_unicast_group_delete(unicast_group);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to create group: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify that it cannot be deleted twice */
|
||||
err = bt_bap_unicast_group_delete(unicast_group);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_unicast_group_delete with already-deleted unicast group did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_main_cap_initiator_unicast(void)
|
||||
{
|
||||
struct bt_bap_unicast_group *unicast_group;
|
||||
const size_t iterations = 2;
|
||||
|
||||
init();
|
||||
|
||||
scan_and_connect();
|
||||
|
||||
WAIT_FOR_FLAG(flag_mtu_exchanged);
|
||||
|
||||
discover_cas_inval();
|
||||
discover_cas();
|
||||
|
||||
discover_sink();
|
||||
|
||||
for (size_t i = 0U; i < iterations; i++) {
|
||||
unicast_group_create(&unicast_group);
|
||||
|
||||
for (size_t j = 0U; j < iterations; j++) {
|
||||
unicast_audio_start_inval(unicast_group);
|
||||
unicast_audio_start(unicast_group);
|
||||
|
||||
unicast_audio_update_inval();
|
||||
unicast_audio_update();
|
||||
|
||||
unicast_audio_stop_inval();
|
||||
unicast_audio_stop(unicast_group);
|
||||
}
|
||||
|
||||
unicast_group_delete_inval();
|
||||
unicast_group_delete(unicast_group);
|
||||
unicast_group = NULL;
|
||||
}
|
||||
|
||||
PASS("CAP initiator unicast passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_cap_initiator_unicast[] = {
|
||||
{
|
||||
.test_id = "cap_initiator_unicast",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main_cap_initiator_unicast,
|
||||
},
|
||||
BSTEST_END_MARKER,
|
||||
};
|
||||
|
||||
struct bst_test_list *test_cap_initiator_unicast_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_cap_initiator_unicast);
|
||||
}
|
||||
|
||||
#else /* !(defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_UNICAST_CLIENT)) */
|
||||
|
||||
struct bst_test_list *test_cap_initiator_unicast_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_UNICAST_CLIENT) */
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2020-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -25,7 +25,8 @@ extern struct bst_test_list *test_scan_delegator_install(struct bst_test_list *t
|
|||
extern struct bst_test_list *test_bap_broadcast_assistant_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_bass_broadcaster_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_cap_acceptor_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_cap_initiator_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_cap_initiator_broadcast_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_cap_initiator_unicast_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_has_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_has_client_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_ias_install(struct bst_test_list *tests);
|
||||
|
@ -53,7 +54,8 @@ bst_test_install_t test_installers[] = {
|
|||
test_bap_broadcast_assistant_install,
|
||||
test_bass_broadcaster_install,
|
||||
test_cap_acceptor_install,
|
||||
test_cap_initiator_install,
|
||||
test_cap_initiator_broadcast_install,
|
||||
test_cap_initiator_unicast_install,
|
||||
test_has_install,
|
||||
test_has_client_install,
|
||||
test_ias_install,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue