1 /*
2  * Copyright (c) 2022 Bose Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 /** @file
7  *  @brief Bluetooth LE-Audio codec LTV parsing
8  *
9  *  Helper functions to parse codec config data as specified in the Bluetooth assigned numbers for
10  *  Generic Audio.
11  */
12 
13 #include <zephyr/bluetooth/audio/audio.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/sys/check.h>
16 
17 #include <zephyr/logging/log.h>
18 
19 LOG_MODULE_REGISTER(bt_audio_codec, CONFIG_BT_AUDIO_CODEC_LOG_LEVEL);
20 
bt_codec_get_val(const struct bt_codec * codec,uint8_t type,const struct bt_codec_data ** data)21 bool bt_codec_get_val(const struct bt_codec *codec,
22 		      uint8_t type,
23 		      const struct bt_codec_data **data)
24 {
25 	CHECKIF(codec == NULL) {
26 		LOG_DBG("codec is NULL");
27 		return false;
28 	}
29 
30 	for (size_t i = 0; i < codec->data_count; i++) {
31 		if (codec->data[i].data.type == type) {
32 			*data = &codec->data[i];
33 
34 			return true;
35 		}
36 	}
37 
38 	return false;
39 }
40 
bt_codec_cfg_get_freq(const struct bt_codec * codec)41 int bt_codec_cfg_get_freq(const struct bt_codec *codec)
42 {
43 	const struct bt_codec_data *element;
44 
45 	CHECKIF(codec == NULL) {
46 		LOG_DBG("codec is NULL");
47 		return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
48 	}
49 
50 	if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_FREQ, &element)) {
51 
52 		switch (element->data.data[0]) {
53 		case BT_CODEC_CONFIG_LC3_FREQ_8KHZ:
54 			return 8000;
55 		case BT_CODEC_CONFIG_LC3_FREQ_11KHZ:
56 			return 11025;
57 		case BT_CODEC_CONFIG_LC3_FREQ_16KHZ:
58 			return 16000;
59 		case BT_CODEC_CONFIG_LC3_FREQ_22KHZ:
60 			return 22050;
61 		case BT_CODEC_CONFIG_LC3_FREQ_24KHZ:
62 			return 24000;
63 		case BT_CODEC_CONFIG_LC3_FREQ_32KHZ:
64 			return 32000;
65 		case BT_CODEC_CONFIG_LC3_FREQ_44KHZ:
66 			return 44100;
67 		case BT_CODEC_CONFIG_LC3_FREQ_48KHZ:
68 			return 48000;
69 		case BT_CODEC_CONFIG_LC3_FREQ_88KHZ:
70 			return 88200;
71 		case BT_CODEC_CONFIG_LC3_FREQ_96KHZ:
72 			return 96000;
73 		case BT_CODEC_CONFIG_LC3_FREQ_176KHZ:
74 			return 176400;
75 		case BT_CODEC_CONFIG_LC3_FREQ_192KHZ:
76 			return 192000;
77 		case BT_CODEC_CONFIG_LC3_FREQ_384KHZ:
78 			return 384000;
79 		default:
80 			return BT_AUDIO_CODEC_PARSE_ERR_INVALID_VALUE_FOUND;
81 		}
82 	}
83 
84 	return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND;
85 }
86 
bt_codec_cfg_get_frame_duration_us(const struct bt_codec * codec)87 int bt_codec_cfg_get_frame_duration_us(const struct bt_codec *codec)
88 {
89 	const struct bt_codec_data *element;
90 
91 	CHECKIF(codec == NULL) {
92 		LOG_DBG("codec is NULL");
93 		return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
94 	}
95 
96 	if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_DURATION, &element)) {
97 		switch (element->data.data[0]) {
98 		case BT_CODEC_CONFIG_LC3_DURATION_7_5:
99 			return 7500;
100 		case BT_CODEC_CONFIG_LC3_DURATION_10:
101 			return 10000;
102 		default:
103 			return BT_AUDIO_CODEC_PARSE_ERR_INVALID_VALUE_FOUND;
104 		}
105 	}
106 
107 	return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND;
108 }
109 
bt_codec_cfg_get_chan_allocation_val(const struct bt_codec * codec,enum bt_audio_location * chan_allocation)110 int bt_codec_cfg_get_chan_allocation_val(const struct bt_codec *codec,
111 					 enum bt_audio_location *chan_allocation)
112 {
113 	const struct bt_codec_data *element;
114 
115 	CHECKIF(codec == NULL) {
116 		LOG_DBG("codec is NULL");
117 		return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
118 	}
119 
120 	CHECKIF(chan_allocation == NULL) {
121 		return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
122 	}
123 
124 	*chan_allocation = 0;
125 	if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_CHAN_ALLOC, &element)) {
126 
127 		*chan_allocation = sys_le32_to_cpu(*((uint32_t *)&element->data.data[0]));
128 
129 		return BT_AUDIO_CODEC_PARSE_ERR_SUCCESS;
130 	}
131 
132 	return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND;
133 }
134 
bt_codec_cfg_get_octets_per_frame(const struct bt_codec * codec)135 int bt_codec_cfg_get_octets_per_frame(const struct bt_codec *codec)
136 {
137 	const struct bt_codec_data *element;
138 
139 	CHECKIF(codec == NULL) {
140 		LOG_DBG("codec is NULL");
141 		return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
142 	}
143 
144 	if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_FRAME_LEN, &element)) {
145 
146 		return sys_le16_to_cpu(*((uint16_t *)&element->data.data[0]));
147 	}
148 
149 	return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND;
150 }
151 
bt_codec_cfg_get_frame_blocks_per_sdu(const struct bt_codec * codec,bool fallback_to_default)152 int bt_codec_cfg_get_frame_blocks_per_sdu(const struct bt_codec *codec, bool fallback_to_default)
153 {
154 	const struct bt_codec_data *element;
155 
156 	CHECKIF(codec == NULL) {
157 		LOG_DBG("codec is NULL");
158 		return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
159 	}
160 
161 	if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU, &element)) {
162 
163 		return element->data.data[0];
164 	}
165 
166 	if (fallback_to_default) {
167 
168 		return 1;
169 	}
170 
171 	return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND;
172 }
173