| /* |
| * Copyright (c) 2022 Bose Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| /** @file |
| * @brief Bluetooth LE-Audio codec LTV parsing |
| * |
| * Helper functions to parse codec config data as specified in the Bluetooth assigned numbers for |
| * Generic Audio. |
| */ |
| |
| #include <errno.h> |
| #include <stdbool.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <zephyr/autoconf.h> |
| #include <zephyr/bluetooth/audio/audio.h> |
| #include <zephyr/bluetooth/bluetooth.h> |
| #include <zephyr/logging/log.h> |
| #include <zephyr/net_buf.h> |
| #include <zephyr/sys/byteorder.h> |
| #include <zephyr/sys/check.h> |
| #include <zephyr/sys/util.h> |
| |
| LOG_MODULE_REGISTER(bt_audio_codec, CONFIG_BT_AUDIO_CODEC_LOG_LEVEL); |
| |
| int bt_audio_codec_cfg_freq_to_freq_hz(enum bt_audio_codec_cfg_freq freq) |
| { |
| switch (freq) { |
| case BT_AUDIO_CODEC_CFG_FREQ_8KHZ: |
| return 8000; |
| case BT_AUDIO_CODEC_CFG_FREQ_11KHZ: |
| return 11025; |
| case BT_AUDIO_CODEC_CFG_FREQ_16KHZ: |
| return 16000; |
| case BT_AUDIO_CODEC_CFG_FREQ_22KHZ: |
| return 22050; |
| case BT_AUDIO_CODEC_CFG_FREQ_24KHZ: |
| return 24000; |
| case BT_AUDIO_CODEC_CFG_FREQ_32KHZ: |
| return 32000; |
| case BT_AUDIO_CODEC_CFG_FREQ_44KHZ: |
| return 44100; |
| case BT_AUDIO_CODEC_CFG_FREQ_48KHZ: |
| return 48000; |
| case BT_AUDIO_CODEC_CFG_FREQ_88KHZ: |
| return 88200; |
| case BT_AUDIO_CODEC_CFG_FREQ_96KHZ: |
| return 96000; |
| case BT_AUDIO_CODEC_CFG_FREQ_176KHZ: |
| return 176400; |
| case BT_AUDIO_CODEC_CFG_FREQ_192KHZ: |
| return 192000; |
| case BT_AUDIO_CODEC_CFG_FREQ_384KHZ: |
| return 384000; |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| int bt_audio_codec_cfg_freq_hz_to_freq(uint32_t freq_hz) |
| { |
| switch (freq_hz) { |
| case 8000U: |
| return BT_AUDIO_CODEC_CFG_FREQ_8KHZ; |
| case 11025U: |
| return BT_AUDIO_CODEC_CFG_FREQ_11KHZ; |
| case 16000U: |
| return BT_AUDIO_CODEC_CFG_FREQ_16KHZ; |
| case 22050U: |
| return BT_AUDIO_CODEC_CFG_FREQ_22KHZ; |
| case 24000U: |
| return BT_AUDIO_CODEC_CFG_FREQ_24KHZ; |
| case 32000U: |
| return BT_AUDIO_CODEC_CFG_FREQ_32KHZ; |
| case 44100U: |
| return BT_AUDIO_CODEC_CFG_FREQ_44KHZ; |
| case 48000U: |
| return BT_AUDIO_CODEC_CFG_FREQ_48KHZ; |
| case 88200U: |
| return BT_AUDIO_CODEC_CFG_FREQ_88KHZ; |
| case 96000U: |
| return BT_AUDIO_CODEC_CFG_FREQ_96KHZ; |
| case 176400U: |
| return BT_AUDIO_CODEC_CFG_FREQ_176KHZ; |
| case 192000U: |
| return BT_AUDIO_CODEC_CFG_FREQ_192KHZ; |
| case 384000U: |
| return BT_AUDIO_CODEC_CFG_FREQ_384KHZ; |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| int bt_audio_codec_cfg_frame_dur_to_frame_dur_us(enum bt_audio_codec_cfg_frame_dur frame_dur) |
| { |
| switch (frame_dur) { |
| case BT_AUDIO_CODEC_CFG_DURATION_7_5: |
| return 7500; |
| case BT_AUDIO_CODEC_CFG_DURATION_10: |
| return 10000; |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| int bt_audio_codec_cfg_frame_dur_us_to_frame_dur(uint32_t frame_dur_us) |
| { |
| switch (frame_dur_us) { |
| case 7500U: |
| return BT_AUDIO_CODEC_CFG_DURATION_7_5; |
| case 10000U: |
| return BT_AUDIO_CODEC_CFG_DURATION_10; |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| #if 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 || \ |
| CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 |
| |
| static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t *data, |
| size_t data_len) |
| { |
| size_t new_buf_len; |
| |
| for (uint16_t i = 0U; i < buf->len;) { |
| 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) { |
| uint8_t *value = &buf->data[i]; |
| |
| if (data_len == value_len) { |
| memcpy(value, data, data_len); |
| } else { |
| const int16_t diff = data_len - value_len; |
| uint8_t *old_next_data_start; |
| uint8_t *new_next_data_start; |
| uint8_t data_len_to_move; |
| |
| /* Check if this is the last value in the buffer */ |
| if (value + value_len == buf->data + buf->len) { |
| data_len_to_move = 0U; |
| } else { |
| old_next_data_start = value + value_len; |
| new_next_data_start = value + data_len; |
| data_len_to_move = |
| buf->len - (old_next_data_start - buf->data); |
| } |
| |
| if (diff < 0) { |
| /* In this case we need to move memory around after the copy |
| * to fit the new shorter data |
| */ |
| |
| memcpy(value, data, data_len); |
| if (data_len_to_move > 0U) { |
| memmove(new_next_data_start, old_next_data_start, |
| data_len_to_move); |
| } |
| } else { |
| /* In this case we need to move memory around before |
| * the copy to fit the new longer data |
| */ |
| if ((buf->len + diff) > buf->size) { |
| LOG_DBG("Cannot fit data_len %zu in buf with len " |
| "%u and size %u", |
| data_len, buf->len, buf->size); |
| return -ENOMEM; |
| } |
| |
| if (data_len_to_move > 0) { |
| memmove(new_next_data_start, old_next_data_start, |
| data_len_to_move); |
| } |
| memcpy(value, data, data_len); |
| } |
| |
| buf->len += diff; |
| *len += diff; |
| } |
| |
| return buf->len; |
| } |
| |
| i += value_len; |
| } |
| |
| /* If we reach here, we did not find the data in the buffer, so we simply add it */ |
| new_buf_len = buf->len + 1 /* len */ + sizeof(type) + data_len; |
| if (new_buf_len <= buf->size) { |
| net_buf_simple_add_u8(buf, data_len + sizeof(type)); /* len */ |
| net_buf_simple_add_u8(buf, type); /* type */ |
| if (data_len > 0) { |
| net_buf_simple_add_mem(buf, data, data_len); /* value */ |
| } |
| } else { |
| LOG_DBG("Cannot fit data_len %zu in codec_cfg with len %u and size %u", data_len, |
| buf->len, buf->size); |
| return -ENOMEM; |
| } |
| |
| 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 || \ |
| * CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 \ |
| */ |
| |
| #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 |
| |
| static void init_net_buf_simple_from_codec_cfg(struct net_buf_simple *buf, |
| struct bt_audio_codec_cfg *codec_cfg) |
| { |
| buf->__buf = codec_cfg->data; |
| buf->data = codec_cfg->data; |
| buf->size = sizeof(codec_cfg->data); |
| buf->len = codec_cfg->data_len; |
| } |
| |
| int bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_codec_cfg_type type, const uint8_t **data) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(data == NULL) { |
| LOG_DBG("data is NULL"); |
| return -EINVAL; |
| } |
| |
| return bt_audio_data_get_val(codec_cfg->data, codec_cfg->data_len, (uint8_t)type, data); |
| } |
| |
| int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_codec_cfg_type type, const uint8_t *data, |
| size_t data_len) |
| { |
| struct net_buf_simple buf; |
| int ret; |
| |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(data == NULL) { |
| LOG_DBG("data is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(data_len == 0U || data_len > UINT8_MAX) { |
| LOG_DBG("Invalid data_len %zu", data_len); |
| return -EINVAL; |
| } |
| |
| init_net_buf_simple_from_codec_cfg(&buf, codec_cfg); |
| |
| ret = ltv_set_val(&buf, type, data, data_len); |
| if (ret >= 0) { |
| codec_cfg->data_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_unset_val(struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_codec_cfg_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_cfg_freq freq; |
| const uint8_t *data; |
| uint8_t data_len; |
| |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec is NULL"); |
| return -EINVAL; |
| } |
| |
| data_len = bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CFG_FREQ, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (data_len != sizeof(uint8_t)) { |
| return -EBADMSG; |
| } |
| |
| freq = data[0]; |
| if (bt_audio_codec_cfg_freq_to_freq_hz(freq) < 0) { |
| LOG_DBG("Invalid freq value: 0x%02X", freq); |
| return -EBADMSG; |
| } |
| |
| return freq; |
| } |
| |
| int bt_audio_codec_cfg_set_freq(struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_codec_cfg_freq freq) |
| { |
| uint8_t freq_u8; |
| |
| if (bt_audio_codec_cfg_freq_to_freq_hz(freq) < 0) { |
| LOG_DBG("Invalid freq value: %d", freq); |
| return -EINVAL; |
| } |
| |
| freq_u8 = (uint8_t)freq; |
| |
| return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_FREQ, &freq_u8, |
| sizeof(freq_u8)); |
| } |
| |
| int bt_audio_codec_cfg_get_frame_dur(const struct bt_audio_codec_cfg *codec_cfg) |
| { |
| enum bt_audio_codec_cfg_frame_dur frame_dur; |
| const uint8_t *data; |
| uint8_t data_len; |
| |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec is NULL"); |
| return -EINVAL; |
| } |
| |
| data_len = bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CFG_DURATION, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (data_len != sizeof(uint8_t)) { |
| return -EBADMSG; |
| } |
| |
| frame_dur = data[0]; |
| if (bt_audio_codec_cfg_frame_dur_to_frame_dur_us(frame_dur) < 0) { |
| LOG_DBG("Invalid frame_dur value: 0x%02X", frame_dur); |
| return -EBADMSG; |
| } |
| |
| return frame_dur; |
| } |
| |
| int bt_audio_codec_cfg_set_frame_dur(struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_codec_cfg_frame_dur frame_dur) |
| { |
| uint8_t frame_dur_u8; |
| |
| if (bt_audio_codec_cfg_frame_dur_to_frame_dur_us(frame_dur) < 0) { |
| LOG_DBG("Invalid freq value: %d", frame_dur); |
| return -EINVAL; |
| } |
| |
| frame_dur_u8 = (uint8_t)frame_dur; |
| |
| return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_DURATION, |
| &frame_dur_u8, sizeof(frame_dur_u8)); |
| } |
| |
| int bt_audio_codec_cfg_get_chan_allocation(const struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_location *chan_allocation, |
| bool fallback_to_default) |
| { |
| const uint8_t *data; |
| uint8_t data_len; |
| |
| *chan_allocation = 0; |
| |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(chan_allocation == NULL) { |
| return -EINVAL; |
| } |
| |
| 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; |
| } |
| |
| if (data_len != sizeof(uint32_t)) { |
| return -EBADMSG; |
| } |
| |
| *chan_allocation = sys_get_le32(data); |
| |
| return 0; |
| } |
| |
| int bt_audio_codec_cfg_set_chan_allocation(struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_location chan_allocation) |
| { |
| uint32_t chan_allocation_u32; |
| |
| if ((chan_allocation & BT_AUDIO_LOCATION_ANY) != chan_allocation) { |
| LOG_DBG("Invalid chan_allocation value: 0x%08X", chan_allocation); |
| return -EINVAL; |
| } |
| |
| chan_allocation_u32 = sys_cpu_to_le32((uint32_t)chan_allocation); |
| |
| return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_CHAN_ALLOC, |
| (const uint8_t *)&chan_allocation_u32, |
| sizeof(chan_allocation_u32)); |
| } |
| |
| int bt_audio_codec_cfg_get_octets_per_frame(const struct bt_audio_codec_cfg *codec_cfg) |
| { |
| const uint8_t *data; |
| uint8_t data_len; |
| |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec is NULL"); |
| return -EINVAL; |
| } |
| |
| data_len = |
| bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CFG_FRAME_LEN, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (data_len != sizeof(uint16_t)) { |
| return -EBADMSG; |
| } |
| |
| return sys_get_le16(data); |
| } |
| |
| int bt_audio_codec_cfg_set_octets_per_frame(struct bt_audio_codec_cfg *codec_cfg, |
| uint16_t octets_per_frame) |
| { |
| uint16_t octets_per_frame_le16; |
| |
| octets_per_frame_le16 = sys_cpu_to_le16(octets_per_frame); |
| |
| return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_FRAME_LEN, |
| (uint8_t *)&octets_per_frame_le16, |
| sizeof(octets_per_frame_le16)); |
| } |
| |
| int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg *codec_cfg, |
| bool fallback_to_default) |
| { |
| const uint8_t *data; |
| uint8_t data_len; |
| |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec is NULL"); |
| return -EINVAL; |
| } |
| |
| 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 && codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { |
| return 1; |
| } |
| |
| return -ENODATA; |
| } |
| |
| if (data_len != sizeof(uint8_t)) { |
| return -EBADMSG; |
| } |
| |
| return data[0]; |
| } |
| |
| int bt_audio_codec_cfg_set_frame_blocks_per_sdu(struct bt_audio_codec_cfg *codec_cfg, |
| uint8_t frame_blocks) |
| { |
| return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_FRAME_BLKS_PER_SDU, |
| &frame_blocks, sizeof(frame_blocks)); |
| } |
| #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */ |
| |
| #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ |
| CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 |
| |
| static void init_net_buf_simple_from_meta(struct net_buf_simple *buf, uint8_t meta[], |
| size_t meta_len, size_t meta_size) |
| { |
| buf->__buf = meta; |
| buf->data = meta; |
| buf->size = meta_size; |
| buf->len = meta_len; |
| } |
| |
| static int codec_meta_get_val(const uint8_t meta[], size_t meta_len, |
| enum bt_audio_metadata_type type, const uint8_t **data) |
| { |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(data == NULL) { |
| LOG_DBG("data is NULL"); |
| return -EINVAL; |
| } |
| |
| return bt_audio_data_get_val(meta, meta_len, (uint8_t)type, data); |
| } |
| |
| static int codec_meta_set_val(uint8_t meta[], size_t meta_len, size_t meta_size, |
| enum bt_audio_metadata_type type, const uint8_t *data, |
| size_t data_len) |
| { |
| struct net_buf_simple buf; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(data == NULL && data_len != 0) { |
| LOG_DBG("data is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(data_len > UINT8_MAX) { |
| LOG_DBG("Invalid data_len %zu", data_len); |
| return -EINVAL; |
| } |
| |
| init_net_buf_simple_from_meta(&buf, meta, meta_len, 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; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (ret != sizeof(uint16_t)) { |
| return -EBADMSG; |
| } |
| |
| return sys_get_le16(data); |
| } |
| |
| static int codec_meta_set_pref_context(uint8_t meta[], size_t meta_len, size_t meta_size, |
| enum bt_audio_context ctx) |
| { |
| uint16_t ctx_le16; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| if ((ctx & BT_AUDIO_CONTEXT_TYPE_ANY) != ctx) { |
| LOG_DBG("Invalid ctx value: %d", ctx); |
| return -EINVAL; |
| } |
| |
| ctx_le16 = sys_cpu_to_le16((uint16_t)ctx); |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, |
| (const uint8_t *)&ctx_le16, sizeof(ctx_le16)); |
| } |
| |
| static int codec_meta_get_stream_context(const uint8_t meta[], size_t meta_len) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (ret != sizeof(uint16_t)) { |
| return -EBADMSG; |
| } |
| |
| return sys_get_le16(data); |
| } |
| |
| static int codec_meta_set_stream_context(uint8_t meta[], size_t meta_len, size_t meta_size, |
| enum bt_audio_context ctx) |
| { |
| uint16_t ctx_le16; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| if ((ctx & BT_AUDIO_CONTEXT_TYPE_ANY) != ctx) { |
| LOG_DBG("Invalid ctx value: %d", ctx); |
| return -EINVAL; |
| } |
| |
| ctx_le16 = sys_cpu_to_le16((uint16_t)ctx); |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, |
| (const uint8_t *)&ctx_le16, sizeof(ctx_le16)); |
| } |
| |
| static int codec_meta_get_program_info(const uint8_t meta[], size_t meta_len, |
| const uint8_t **program_info) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(program_info == NULL) { |
| LOG_DBG("program_info is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| *program_info = data; |
| |
| return ret; |
| } |
| |
| static int codec_meta_set_program_info(uint8_t meta[], size_t meta_len, size_t meta_size, |
| const uint8_t *program_info, size_t program_info_len) |
| { |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(program_info == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, |
| program_info, program_info_len); |
| } |
| |
| static int codec_meta_get_lang(const uint8_t meta[], size_t meta_len, const uint8_t **lang) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(lang == NULL) { |
| LOG_DBG("lang is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_LANG, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (ret != BT_AUDIO_LANG_SIZE) { |
| return -EBADMSG; |
| } |
| |
| *lang = data; |
| |
| return 0; |
| } |
| |
| static int codec_meta_set_lang(uint8_t meta[], size_t meta_len, size_t meta_size, |
| const uint8_t lang[BT_AUDIO_LANG_SIZE]) |
| { |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(lang == NULL) { |
| LOG_DBG("lang is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_LANG, lang, |
| BT_AUDIO_LANG_SIZE); |
| } |
| |
| static int codec_meta_get_ccid_list(const uint8_t meta[], size_t meta_len, |
| const uint8_t **ccid_list) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(ccid_list == NULL) { |
| LOG_DBG("ccid_list is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_CCID_LIST, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| *ccid_list = data; |
| |
| return ret; |
| } |
| |
| static int codec_meta_set_ccid_list(uint8_t meta[], size_t meta_len, size_t meta_size, |
| const uint8_t *ccid_list, size_t ccid_list_len) |
| { |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(ccid_list == NULL) { |
| LOG_DBG("ccid_list is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_CCID_LIST, |
| ccid_list, ccid_list_len); |
| } |
| |
| static int codec_meta_get_parental_rating(const uint8_t meta[], size_t meta_len) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (ret != sizeof(uint8_t)) { |
| return -EBADMSG; |
| } |
| |
| return data[0]; |
| } |
| |
| static int codec_meta_set_parental_rating(uint8_t meta[], size_t meta_len, size_t meta_size, |
| enum bt_audio_parental_rating parental_rating) |
| { |
| uint8_t parental_rating_u8; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| if (parental_rating > BT_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE) { |
| LOG_DBG("Invalid parental_rating value: %d", parental_rating); |
| return -EINVAL; |
| } |
| |
| parental_rating_u8 = (uint8_t)parental_rating; |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, |
| &parental_rating_u8, sizeof(parental_rating_u8)); |
| } |
| |
| static int codec_meta_get_program_info_uri(const uint8_t meta[], size_t meta_len, |
| const uint8_t **program_info_uri) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(program_info_uri == NULL) { |
| LOG_DBG("program_info_uri is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| *program_info_uri = data; |
| |
| return ret; |
| } |
| |
| static int codec_meta_set_program_info_uri(uint8_t meta[], size_t meta_len, size_t meta_size, |
| const uint8_t *program_info_uri, |
| size_t program_info_uri_len) |
| { |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(program_info_uri == NULL) { |
| LOG_DBG("program_info_uri is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, |
| BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI, program_info_uri, |
| program_info_uri_len); |
| } |
| |
| static int codec_meta_get_audio_active_state(const uint8_t meta[], size_t meta_len) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_AUDIO_STATE, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (ret != sizeof(uint8_t)) { |
| return -EBADMSG; |
| } |
| |
| return data[0]; |
| } |
| |
| static int codec_meta_set_audio_active_state(uint8_t meta[], size_t meta_len, size_t meta_size, |
| enum bt_audio_active_state state) |
| { |
| uint8_t state_u8; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| if (state != BT_AUDIO_ACTIVE_STATE_DISABLED && state != BT_AUDIO_ACTIVE_STATE_ENABLED) { |
| LOG_DBG("Invalid state value: %d", state); |
| return -EINVAL; |
| } |
| |
| state_u8 = (uint8_t)state; |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_AUDIO_STATE, |
| &state_u8, sizeof(state_u8)); |
| } |
| |
| static int codec_meta_get_bcast_audio_immediate_rend_flag(const uint8_t meta[], size_t meta_len) |
| { |
| const uint8_t *data; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE, |
| &data); |
| } |
| |
| static int codec_meta_set_bcast_audio_immediate_rend_flag(uint8_t meta[], size_t meta_len, |
| size_t meta_size) |
| { |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, |
| BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE, NULL, 0); |
| } |
| |
| static int codec_meta_get_assisted_listening_stream(const uint8_t meta[], size_t meta_len) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM, |
| &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (ret != sizeof(uint8_t)) { |
| return -EBADMSG; |
| } |
| |
| return data[0]; |
| } |
| |
| static int codec_meta_set_assisted_listening_stream(uint8_t meta[], size_t meta_len, |
| size_t meta_size, |
| enum bt_audio_assisted_listening_stream val) |
| { |
| uint8_t val_u8; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| if (val != BT_AUDIO_ASSISTED_LISTENING_STREAM_UNSPECIFIED) { |
| LOG_DBG("Invalid value: %d", val); |
| return -EINVAL; |
| } |
| |
| val_u8 = (uint8_t)val; |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, |
| BT_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM, &val_u8, |
| sizeof(val_u8)); |
| } |
| |
| static int codec_meta_get_broadcast_name(const uint8_t meta[], size_t meta_len, |
| const uint8_t **broadcast_name) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(broadcast_name == NULL) { |
| LOG_DBG("broadcast_name is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_BROADCAST_NAME, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| *broadcast_name = data; |
| |
| return ret; |
| } |
| |
| static int codec_meta_set_broadcast_name(uint8_t meta[], size_t meta_len, size_t meta_size, |
| const uint8_t *broadcast_name, size_t broadcast_name_len) |
| { |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(broadcast_name == NULL) { |
| LOG_DBG("broadcast_name is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_BROADCAST_NAME, |
| broadcast_name, broadcast_name_len); |
| } |
| |
| static int codec_meta_get_extended(const uint8_t meta[], size_t meta_len, |
| const uint8_t **extended_meta) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(extended_meta == NULL) { |
| LOG_DBG("extended_meta is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_EXTENDED, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| *extended_meta = data; |
| |
| return ret; |
| } |
| |
| static int codec_meta_set_extended(uint8_t meta[], size_t meta_len, size_t meta_size, |
| const uint8_t *extended, size_t extended_len) |
| { |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(extended == NULL) { |
| LOG_DBG("extended is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_EXTENDED, |
| extended, extended_len); |
| } |
| |
| static int codec_meta_get_vendor(const uint8_t meta[], size_t meta_len, const uint8_t **vendor_meta) |
| { |
| const uint8_t *data; |
| int ret; |
| |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(vendor_meta == NULL) { |
| LOG_DBG("vendor_meta is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_VENDOR, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| *vendor_meta = data; |
| |
| return ret; |
| } |
| |
| static int codec_meta_set_vendor(uint8_t meta[], size_t meta_len, size_t meta_size, |
| const uint8_t *vendor, size_t vendor_len) |
| { |
| CHECKIF(meta == NULL) { |
| LOG_DBG("meta is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(vendor == NULL) { |
| LOG_DBG("vendor is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_VENDOR, vendor, |
| vendor_len); |
| } |
| |
| #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 |
| int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, |
| const uint8_t **data) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_val(codec_cfg->meta, codec_cfg->meta_len, type, data); |
| } |
| |
| 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) |
| { |
| int ret; |
| |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_set_val(codec_cfg->meta, codec_cfg->meta_len, ARRAY_SIZE(codec_cfg->meta), |
| type, data, data_len); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| 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, |
| bool fallback_to_default) |
| { |
| int ret; |
| |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_get_pref_context(codec_cfg->meta, codec_cfg->meta_len); |
| |
| if (ret == -ENODATA && fallback_to_default && codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { |
| return BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_set_pref_context(struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_context ctx) |
| { |
| int ret; |
| |
| ret = codec_meta_set_pref_context(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), ctx); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg *codec_cfg) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_stream_context(codec_cfg->meta, codec_cfg->meta_len); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_stream_context(struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_context ctx) |
| { |
| int ret; |
| |
| ret = codec_meta_set_stream_context(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), ctx); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t **program_info) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_program_info(codec_cfg->meta, codec_cfg->meta_len, program_info); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_program_info(struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t *program_info, size_t program_info_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_program_info(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), program_info, |
| program_info_len); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_lang(const struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t **lang) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_lang(codec_cfg->meta, codec_cfg->meta_len, lang); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_lang(struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t lang[BT_AUDIO_LANG_SIZE]) |
| { |
| int ret; |
| |
| ret = codec_meta_set_lang(codec_cfg->meta, codec_cfg->meta_len, ARRAY_SIZE(codec_cfg->meta), |
| lang); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t **ccid_list) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_ccid_list(codec_cfg->meta, codec_cfg->meta_len, ccid_list); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_ccid_list(struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t *ccid_list, size_t ccid_list_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_ccid_list(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), ccid_list, ccid_list_len); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg *codec_cfg) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_parental_rating(codec_cfg->meta, codec_cfg->meta_len); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_parental_rating(struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_parental_rating parental_rating) |
| { |
| int ret; |
| |
| ret = codec_meta_set_parental_rating(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), parental_rating); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t **program_info_uri) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_program_info_uri(codec_cfg->meta, codec_cfg->meta_len, |
| program_info_uri); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_program_info_uri(struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t *program_info_uri, |
| size_t program_info_uri_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_program_info_uri(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), program_info_uri, |
| program_info_uri_len); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_cfg *codec_cfg) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_audio_active_state(codec_cfg->meta, codec_cfg->meta_len); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_audio_active_state(struct bt_audio_codec_cfg *codec_cfg, |
| enum bt_audio_active_state state) |
| { |
| int ret; |
| |
| ret = codec_meta_set_audio_active_state(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), state); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( |
| const struct bt_audio_codec_cfg *codec_cfg) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_bcast_audio_immediate_rend_flag(codec_cfg->meta, codec_cfg->meta_len); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag( |
| struct bt_audio_codec_cfg *codec_cfg) |
| { |
| int ret; |
| |
| ret = codec_meta_set_bcast_audio_immediate_rend_flag(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta)); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_assisted_listening_stream( |
| const struct bt_audio_codec_cfg *codec_cfg) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_assisted_listening_stream(codec_cfg->meta, codec_cfg->meta_len); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_assisted_listening_stream( |
| struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_assisted_listening_stream val) |
| { |
| int ret; |
| |
| ret = codec_meta_set_assisted_listening_stream(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), val); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t **extended_meta) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_extended(codec_cfg->meta, codec_cfg->meta_len, extended_meta); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_extended(struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t *extended_meta, size_t extended_meta_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_extended(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), extended_meta, |
| extended_meta_len); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t **vendor_meta) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_vendor(codec_cfg->meta, codec_cfg->meta_len, vendor_meta); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_vendor(struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t *vendor_meta, size_t vendor_meta_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_vendor(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), vendor_meta, vendor_meta_len); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cfg_meta_get_broadcast_name(const struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t **broadcast_name) |
| { |
| CHECKIF(codec_cfg == NULL) { |
| LOG_DBG("codec_cfg is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_broadcast_name(codec_cfg->meta, codec_cfg->meta_len, broadcast_name); |
| } |
| |
| int bt_audio_codec_cfg_meta_set_broadcast_name(struct bt_audio_codec_cfg *codec_cfg, |
| const uint8_t *broadcast_name, |
| size_t broadcast_name_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_broadcast_name(codec_cfg->meta, codec_cfg->meta_len, |
| ARRAY_SIZE(codec_cfg->meta), broadcast_name, |
| broadcast_name_len); |
| if (ret >= 0) { |
| codec_cfg->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */ |
| |
| #if CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 |
| int bt_audio_codec_cap_meta_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, |
| const uint8_t **data) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_val(codec_cap->meta, codec_cap->meta_len, type, data); |
| } |
| |
| 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) |
| { |
| int ret; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| ret = codec_meta_set_val(codec_cap->meta, codec_cap->meta_len, ARRAY_SIZE(codec_cap->meta), |
| type, data, data_len); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| 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) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_pref_context(codec_cap->meta, codec_cap->meta_len); |
| } |
| |
| int bt_audio_codec_cap_meta_set_pref_context(struct bt_audio_codec_cap *codec_cap, |
| enum bt_audio_context ctx) |
| { |
| int ret; |
| |
| ret = codec_meta_set_pref_context(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), ctx); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap *codec_cap) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_stream_context(codec_cap->meta, codec_cap->meta_len); |
| } |
| |
| int bt_audio_codec_cap_meta_set_stream_context(struct bt_audio_codec_cap *codec_cap, |
| enum bt_audio_context ctx) |
| { |
| int ret; |
| |
| ret = codec_meta_set_stream_context(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), ctx); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *codec_cap, |
| const uint8_t **program_info) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_program_info(codec_cap->meta, codec_cap->meta_len, program_info); |
| } |
| |
| int bt_audio_codec_cap_meta_set_program_info(struct bt_audio_codec_cap *codec_cap, |
| const uint8_t *program_info, size_t program_info_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_program_info(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), program_info, |
| program_info_len); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_lang(const struct bt_audio_codec_cap *codec_cap, |
| const uint8_t **lang) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_lang(codec_cap->meta, codec_cap->meta_len, lang); |
| } |
| |
| int bt_audio_codec_cap_meta_set_lang(struct bt_audio_codec_cap *codec_cap, |
| const uint8_t lang[BT_AUDIO_LANG_SIZE]) |
| { |
| int ret; |
| |
| ret = codec_meta_set_lang(codec_cap->meta, codec_cap->meta_len, ARRAY_SIZE(codec_cap->meta), |
| lang); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec_cap, |
| const uint8_t **ccid_list) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_ccid_list(codec_cap->meta, codec_cap->meta_len, ccid_list); |
| } |
| |
| int bt_audio_codec_cap_meta_set_ccid_list(struct bt_audio_codec_cap *codec_cap, |
| const uint8_t *ccid_list, size_t ccid_list_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_ccid_list(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), ccid_list, ccid_list_len); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap *codec_cap) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_parental_rating(codec_cap->meta, codec_cap->meta_len); |
| } |
| |
| int bt_audio_codec_cap_meta_set_parental_rating(struct bt_audio_codec_cap *codec_cap, |
| enum bt_audio_parental_rating parental_rating) |
| { |
| int ret; |
| |
| ret = codec_meta_set_parental_rating(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), parental_rating); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap *codec_cap, |
| const uint8_t **program_info_uri) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_program_info_uri(codec_cap->meta, codec_cap->meta_len, |
| program_info_uri); |
| } |
| |
| int bt_audio_codec_cap_meta_set_program_info_uri(struct bt_audio_codec_cap *codec_cap, |
| const uint8_t *program_info_uri, |
| size_t program_info_uri_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_program_info_uri(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), program_info_uri, |
| program_info_uri_len); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_cap *codec_cap) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_audio_active_state(codec_cap->meta, codec_cap->meta_len); |
| } |
| |
| int bt_audio_codec_cap_meta_set_audio_active_state(struct bt_audio_codec_cap *codec_cap, |
| enum bt_audio_active_state state) |
| { |
| int ret; |
| |
| ret = codec_meta_set_audio_active_state(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), state); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( |
| const struct bt_audio_codec_cap *codec_cap) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_bcast_audio_immediate_rend_flag(codec_cap->meta, codec_cap->meta_len); |
| } |
| |
| int bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag( |
| struct bt_audio_codec_cap *codec_cap) |
| { |
| int ret; |
| |
| ret = codec_meta_set_bcast_audio_immediate_rend_flag(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta)); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_assisted_listening_stream( |
| const struct bt_audio_codec_cap *codec_cap) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_assisted_listening_stream(codec_cap->meta, codec_cap->meta_len); |
| } |
| |
| int bt_audio_codec_cap_meta_set_assisted_listening_stream( |
| struct bt_audio_codec_cap *codec_cap, enum bt_audio_assisted_listening_stream val) |
| { |
| int ret; |
| |
| ret = codec_meta_set_assisted_listening_stream(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), val); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_cap, |
| const uint8_t **extended_meta) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_extended(codec_cap->meta, codec_cap->meta_len, extended_meta); |
| } |
| |
| int bt_audio_codec_cap_meta_set_extended(struct bt_audio_codec_cap *codec_cap, |
| const uint8_t *extended_meta, size_t extended_meta_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_extended(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), extended_meta, |
| extended_meta_len); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_cap, |
| const uint8_t **vendor_meta) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_vendor(codec_cap->meta, codec_cap->meta_len, vendor_meta); |
| } |
| |
| int bt_audio_codec_cap_meta_set_vendor(struct bt_audio_codec_cap *codec_cap, |
| const uint8_t *vendor_meta, size_t vendor_meta_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_vendor(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), vendor_meta, vendor_meta_len); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_meta_get_broadcast_name(const struct bt_audio_codec_cap *codec_cap, |
| const uint8_t **broadcast_name) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return codec_meta_get_broadcast_name(codec_cap->meta, codec_cap->meta_len, broadcast_name); |
| } |
| |
| int bt_audio_codec_cap_meta_set_broadcast_name(struct bt_audio_codec_cap *codec_cap, |
| const uint8_t *broadcast_name, |
| size_t broadcast_name_len) |
| { |
| int ret; |
| |
| ret = codec_meta_set_broadcast_name(codec_cap->meta, codec_cap->meta_len, |
| ARRAY_SIZE(codec_cap->meta), broadcast_name, |
| broadcast_name_len); |
| if (ret >= 0) { |
| codec_cap->meta_len = ret; |
| } |
| |
| return ret; |
| } |
| #endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 */ |
| #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ |
| * CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 \ |
| */ |
| |
| #if CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 |
| |
| static void init_net_buf_simple_from_codec_cap(struct net_buf_simple *buf, |
| struct bt_audio_codec_cap *codec_cap) |
| { |
| buf->__buf = codec_cap->data; |
| buf->data = codec_cap->data; |
| buf->size = sizeof(codec_cap->data); |
| buf->len = codec_cap->data_len; |
| } |
| |
| int bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, |
| enum bt_audio_codec_cap_type type, const uint8_t **data) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(data == NULL) { |
| LOG_DBG("data is NULL"); |
| return -EINVAL; |
| } |
| |
| return bt_audio_data_get_val(codec_cap->data, codec_cap->data_len, (uint8_t)type, data); |
| } |
| |
| int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, |
| enum bt_audio_codec_cap_type type, const uint8_t *data, |
| size_t data_len) |
| { |
| struct net_buf_simple buf; |
| int ret; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(data == NULL) { |
| LOG_DBG("data is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(data_len == 0U || data_len > UINT8_MAX) { |
| LOG_DBG("Invalid data_len %zu", data_len); |
| return -EINVAL; |
| } |
| |
| init_net_buf_simple_from_codec_cap(&buf, codec_cap); |
| |
| ret = ltv_set_val(&buf, type, data, data_len); |
| if (ret >= 0) { |
| codec_cap->data_len = ret; |
| } |
| |
| return ret; |
| } |
| |
| int bt_audio_codec_cap_unset_val(struct bt_audio_codec_cap *codec_cap, |
| enum bt_audio_codec_cap_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; |
| uint8_t data_len; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| data_len = bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FREQ, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (data_len != sizeof(uint16_t)) { |
| return -EBADMSG; |
| } |
| |
| return sys_get_le16(data); |
| } |
| |
| int bt_audio_codec_cap_set_freq(struct bt_audio_codec_cap *codec_cap, |
| enum bt_audio_codec_cap_freq freq) |
| { |
| uint16_t freq_le16; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| if ((freq & BT_AUDIO_CODEC_CAP_FREQ_ANY) != freq) { |
| LOG_DBG("Invalid freq value: %d", freq); |
| return -EINVAL; |
| } |
| |
| freq_le16 = sys_cpu_to_le16((uint16_t)freq); |
| |
| return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FREQ, |
| (uint8_t *)&freq_le16, sizeof(freq_le16)); |
| } |
| |
| int bt_audio_codec_cap_get_frame_dur(const struct bt_audio_codec_cap *codec_cap) |
| { |
| const uint8_t *data; |
| uint8_t data_len; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| data_len = bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_DURATION, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (data_len != sizeof(uint8_t)) { |
| return -EBADMSG; |
| } |
| |
| return data[0]; |
| } |
| |
| int bt_audio_codec_cap_set_frame_dur(struct bt_audio_codec_cap *codec_cap, |
| enum bt_audio_codec_cap_frame_dur frame_dur) |
| { |
| uint8_t frame_dur_u8; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_ANY) == 0) { |
| LOG_DBG("Invalid frame_dur value: %d", frame_dur); |
| return -EINVAL; |
| } |
| |
| if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_PREFER_7_5) != 0) { |
| if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_PREFER_10) != 0) { |
| LOG_DBG("Cannot prefer both 7.5 and 10ms: %d", frame_dur); |
| return -EINVAL; |
| } |
| |
| if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_7_5) == 0) { |
| LOG_DBG("Cannot prefer 7.5ms when not supported: %d", frame_dur); |
| return -EINVAL; |
| } |
| } |
| |
| if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_PREFER_10) != 0 && |
| (frame_dur & BT_AUDIO_CODEC_CAP_DURATION_10) == 0) { |
| LOG_DBG("Cannot prefer 10ms when not supported: %d", frame_dur); |
| return -EINVAL; |
| } |
| |
| frame_dur_u8 = (uint8_t)frame_dur; |
| |
| return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_DURATION, |
| &frame_dur_u8, sizeof(frame_dur_u8)); |
| } |
| |
| int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_codec_cap *codec_cap, |
| bool fallback_to_default) |
| { |
| const uint8_t *data; |
| uint8_t data_len; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| data_len = bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT, &data); |
| if (data == NULL) { |
| if (fallback_to_default && codec_cap->id == BT_HCI_CODING_FORMAT_LC3) { |
| return 1; |
| } |
| |
| return -ENODATA; |
| } |
| |
| if (data_len != sizeof(uint8_t)) { |
| return -EBADMSG; |
| } |
| |
| return data[0]; |
| } |
| |
| int bt_audio_codec_cap_set_supported_audio_chan_counts( |
| struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_cap_chan_count chan_count) |
| { |
| uint8_t chan_count_u8; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| if ((chan_count & BT_AUDIO_CODEC_CAP_CHAN_COUNT_ANY) != chan_count) { |
| LOG_DBG("Invalid chan_count value: %d", chan_count); |
| return -EINVAL; |
| } |
| |
| chan_count_u8 = (uint8_t)chan_count; |
| |
| return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT, |
| &chan_count_u8, sizeof(chan_count_u8)); |
| } |
| |
| int bt_audio_codec_cap_get_octets_per_frame( |
| const struct bt_audio_codec_cap *codec_cap, |
| struct bt_audio_codec_octets_per_codec_frame *codec_frame) |
| { |
| const uint8_t *data; |
| uint8_t data_len; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(codec_frame == NULL) { |
| LOG_DBG("codec_frame is NULL"); |
| return -EINVAL; |
| } |
| |
| data_len = bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FRAME_LEN, &data); |
| if (data == NULL) { |
| return -ENODATA; |
| } |
| |
| if (data_len != sizeof(uint32_t)) { |
| return -EBADMSG; |
| } |
| |
| codec_frame->min = sys_get_le16(data); |
| codec_frame->max = sys_get_le16(data + sizeof(codec_frame->min)); |
| |
| return 0; |
| } |
| |
| int bt_audio_codec_cap_set_octets_per_frame( |
| struct bt_audio_codec_cap *codec_cap, |
| const struct bt_audio_codec_octets_per_codec_frame *codec_frame) |
| { |
| uint8_t codec_frame_le32[4]; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(codec_frame == NULL) { |
| LOG_DBG("codec_frame is NULL"); |
| return -EINVAL; |
| } |
| |
| if (codec_frame->min > codec_frame->max) { |
| LOG_DBG("Invalid codec_frame values: %u/%u", codec_frame->min, codec_frame->max); |
| return -EINVAL; |
| } |
| |
| sys_put_le16(codec_frame->min, codec_frame_le32); |
| sys_put_le16(codec_frame->max, codec_frame_le32 + 2); |
| |
| return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FRAME_LEN, |
| codec_frame_le32, sizeof(codec_frame_le32)); |
| } |
| |
| int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_cap *codec_cap, |
| bool fallback_to_default) |
| { |
| const uint8_t *data; |
| uint8_t data_len; |
| |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| data_len = |
| bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FRAME_COUNT, &data); |
| if (data == NULL) { |
| if (fallback_to_default && codec_cap->id == BT_HCI_CODING_FORMAT_LC3) { |
| return 1; |
| } |
| |
| return -ENODATA; |
| } |
| |
| if (data_len != sizeof(uint8_t)) { |
| return -EBADMSG; |
| } |
| |
| return data[0]; |
| } |
| |
| int bt_audio_codec_cap_set_max_codec_frames_per_sdu(struct bt_audio_codec_cap *codec_cap, |
| uint8_t codec_frames_per_sdu) |
| { |
| CHECKIF(codec_cap == NULL) { |
| LOG_DBG("codec_cap is NULL"); |
| return -EINVAL; |
| } |
| |
| return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FRAME_COUNT, |
| &codec_frames_per_sdu, sizeof(codec_frames_per_sdu)); |
| } |
| |
| #endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 */ |