Bluetooth: BAP: Broadcast Source: Update stream codec config data
When creating a BAP broadcast source with bt_bap_broadcast_source_create only the subgroup information is stored in the streams and the remaining BIS specific information is not stored in the stream->codec_cfg, which it should. Fix is to store bis specific information also in stream codec config. Updated broadcast source BSIM test to verify above usecase. Signed-off-by: Nithin Ramesh Myliattil <niym@demant.com>
This commit is contained in:
parent
14c2be6d9d
commit
df45858d0f
6 changed files with 249 additions and 20 deletions
|
@ -658,6 +658,59 @@ static enum bt_bap_ep_state broadcast_source_get_state(struct bt_bap_broadcast_s
|
|||
return stream->ep->status.state;
|
||||
}
|
||||
|
||||
static bool merge_bis_and_subgroup_data_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_audio_codec_cfg *codec_cfg = user_data;
|
||||
int err;
|
||||
|
||||
err = bt_audio_codec_cfg_set_val(codec_cfg, data->type, data->data, data->data_len);
|
||||
if (err < 0) {
|
||||
LOG_DBG("Failed to set type %u with len %u in codec_cfg: %d", data->type,
|
||||
data->data_len, err);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int update_codec_cfg_data(struct bt_audio_codec_cfg *codec_cfg,
|
||||
const struct bt_bap_broadcast_source_stream_param *stream_param)
|
||||
{
|
||||
int err;
|
||||
/* Merge subgroup codec configuration with the BIS configuration
|
||||
* As per the BAP spec, if a value exist at level 2 (subgroup) and 3 (BIS), then it is
|
||||
* the value at level 3 that shall be used
|
||||
*/
|
||||
if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
|
||||
err = bt_audio_data_parse(stream_param->data, stream_param->data_len,
|
||||
merge_bis_and_subgroup_data_cb, codec_cfg);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Could not merge BIS and subgroup config in codec_cfg: %d", err);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
/* If it is not LC3, then we don't know how to merge the subgroup and BIS codecs,
|
||||
* so we just append them
|
||||
*/
|
||||
if (codec_cfg->data_len + stream_param->data_len >
|
||||
sizeof(codec_cfg->data)) {
|
||||
LOG_DBG("Could not store BIS and subgroup config in codec_cfg (%u > %u)",
|
||||
codec_cfg->data_len + stream_param->data_len,
|
||||
sizeof(codec_cfg->data));
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(&codec_cfg->data[codec_cfg->data_len], stream_param->data,
|
||||
stream_param->data_len);
|
||||
codec_cfg->data_len += stream_param->data_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
|
||||
struct bt_bap_broadcast_source **out_source)
|
||||
{
|
||||
|
@ -665,6 +718,7 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
|
|||
struct bt_audio_codec_qos *qos;
|
||||
size_t stream_count;
|
||||
uint8_t index;
|
||||
uint8_t bis_count;
|
||||
int err;
|
||||
|
||||
CHECKIF(out_source == NULL) {
|
||||
|
@ -694,7 +748,7 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
|
|||
}
|
||||
|
||||
stream_count = 0U;
|
||||
|
||||
bis_count = 0U;
|
||||
qos = param->qos;
|
||||
/* Go through all subgroups and streams and setup each setup with an
|
||||
* endpoint
|
||||
|
@ -726,12 +780,33 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
|
|||
for (size_t j = 0U; j < subgroup_param->params_count; j++) {
|
||||
const struct bt_bap_broadcast_source_stream_param *stream_param;
|
||||
struct bt_bap_stream *stream;
|
||||
struct bt_audio_codec_cfg *codec_cfg;
|
||||
|
||||
codec_cfg = subgroup_param->codec_cfg;
|
||||
stream_param = &subgroup_param->params[j];
|
||||
stream = stream_param->stream;
|
||||
|
||||
if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0) {
|
||||
if (bis_count >= BROADCAST_STREAM_CNT) {
|
||||
LOG_DBG("Stream count %d exceeded", bis_count);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec_cfg = &source->codec_cfg[bis_count];
|
||||
memcpy(codec_cfg, subgroup_param->codec_cfg,
|
||||
sizeof(struct bt_audio_codec_cfg));
|
||||
err = update_codec_cfg_data(codec_cfg, stream_param);
|
||||
if (err != 0) {
|
||||
LOG_DBG("codec config update failed [%zu]: %d", i, err);
|
||||
broadcast_source_cleanup(source);
|
||||
return err;
|
||||
}
|
||||
|
||||
bis_count++;
|
||||
}
|
||||
|
||||
err = broadcast_source_setup_stream(index, stream,
|
||||
subgroup_param->codec_cfg, qos, source);
|
||||
codec_cfg, qos, source);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Failed to setup streams[%zu]: %d", i, err);
|
||||
broadcast_source_cleanup(source);
|
||||
|
@ -789,6 +864,7 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
|
|||
enum bt_bap_ep_state broadcast_state;
|
||||
struct bt_audio_codec_qos *qos;
|
||||
size_t subgroup_cnt;
|
||||
uint8_t bis_count;
|
||||
|
||||
CHECKIF(source == NULL) {
|
||||
LOG_DBG("source is NULL");
|
||||
|
@ -859,7 +935,7 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
|
|||
}
|
||||
|
||||
qos = param->qos;
|
||||
|
||||
bis_count = 0U;
|
||||
/* We update up to the first param->params_count subgroups */
|
||||
for (size_t i = 0U; i < param->params_count; i++) {
|
||||
const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
|
||||
|
@ -885,6 +961,26 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
|
|||
|
||||
stream_param = &subgroup_param->params[j];
|
||||
stream = stream_param->stream;
|
||||
if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0) {
|
||||
int err;
|
||||
|
||||
if (bis_count >= BROADCAST_STREAM_CNT) {
|
||||
LOG_DBG("Stream count %d exceeded", bis_count);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec_cfg = &source->codec_cfg[bis_count];
|
||||
memcpy(codec_cfg, subgroup_param->codec_cfg,
|
||||
sizeof(struct bt_audio_codec_cfg));
|
||||
err = update_codec_cfg_data(codec_cfg, stream_param);
|
||||
|
||||
if (err != 0) {
|
||||
LOG_DBG("codec config update failed [%zu]: %d", i, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
bis_count++;
|
||||
}
|
||||
|
||||
stream_idx = 0U;
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
|
||||
|
|
|
@ -103,9 +103,13 @@ struct bt_bap_broadcast_source {
|
|||
/* The codec specific configured data for each stream in the subgroup */
|
||||
struct bt_audio_broadcast_stream_data stream_data[BROADCAST_STREAM_CNT];
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE];
|
||||
|
||||
/* The complete codec specific configured data for each stream in the subgroup.
|
||||
* This contains both the subgroup and the BIS-specific data for each stream.
|
||||
*/
|
||||
struct bt_audio_codec_cfg codec_cfg[BROADCAST_STREAM_CNT];
|
||||
|
||||
/* The subgroups containing the streams used to create the broadcast source */
|
||||
sys_slist_t subgroups;
|
||||
};
|
||||
|
|
|
@ -44,7 +44,8 @@ static void bap_broadcast_source_test_suite_fixture_init(
|
|||
{
|
||||
const uint8_t bis_cfg_data[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT),
|
||||
BT_BYTES_LIST_LE32(BT_AUDIO_LOCATION_FRONT_LEFT |
|
||||
BT_AUDIO_LOCATION_FRONT_RIGHT)),
|
||||
};
|
||||
const size_t streams_per_subgroup = CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT /
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT;
|
||||
|
@ -228,6 +229,19 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_create_start_send
|
|||
for (size_t j = 0U; j < create_param->params[i].params_count; j++) {
|
||||
struct bt_bap_stream *bap_stream = create_param->params[i].params[j].stream;
|
||||
|
||||
/* verify bap stream started cb stream parameter */
|
||||
zassert_equal(mock_bap_stream_started_cb_fake.arg0_history[i], bap_stream);
|
||||
struct bt_audio_codec_cfg *codec_cfg = bap_stream->codec_cfg;
|
||||
enum bt_audio_location chan_allocation;
|
||||
/* verify subgroup codec data */
|
||||
zassert_equal(bt_audio_codec_cfg_get_freq(codec_cfg),
|
||||
BT_AUDIO_CODEC_CFG_FREQ_16KHZ);
|
||||
zassert_equal(bt_audio_codec_cfg_get_frame_dur(codec_cfg),
|
||||
BT_AUDIO_CODEC_CFG_DURATION_10);
|
||||
/* verify bis specific codec data */
|
||||
bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation);
|
||||
zassert_equal(chan_allocation,
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT);
|
||||
/* Since BAP doesn't care about the `buf` we can just provide NULL */
|
||||
err = bt_bap_stream_send(bap_stream, NULL, 0);
|
||||
zassert_equal(0, err,
|
||||
|
@ -1220,6 +1234,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_id_inval_stat
|
|||
zassert_not_equal(0, err, "Did not fail with deleted broadcast source");
|
||||
}
|
||||
|
||||
|
||||
|
||||
ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base_single_bis)
|
||||
{
|
||||
struct bt_bap_broadcast_source_param *create_param = fixture->param;
|
||||
|
@ -1237,8 +1253,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base_single_b
|
|||
0x04, /* meta length */
|
||||
0x03, 0x02, 0x01, 0x00, /* meta */
|
||||
0x01, /* bis index */
|
||||
0x03, /* bis cc length */
|
||||
0x02, 0x03, 0x03 /* bis cc length */
|
||||
0x06, /* bis cc length */
|
||||
0x05, 0x03, 0x03, 0x00, 0x00, 0x00 /* bis cc length */
|
||||
};
|
||||
|
||||
NET_BUF_SIMPLE_DEFINE(base_buf, 64);
|
||||
|
@ -1294,8 +1310,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base)
|
|||
0x04, /* meta length */
|
||||
0x03, 0x02, 0x01, 0x00, /* meta */
|
||||
0x01, /* bis index */
|
||||
0x03, /* bis cc length */
|
||||
0x02, 0x03, 0x03, /* bis cc length */
|
||||
0x06, /* bis cc length */
|
||||
0x05, 0x03, 0x03, 0x00, 0x00, 0x00, /* bis cc length */
|
||||
0x01, /* Subgroup 1: bis count */
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, /* LC3 codec_id*/
|
||||
0x10, /* cc length */
|
||||
|
@ -1304,8 +1320,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_get_base)
|
|||
0x04, /* meta length */
|
||||
0x03, 0x02, 0x01, 0x00, /* meta */
|
||||
0x02, /* bis index */
|
||||
0x03, /* bis cc length */
|
||||
0x02, 0x03, 0x03 /* bis cc length */
|
||||
0x06, /* bis cc length */
|
||||
0x05, 0x03, 0x03, 0x00, 0x00, 0x00 /* bis cc length */
|
||||
};
|
||||
|
||||
NET_BUF_SIMPLE_DEFINE(base_buf, 128);
|
||||
|
|
|
@ -11,6 +11,7 @@ add_library(uut STATIC
|
|||
${ZEPHYR_BASE}/subsys/bluetooth/audio/bap_iso.c
|
||||
${ZEPHYR_BASE}/subsys/bluetooth/audio/bap_stream.c
|
||||
${ZEPHYR_BASE}/subsys/bluetooth/audio/bap_broadcast_source.c
|
||||
${ZEPHYR_BASE}/subsys/bluetooth/audio/codec.c
|
||||
${ZEPHYR_BASE}/subsys/logging/log_minimal.c
|
||||
${ZEPHYR_BASE}/subsys/net/buf_simple.c
|
||||
)
|
||||
|
|
|
@ -446,7 +446,7 @@ static void validate_stream_codec_cfg(const struct bt_bap_stream *stream)
|
|||
*/
|
||||
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
|
||||
if (ret == 0) {
|
||||
if (chan_allocation != BT_AUDIO_LOCATION_FRONT_LEFT) {
|
||||
if (chan_allocation != BT_AUDIO_LOCATION_FRONT_CENTER) {
|
||||
FAIL("Unexpected channel allocation: 0x%08X", chan_allocation);
|
||||
|
||||
return;
|
||||
|
|
|
@ -27,6 +27,11 @@
|
|||
#include "bstests.h"
|
||||
#include "common.h"
|
||||
|
||||
#define SUPPORTED_CHAN_COUNTS BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2)
|
||||
#define SUPPORTED_MIN_OCTETS_PER_FRAME 30
|
||||
#define SUPPORTED_MAX_OCTETS_PER_FRAME 155
|
||||
#define SUPPORTED_MAX_FRAMES_PER_SDU 1
|
||||
|
||||
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
|
||||
/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that
|
||||
* the controller is never idle
|
||||
|
@ -50,9 +55,123 @@ static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2
|
|||
static struct bt_bap_lc3_preset preset_16_1_1 = BT_BAP_LC3_BROADCAST_PRESET_16_1_1(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
|
||||
|
||||
static uint8_t bis_codec_data[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
|
||||
BT_BYTES_LIST_LE32(BT_AUDIO_LOCATION_FRONT_CENTER)),
|
||||
};
|
||||
|
||||
static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(broadcast_source_streams));
|
||||
static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(broadcast_source_streams));
|
||||
|
||||
static void validate_stream_codec_cfg(const struct bt_bap_stream *stream)
|
||||
{
|
||||
const struct bt_audio_codec_cfg *codec_cfg = stream->codec_cfg;
|
||||
const struct bt_audio_codec_cfg *exp_codec_cfg = &preset_16_1_1.codec_cfg;
|
||||
enum bt_audio_location chan_allocation;
|
||||
uint8_t frames_blocks_per_sdu;
|
||||
size_t min_sdu_size_required;
|
||||
uint16_t octets_per_frame;
|
||||
uint8_t chan_cnt;
|
||||
int ret;
|
||||
int exp_ret;
|
||||
|
||||
ret = bt_audio_codec_cfg_get_freq(codec_cfg);
|
||||
exp_ret = bt_audio_codec_cfg_get_freq(exp_codec_cfg);
|
||||
if (ret >= 0) {
|
||||
const int freq = bt_audio_codec_cfg_freq_to_freq_hz(ret);
|
||||
const int exp_freq = bt_audio_codec_cfg_freq_to_freq_hz(exp_ret);
|
||||
|
||||
if (freq != exp_freq) {
|
||||
FAIL("Invalid frequency: %d Expected: %d\n", freq, exp_freq);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
FAIL("Could not get frequency: %d\n", ret);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg);
|
||||
exp_ret = bt_audio_codec_cfg_get_frame_dur(exp_codec_cfg);
|
||||
if (ret >= 0) {
|
||||
const int frm_dur_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret);
|
||||
const int exp_frm_dur_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(exp_ret);
|
||||
|
||||
if (frm_dur_us != exp_frm_dur_us) {
|
||||
FAIL("Invalid frame duration: %d Exp: %d\n", frm_dur_us, exp_frm_dur_us);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
FAIL("Could not get frame duration: %d\n", ret);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* The broadcast source sets the channel allocation in the BIS to
|
||||
* BT_AUDIO_LOCATION_FRONT_CENTER
|
||||
*/
|
||||
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation);
|
||||
if (ret == 0) {
|
||||
if (chan_allocation != BT_AUDIO_LOCATION_FRONT_CENTER) {
|
||||
FAIL("Unexpected channel allocation: 0x%08X", chan_allocation);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
chan_cnt = bt_audio_get_chan_count(chan_allocation);
|
||||
} else {
|
||||
FAIL("Could not get subgroup channel allocation: %d\n", ret);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (chan_cnt == 0 || (BIT(chan_cnt - 1) & SUPPORTED_CHAN_COUNTS) == 0) {
|
||||
FAIL("Unsupported channel count: %u\n", chan_cnt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ret = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
|
||||
if (ret > 0) {
|
||||
octets_per_frame = (uint16_t)ret;
|
||||
} else {
|
||||
FAIL("Could not get subgroup octets per frame: %d\n", ret);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IN_RANGE(octets_per_frame, SUPPORTED_MIN_OCTETS_PER_FRAME,
|
||||
SUPPORTED_MAX_OCTETS_PER_FRAME)) {
|
||||
FAIL("Unsupported octets per frame: %u\n", octets_per_frame);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, false);
|
||||
if (ret > 0) {
|
||||
frames_blocks_per_sdu = (uint8_t)ret;
|
||||
} else {
|
||||
printk("Could not get octets per frame: %d\n", ret);
|
||||
/* Frame blocks per SDU is optional and is implicitly 1 */
|
||||
frames_blocks_per_sdu = 1U;
|
||||
}
|
||||
|
||||
/* An SDU can consist of X frame blocks, each with Y frames (one per channel) of size Z in
|
||||
* them. The minimum SDU size required for this is X * Y * Z.
|
||||
*/
|
||||
min_sdu_size_required = chan_cnt * octets_per_frame * frames_blocks_per_sdu;
|
||||
if (min_sdu_size_required > stream->qos->sdu) {
|
||||
FAIL("With %zu channels and %u octets per frame and %u frames per block, SDUs "
|
||||
"shall be at minimum %zu, but the stream has been configured for %u\n",
|
||||
chan_cnt, octets_per_frame, frames_blocks_per_sdu, min_sdu_size_required,
|
||||
stream->qos->sdu);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void started_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
struct bt_bap_ep_info info;
|
||||
|
@ -90,6 +209,7 @@ static void started_cb(struct bt_bap_stream *stream)
|
|||
}
|
||||
|
||||
printk("Stream %p started\n", stream);
|
||||
validate_stream_codec_cfg(stream);
|
||||
k_sem_give(&sem_started);
|
||||
}
|
||||
|
||||
|
@ -146,10 +266,6 @@ static struct bt_bap_stream_ops stream_ops = {
|
|||
|
||||
static int setup_broadcast_source(struct bt_bap_broadcast_source **source)
|
||||
{
|
||||
uint8_t bis_codec_data[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
|
||||
BT_BYTES_LIST_LE32(BT_AUDIO_LOCATION_FRONT_LEFT)),
|
||||
};
|
||||
struct bt_bap_broadcast_source_stream_param
|
||||
stream_params[ARRAY_SIZE(broadcast_source_streams)];
|
||||
struct bt_bap_broadcast_source_subgroup_param
|
||||
|
@ -297,10 +413,6 @@ static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_
|
|||
|
||||
static void test_broadcast_source_reconfig(struct bt_bap_broadcast_source *source)
|
||||
{
|
||||
uint8_t bis_codec_data[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_FREQ,
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CFG_FREQ_16KHZ)),
|
||||
};
|
||||
struct bt_bap_broadcast_source_stream_param
|
||||
stream_params[ARRAY_SIZE(broadcast_source_streams)];
|
||||
struct bt_bap_broadcast_source_subgroup_param
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue