Bluetooth: Audio: Add fallback to get_chan_allocation

Added a fallback parameter to
bt_audio_codec_cfg_get_chan_allocation as absence of
channel allocation in BAP implicitly means Mono.
In the case that it is absent,
BT_AUDIO_LOCATION_MONO_AUDIO is the returned value.

This commit also fixes the implementation of
bt_audio_codec_cfg_get_frame_blocks_per_sdu as it only applies to
LC3 (as per the BAP spec). It also adds additional testing of it

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2024-05-10 13:50:16 +02:00 committed by Anas Nashif
commit c6cc034b5c
14 changed files with 157 additions and 60 deletions

View file

@ -571,6 +571,9 @@ Bluetooth Audio
* All occurrences of ``set_sirk`` have been changed to just ``sirk`` as the ``s`` in ``sirk`` stands
for set. (:github:`73413`)
* Added ``fallback_to_default`` parameter to :c:func:`bt_audio_codec_cfg_get_chan_allocation`.
To maintain existing behavior set the parameter to ``false``. (:github:`72090`)
Bluetooth Classic
=================

View file

@ -986,24 +986,29 @@ int bt_audio_codec_cfg_get_frame_dur(const struct bt_audio_codec_cfg *codec_cfg)
int bt_audio_codec_cfg_set_frame_dur(struct bt_audio_codec_cfg *codec_cfg,
enum bt_audio_codec_cfg_frame_dur frame_dur);
/** @brief Extract channel allocation from BT codec config
/**
* @brief Extract channel allocation from BT codec config
*
* The value returned is a bit field representing one or more audio locations as
* specified by @ref bt_audio_location
* Shall match one or more of the bits set in BT_PAC_SNK_LOC/BT_PAC_SRC_LOC.
* The value returned is a bit field representing one or more audio locations as
* specified by @ref bt_audio_location
* Shall match one or more of the bits set in BT_PAC_SNK_LOC/BT_PAC_SRC_LOC.
*
* Up to the configured @ref BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT number of channels can be present.
* Up to the configured @ref BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT number of channels can be present.
*
* @param codec_cfg The codec configuration to extract data from.
* @param chan_allocation Pointer to the variable to store the extracted value in.
* @param codec_cfg The codec configuration to extract data from.
* @param chan_allocation Pointer to the variable to store the extracted value in.
* @param fallback_to_default If true this function will provide the default value of
* @ref BT_AUDIO_LOCATION_MONO_AUDIO if the type is not found when @p codec_cfg.id is @ref
* BT_HCI_CODING_FORMAT_LC3.
*
* @retval 0 if value is found and stored in the pointer provided
* @retval -EINVAL if arguments are invalid
* @retval -ENODATA if not found
* @retval -EBADMSG if found value has invalid size or value
* @retval 0 if value is found and stored in the pointer provided
* @retval -EINVAL if arguments are invalid
* @retval -ENODATA if not found
* @retval -EBADMSG if found value has invalid size or value
*/
int bt_audio_codec_cfg_get_chan_allocation(const struct bt_audio_codec_cfg *codec_cfg,
enum bt_audio_location *chan_allocation);
enum bt_audio_location *chan_allocation,
bool fallback_to_default);
/**
* @brief Set the channel allocation of a codec configuration.
@ -1051,26 +1056,25 @@ int bt_audio_codec_cfg_get_octets_per_frame(const struct bt_audio_codec_cfg *cod
int bt_audio_codec_cfg_set_octets_per_frame(struct bt_audio_codec_cfg *codec_cfg,
uint16_t octets_per_frame);
/** @brief Extract number of audio frame blocks in each SDU from BT codec config
/**
* @brief Extract number of audio frame blocks in each SDU from BT codec config
*
* The overall SDU size will be octets_per_frame * frame_blocks_per_sdu * number-of-channels.
* The overall SDU size will be octets_per_frame * frame_blocks_per_sdu * number-of-channels.
*
* If this value is not present a default value of 1 shall be used.
* If this value is not present a default value of 1 shall be used.
*
* A frame block is one or more frames that represents data for the same period of time but
* for different channels. If the stream have two audio channels and this value is two
* there will be four frames in the SDU.
* A frame block is one or more frames that represents data for the same period of time but
* for different channels. If the stream have two audio channels and this value is two
* there will be four frames in the SDU.
*
* @param codec_cfg The codec configuration to extract data from.
* @param fallback_to_default If true this function will return the default value of 1
* if the type is not found. In this case the function will only fail if a NULL
* pointer is provided.
* @param codec_cfg The codec configuration to extract data from.
* @param fallback_to_default If true this function will return the default value of 1
* if the type is not found when @p codec_cfg.id is @ref BT_HCI_CODING_FORMAT_LC3.
*
* @retval The count of codec frames in each SDU if value is found else of @p fallback_to_default
* is true then the value 1 is returned if frames per sdu is not found.
* @retval -EINVAL if arguments are invalid
* @retval -ENODATA if not found
* @retval -EBADMSG if found value has invalid size or value
* @retval The count of codec frame blocks in each SDU.
* @retval -EINVAL if arguments are invalid
* @retval -ENODATA if not found
* @retval -EBADMSG if found value has invalid size or value
*/
int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg *codec_cfg,
bool fallback_to_default);

