From 2b0e39dfa5cbddf801c8adf8de79ee4e900bb402 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 2 Oct 2023 16:59:43 +0200 Subject: [PATCH] Bluetooth: Audio: Add bt_audio_codec unset functions Add functions to unset, or remove, specific codec LTV structure from codec_cfgs or codec_caps. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/audio.h | 55 ++++ subsys/bluetooth/audio/codec.c | 133 ++++++++ tests/bluetooth/audio/codec/src/main.c | 416 +++++++++++++++++++++++++ 3 files changed, 604 insertions(+) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index f6885c41a83..772e93588fa 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -823,6 +823,20 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_codec_config_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec configuration value + * + * The type and the value will be removed from the codec configuration. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cfg_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type); + /** @brief Lookup a specific metadata value based on type * * @@ -853,6 +867,19 @@ int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_metadata_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec configuration metadata value + * + * The type and the value will be removed from the codec configuration metadata. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The meta_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cfg_meta_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type); /** @brief Extract preferred contexts * * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. @@ -1188,6 +1215,20 @@ int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_capability_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec capability value + * + * The type and the value will be removed from the codec capability. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cap_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type); + /** * @brief Extract the frequency from a codec capability. * @@ -1346,6 +1387,20 @@ int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap, enum bt_audio_metadata_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec capability metadata value + * + * The type and the value will be removed from the codec capability metadata. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The meta_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cap_meta_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type); + /** @brief Extract preferred contexts * * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 3f5f2b56629..6eec848a9b4 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -224,6 +224,44 @@ static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t * return buf->len; } + +static int ltv_unset_val(struct net_buf_simple *buf, uint8_t type) +{ + for (uint16_t i = 0U; i < buf->len;) { + uint8_t *ltv_start = &buf->data[i]; + const uint8_t len = buf->data[i++]; + const uint8_t data_type = buf->data[i++]; + const uint8_t value_len = len - sizeof(data_type); + + if (data_type == type) { + const uint8_t ltv_size = value_len + sizeof(data_type) + sizeof(len); + uint8_t *value = &buf->data[i]; + + /* Check if this is not the last value in the buffer */ + if (value + value_len != buf->data + buf->len) { + uint8_t *next_data_start; + uint8_t data_len_to_move; + + next_data_start = value + value_len; + data_len_to_move = buf->len - (next_data_start - buf->data); + memmove(ltv_start, next_data_start, data_len_to_move); + + LOG_ERR("buf->data %p, ltv_start %p, value_len %u next_data_start " + "%p data_len_to_move %u", + buf->data, ltv_start, value_len, next_data_start, + data_len_to_move); + } /* else just reduce the length of the buffer */ + + buf->len -= ltv_size; + + return buf->len; + } + + i += value_len; + } + + return buf->len; +} #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 || \ * CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ * CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 || \ @@ -310,6 +348,27 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, return ret; } +int bt_audio_codec_cfg_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type) +{ + struct net_buf_simple buf; + int ret; + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + return -EINVAL; + } + + init_net_buf_simple_from_codec_cfg(&buf, codec_cfg); + + ret = ltv_unset_val(&buf, type); + if (ret >= 0) { + codec_cfg->data_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg) { enum bt_audio_codec_config_freq freq; @@ -595,6 +654,21 @@ static int codec_meta_set_val(uint8_t meta[], size_t meta_len, size_t meta_size, return ltv_set_val(&buf, (uint8_t)type, data, data_len); } +static int codec_meta_unset_val(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_metadata_type type) +{ + struct net_buf_simple buf; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + init_net_buf_simple_from_meta(&buf, meta, meta_len, meta_size); + + return ltv_unset_val(&buf, type); +} + static int codec_meta_get_pref_context(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -1083,6 +1157,25 @@ int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg, return ret; } +int bt_audio_codec_cfg_meta_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type) +{ + int ret; + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + return -EINVAL; + } + + ret = codec_meta_unset_val(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), type); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -1391,6 +1484,25 @@ int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap, return ret; } +int bt_audio_codec_cap_meta_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type) +{ + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + ret = codec_meta_unset_val(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), type); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -1750,6 +1862,27 @@ int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, return ret; } +int bt_audio_codec_cap_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type) +{ + struct net_buf_simple buf; + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + init_net_buf_simple_from_codec_cap(&buf, codec_cap); + + ret = ltv_unset_val(&buf, type); + if (ret >= 0) { + codec_cap->data_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; diff --git a/tests/bluetooth/audio/codec/src/main.c b/tests/bluetooth/audio/codec/src/main.c index 3b909e4582f..73d1362956a 100644 --- a/tests/bluetooth/audio/codec/src/main.c +++ b/tests/bluetooth/audio/codec/src/main.c @@ -15,6 +15,89 @@ DEFINE_FFF_GLOBALS; ZTEST_SUITE(audio_codec_test_suite, NULL, NULL, NULL, NULL, NULL); +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t new_expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ; + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_set_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected data value %u", data[0]); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_val_new_value) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + const uint8_t new_expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_set_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_unset_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_unset_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_get_val(&codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, 0, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_freq_to_freq_hz) { const struct freq_test_input { @@ -234,6 +317,93 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_frame_blocks_per_sdu) zassert_equal(ret, 2, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t new_expected_data = BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE; + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected data value %u", data[0]); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_val_new) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + const uint8_t new_expected_data = BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_set_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_unset_val) +{ + struct bt_audio_codec_cfg codec_cfg = + BT_AUDIO_CODEC_CFG(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_unset_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cfg_meta_get_val(&codec_cfg, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_get_pref_context) { const enum bt_audio_context ctx = @@ -705,6 +875,89 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_meta_set_vendor) zassert_mem_equal(new_expected_data, extended_meta, ARRAY_SIZE(new_expected_data)); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t new_expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ; + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_set_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected data value %u", data[0]); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_val_new) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + const uint8_t new_expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_set_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_unset_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)}, + {}); + const uint8_t expected_data = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_unset_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_get_val(&codec_cap, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data); + zassert_equal(ret, 0, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_freq) { const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( @@ -881,6 +1134,169 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_max_codec_frames_per_s zassert_equal(ret, 4, "Unexpected return value %d", ret); } +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_val) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t new_expected_data = BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE; + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_set_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected data value %u", data[0]); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_set_val_new) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, {}); + const uint8_t new_expected_data = BT_AUDIO_PARENTAL_RATING_AGE_13_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_set_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &new_expected_data, sizeof(new_expected_data)); + zassert_true(ret > 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(new_expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], new_expected_data, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_unset_val_only) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, + {BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE)}); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_unset_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + +/* Providing multiple BT_AUDIO_CODEC_DATA to BT_AUDIO_CODEC_CAP without packing it in a macro + * cause compile issue, so define a macro to denote 3 types of metadata for the meta_unset tests + */ +#define TRIPLE_META_DATA \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, \ + BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \ + BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, \ + BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED)) \ + } + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_unset_val_first) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, TRIPLE_META_DATA); + const uint8_t expected_data = BT_AUDIO_PARENTAL_RATING_AGE_10_OR_ABOVE; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(data[0], expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_unset_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_unset_val_middle) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, TRIPLE_META_DATA); + const uint16_t expected_data = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(sys_get_le16(data), expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_unset_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + +ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_unset_val_last) +{ + struct bt_audio_codec_cap codec_cap = + BT_AUDIO_CODEC_CAP(BT_HCI_CODING_FORMAT_LC3, 0x0000, 0x0000, {}, TRIPLE_META_DATA); + const uint16_t expected_data = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + const uint8_t *data; + int ret; + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + &data); + zassert_equal(ret, sizeof(expected_data), "Unexpected return value %d", ret); + zassert_equal(sys_get_le16(data), expected_data, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_unset_val(&codec_cap, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT); + zassert_true(ret >= 0, "Unexpected return value %d", ret); + + ret = bt_audio_codec_cap_meta_get_val(&codec_cap, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + &data); + zassert_equal(ret, -ENODATA, "Unexpected return value %d", ret); +} + ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_pref_context) { const enum bt_audio_context ctx =