View file

@ -345,7 +345,7 @@ static int lc3_enable(struct broadcast_sink_stream *sink_stream)
}
ret = bt_audio_codec_cfg_get_chan_allocation(sink_stream->stream.codec_cfg,
&sink_stream->chan_allocation);
&sink_stream->chan_allocation, true);
if (ret != 0) {
printk("Error: Channel allocation not set, invalid configuration for LC3");
return ret;
@ -622,18 +622,11 @@ static bool find_valid_bis_cb(const struct bt_bap_base_subgroup_bis *bis,
return true;
}
err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation);
err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation, true);
if (err != 0) {
printk("Could not find channel allocation for BIS: %d\n", err);
/* Absence of channel allocation is implicitly mono as per the BAP spec */
if (CONFIG_TARGET_BROADCAST_CHANNEL == BT_AUDIO_LOCATION_MONO_AUDIO) {
data->bis[0].index = bis->index;
data->bis[0].chan_allocation = chan_allocation;
data->cnt = 1;
return false;
} else if (err == -ENODATA && strlen(CONFIG_TARGET_BROADCAST_NAME) > 0U) {
if (err == -ENODATA && strlen(CONFIG_TARGET_BROADCAST_NAME) > 0U) {
/* Accept no channel allocation data available
* if TARGET_BROADCAST_NAME defined. Use current index.
*/
@ -742,7 +735,7 @@ static bool find_valid_bis_in_subgroup_cb(const struct bt_bap_base_subgroup *sub
return true;
}
err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation);
err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation, false);
if (err != 0) {
printk("Could not find subgroup channel allocation: %d - Looking in the BISes\n",
err);

View file

@ -105,7 +105,7 @@ static int extract_lc3_config(struct tx_stream *stream)
return ret;
}
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &lc3_tx->chan_allocation);
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &lc3_tx->chan_allocation, false);
if (ret != 0) {
LOG_DBG("Could not get channel allocation: %d", ret);
lc3_tx->chan_allocation = BT_AUDIO_LOCATION_MONO_AUDIO;

View file

@ -154,7 +154,8 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret));
}
if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation) == 0) {
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
if (ret == 0) {
printk(" Channel allocation: 0x%x\n", chan_allocation);
}

View file

@ -93,7 +93,8 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret));
}
if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation) == 0) {
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
if (ret == 0) {
printk(" Channel allocation: 0x%x\n", chan_allocation);
}

View file

@ -82,7 +82,8 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret));
}
if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation) == 0) {
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
if (ret == 0) {
printk(" Channel allocation: 0x%x\n", chan_allocation);
}

View file

@ -467,7 +467,8 @@ int bt_audio_codec_cfg_set_frame_dur(struct bt_audio_codec_cfg *codec_cfg,
}
int bt_audio_codec_cfg_get_chan_allocation(const struct bt_audio_codec_cfg *codec_cfg,
enum bt_audio_location *chan_allocation)
enum bt_audio_location *chan_allocation,
bool fallback_to_default)
{
const uint8_t *data;
uint8_t data_len;
@ -486,6 +487,12 @@ int bt_audio_codec_cfg_get_chan_allocation(const struct bt_audio_codec_cfg *code
data_len =
bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CFG_CHAN_ALLOC, &data);
if (data == NULL) {
if (fallback_to_default && codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
*chan_allocation = BT_AUDIO_LOCATION_MONO_AUDIO;
return 0;
}
return -ENODATA;
}
@ -564,7 +571,7 @@ int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg
data_len = bt_audio_codec_cfg_get_val(codec_cfg,
BT_AUDIO_CODEC_CFG_FRAME_BLKS_PER_SDU, &data);
if (data == NULL) {
if (fallback_to_default) {
if (fallback_to_default && codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
return 1;
}

View file

@ -912,8 +912,8 @@ static inline void print_codec_cfg(const struct shell *sh, size_t indent,
(enum bt_audio_codec_cfg_frame_dur)ret);
}
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation);
if (ret >= 0) {
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
if (ret == 0) {
print_codec_cfg_chan_allocation(sh, indent, chan_allocation);
}

View file

@ -2901,8 +2901,8 @@ static void stream_started_cb(struct bt_bap_stream *bap_stream)
sh_stream->lc3_frame_duration_us = 0U;
}
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg,
&sh_stream->lc3_chan_allocation);
ret = bt_audio_codec_cfg_get_chan_allocation(
codec_cfg, &sh_stream->lc3_chan_allocation, false);
if (ret == 0) {
sh_stream->lc3_chan_cnt =
bt_audio_get_chan_count(sh_stream->lc3_chan_allocation);

View file

@ -10,6 +10,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@ -719,7 +720,7 @@ static int set_codec_config(const struct shell *sh, struct shell_stream *sh_stre
return 0;
}
err = bt_audio_codec_cfg_get_chan_allocation(&sh_stream->codec_cfg, &chan_alloc);
err = bt_audio_codec_cfg_get_chan_allocation(&sh_stream->codec_cfg, &chan_alloc, false);
if (err != 0) {
if (err == -ENODATA) {
chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO;

View file

@ -6,11 +6,19 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/fff.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/fff.h>
#include <zephyr/sys/byteorder.h>
#include <ztest_test.h>
#include <ztest_assert.h>
DEFINE_FFF_GLOBALS;
ZTEST_SUITE(audio_codec_test_suite, NULL, NULL, NULL, NULL, NULL);
@ -228,18 +236,59 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_frame_dur)
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_chan_allocation)
{
const struct bt_bap_lc3_preset preset =
BT_BAP_LC3_UNICAST_PRESET_8_1_1(BT_AUDIO_LOCATION_FRONT_LEFT,
BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
const struct bt_bap_lc3_preset preset = BT_BAP_LC3_UNICAST_PRESET_8_1_1(
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
enum bt_audio_location chan_allocation = BT_AUDIO_LOCATION_FRONT_RIGHT;
int err;
err = bt_audio_codec_cfg_get_chan_allocation(&preset.codec_cfg, &chan_allocation);
err = bt_audio_codec_cfg_get_chan_allocation(&preset.codec_cfg, &chan_allocation, false);
zassert_false(err, "unexpected error %d", err);
zassert_equal(chan_allocation, BT_AUDIO_LOCATION_FRONT_LEFT, "unexpected return value %d",
chan_allocation);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_chan_allocation_lc3_fallback_true)
{
struct bt_audio_codec_cfg codec_cfg = {.id = BT_HCI_CODING_FORMAT_LC3};
enum bt_audio_location chan_allocation;
int err;
err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation, true);
zassert_equal(err, 0, "unexpected error %d", err);
zassert_equal(chan_allocation, BT_AUDIO_LOCATION_MONO_AUDIO, "unexpected return value %d",
chan_allocation);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_chan_allocation_lc3_fallback_false)
{
struct bt_audio_codec_cfg codec_cfg = {.id = BT_HCI_CODING_FORMAT_LC3};
enum bt_audio_location chan_allocation;
int err;
err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation, false);
zassert_equal(err, -ENODATA, "unexpected error %d", err);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_chan_allocation_fallback_true)
{
struct bt_audio_codec_cfg codec_cfg = {0};
enum bt_audio_location chan_allocation;
int err;
err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation, true);
zassert_equal(err, -ENODATA, "unexpected error %d", err);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_chan_allocation_fallback_false)
{
struct bt_audio_codec_cfg codec_cfg = {0};
enum bt_audio_location chan_allocation;
int err;
err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation, false);
zassert_equal(err, -ENODATA, "unexpected error %d", err);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_chan_allocation)
{
struct bt_bap_lc3_preset preset = BT_BAP_LC3_UNICAST_PRESET_16_2_1(
@ -247,7 +296,7 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_chan_allocation)
enum bt_audio_location chan_allocation;
int err;
err = bt_audio_codec_cfg_get_chan_allocation(&preset.codec_cfg, &chan_allocation);
err = bt_audio_codec_cfg_get_chan_allocation(&preset.codec_cfg, &chan_allocation, false);
zassert_equal(err, 0, "Unexpected return value %d", err);
zassert_equal(chan_allocation, 0x00000001, "Unexpected chan_allocation value %d",
chan_allocation);
@ -257,7 +306,7 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_chan_allocation)
err = bt_audio_codec_cfg_set_chan_allocation(&preset.codec_cfg, chan_allocation);
zassert_true(err > 0, "Unexpected return value %d", err);
err = bt_audio_codec_cfg_get_chan_allocation(&preset.codec_cfg, &chan_allocation);
err = bt_audio_codec_cfg_get_chan_allocation(&preset.codec_cfg, &chan_allocation, false);
zassert_equal(err, 0, "Unexpected return value %d", err);
zassert_equal(chan_allocation, 0x8080802, "Unexpected chan_allocation value %d",
chan_allocation);
@ -301,6 +350,42 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_frame_blocks_per_sdu)
zassert_equal(ret, 1u, "unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_frame_blocks_per_sdu_lc3_fallback_true)
{
struct bt_audio_codec_cfg codec_cfg = {.id = BT_HCI_CODING_FORMAT_LC3};
int err;
err = bt_audio_codec_cfg_get_frame_blocks_per_sdu(&codec_cfg, true);
zassert_equal(err, 1, "unexpected error %d", err);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_frame_blocks_per_sdu_lc3_fallback_false)
{
struct bt_audio_codec_cfg codec_cfg = {.id = BT_HCI_CODING_FORMAT_LC3};
int err;
err = bt_audio_codec_cfg_get_frame_blocks_per_sdu(&codec_cfg, false);
zassert_equal(err, -ENODATA, "unexpected error %d", err);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_frame_blocks_per_sdu_fallback_true)
{
struct bt_audio_codec_cfg codec_cfg = {0};
int err;
err = bt_audio_codec_cfg_get_frame_blocks_per_sdu(&codec_cfg, true);
zassert_equal(err, -ENODATA, "unexpected error %d", err);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_frame_blocks_per_sdu_fallback_false)
{
struct bt_audio_codec_cfg codec_cfg = {0};
int err;
err = bt_audio_codec_cfg_get_frame_blocks_per_sdu(&codec_cfg, false);
zassert_equal(err, -ENODATA, "unexpected error %d", err);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_frame_blocks_per_sdu)
{
struct bt_bap_lc3_preset preset = BT_BAP_LC3_UNICAST_PRESET_32_2_2(

View file

@ -77,7 +77,8 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret));
}
if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation) == 0) {
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
if (ret == 0) {
LOG_DBG(" Channel allocation: 0x%x", chan_allocation);
}
@ -282,7 +283,7 @@ static int validate_codec_parameters(const struct bt_audio_codec_cfg *codec_cfg)
int ret;
chan_allocation_err =
bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation);
bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true);

View file

@ -134,7 +134,7 @@ static bool valid_base_subgroup(const struct bt_bap_base_subgroup *subgroup)
return false;
}
ret = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation);
ret = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation, false);
if (ret == 0) {
chan_cnt = bt_audio_get_chan_count(chan_allocation);
} else {
@ -444,7 +444,7 @@ static void validate_stream_codec_cfg(const struct bt_bap_stream *stream)
/* The broadcast source sets the channel allocation in the BIS to
* BT_AUDIO_LOCATION_FRONT_LEFT
*/
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation);
ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
if (ret == 0) {
if (chan_allocation != BT_AUDIO_LOCATION_FRONT_LEFT) {
FAIL("Unexpected channel allocation: 0x%08X", chan_allocation);