1 /*
2 * Copyright (C) 2022 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 #define BTSTACK_FILE__ "le_audio_util.c"
39
40 #include "btstack_util.h"
41 #include "btstack_debug.h"
42 #include "le-audio/le_audio_util.h"
43 #include "btstack_event.h"
44
45
46 static const le_audio_codec_configuration_t codec_specific_config_settings[] = {
47 {"8_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 26},
48 {"8_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 30},
49 {"16_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 30},
50 {"16_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 40},
51 {"24_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 45},
52 {"24_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 60},
53 {"32_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 60},
54 {"32_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 80},
55 {"441_1",LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 97},
56 {"441_2",LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 130},
57 {"48_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 75},
58 {"48_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 100},
59 {"48_3", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 90},
60 {"48_4", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 120},
61 {"48_5", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 117},
62 {"48_6", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 155},
63 };
64
65 static const le_audio_qos_configuration_t qos_config_settings[] = {
66 {"8_1_1", 7500, 0, 26, 2, 8},
67 {"8_2_1", 10000, 0, 30, 2, 10},
68 {"16_1_1", 7500, 0, 30, 2, 8},
69 {"16_2_1", 10000, 0, 40, 2, 10},
70 {"24_1_1", 7500, 0, 45, 2, 8},
71 {"24_2_1", 10000, 0, 60, 2, 10},
72 {"32_1_1", 7500, 0, 60, 2, 8},
73 {"32_2_1", 10000, 0, 80, 2, 10},
74 {"441_1_1", 8163, 1, 97, 5, 24},
75 {"441_2_1", 10884, 1, 130, 5, 31},
76 {"48_1_1", 7500, 0, 75, 5, 15},
77 {"48_2_1", 10000, 0, 100, 5, 20},
78 {"48_3_1", 7500, 0, 90, 5, 15},
79 {"48_4_1", 10000, 0, 120, 5, 20},
80 {"48_5_1", 7500, 0, 117, 5, 15},
81 {"48_6_1", 10000, 0, 115, 5, 20},
82
83 {"8_1_2", 7500, 0, 26, 13, 75},
84 {"8_2_2", 10000, 0, 30, 13, 95},
85 {"16_1_2", 7500, 0, 30, 13, 75},
86 {"16_2_2", 10000, 0, 40, 13, 95},
87 {"24_1_2", 7500, 0, 45, 13, 75},
88 {"24_2_2", 10000, 0, 60, 13, 95},
89 {"32_1_2", 7500, 0, 60, 13, 75},
90 {"32_2_2", 10000, 0, 80, 13, 95},
91 {"441_1_2", 8163, 1, 97, 13, 80},
92 {"441_2_2", 10884, 1, 130, 13, 85},
93 {"48_1_2", 7500, 0, 75, 13, 75},
94 {"48_2_2", 10000, 0, 100, 13, 95},
95 {"48_3_2", 7500, 0, 90, 13, 75},
96 {"48_4_2", 10000, 0, 120, 13, 100},
97 {"48_5_2", 7500, 0, 117, 13, 75},
98 {"48_6_2", 10000, 0, 115, 13, 100}
99 };
100
codec_offset(le_audio_codec_sampling_frequency_index_t sampling_frequency_index,le_audio_codec_frame_duration_index_t frame_duration_index,le_audio_quality_t audio_quality)101 static uint8_t codec_offset(le_audio_codec_sampling_frequency_index_t sampling_frequency_index,
102 le_audio_codec_frame_duration_index_t frame_duration_index,
103 le_audio_quality_t audio_quality){
104
105 btstack_assert(audio_quality <= LE_AUDIO_QUALITY_HIGH);
106
107 if (sampling_frequency_index == LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ){
108 return 10 + (audio_quality - LE_AUDIO_QUALITY_LOW) * 2 + (frame_duration_index - LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US);
109 }
110 return (sampling_frequency_index - LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ) * 2 + (frame_duration_index - LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US);
111 }
112
le_audio_util_get_codec_setting(le_audio_codec_sampling_frequency_index_t sampling_frequency_index,le_audio_codec_frame_duration_index_t frame_duration_index,le_audio_quality_t audio_quality)113 const le_audio_codec_configuration_t * le_audio_util_get_codec_setting(
114 le_audio_codec_sampling_frequency_index_t sampling_frequency_index,
115 le_audio_codec_frame_duration_index_t frame_duration_index,
116 le_audio_quality_t audio_quality){
117
118 return &codec_specific_config_settings[codec_offset(sampling_frequency_index, frame_duration_index, audio_quality)];
119 }
120
le_audio_util_get_qos_setting(le_audio_codec_sampling_frequency_index_t sampling_frequency_index,le_audio_codec_frame_duration_index_t frame_duration_index,le_audio_quality_t audio_quality,uint8_t num_channels)121 const le_audio_qos_configuration_t * le_audio_util_get_qos_setting(
122 le_audio_codec_sampling_frequency_index_t sampling_frequency_index,
123 le_audio_codec_frame_duration_index_t frame_duration_index,
124 le_audio_quality_t audio_quality, uint8_t num_channels){
125
126 btstack_assert((num_channels >= 1) && (num_channels <= 2));
127
128 return &qos_config_settings[(num_channels - 1) * 16 + codec_offset(sampling_frequency_index, frame_duration_index, audio_quality)];
129 }
130
131
132 // help with buffer == NULL
le_audio_util_virtual_memcpy_helper(const uint8_t * field_data,uint16_t field_len,uint16_t field_offset,uint8_t * buffer,uint16_t buffer_size,uint16_t buffer_offset)133 uint16_t le_audio_util_virtual_memcpy_helper(
134 const uint8_t * field_data, uint16_t field_len, uint16_t field_offset,
135 uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset){
136
137 // only calc total size
138 if (buffer == NULL) {
139 return field_len;
140 }
141 return btstack_virtual_memcpy(field_data, field_len, field_offset, buffer, buffer_size, buffer_offset);
142 }
143
le_audio_util_metadata_virtual_memcpy(const le_audio_metadata_t * metadata,uint8_t metadata_length,uint16_t * records_offset,uint8_t * buffer,uint16_t buffer_size,uint16_t buffer_offset)144 uint16_t le_audio_util_metadata_virtual_memcpy(const le_audio_metadata_t * metadata, uint8_t metadata_length, uint16_t * records_offset, uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset){
145 uint16_t metadata_type;
146 uint8_t field_data[7];
147 uint16_t stored_bytes = 0;
148
149 uint16_t metadata_length_pos = *records_offset;
150 field_data[0] = 0;
151 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, *records_offset, buffer, buffer_size,
152 buffer_offset);
153 *records_offset += 1;
154
155 if (metadata_length == 0){
156 return stored_bytes;
157 }
158
159 for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
160 if ((metadata->metadata_mask & (1 << metadata_type) ) != 0 ){
161 // reserve field_data[0] for num butes to store
162 field_data[0] = 1;
163 field_data[1] = metadata_type;
164
165 switch ((le_audio_metadata_type_t)metadata_type){
166 case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
167 field_data[0] += 2;
168 little_endian_store_16(field_data, 2, metadata->preferred_audio_contexts_mask);
169 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
170 buffer, buffer_size, buffer_offset);
171 *records_offset += field_data[0] + 1;
172 break;
173 case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
174 field_data[0] += 2;
175 little_endian_store_16(field_data, 2, metadata->streaming_audio_contexts_mask);
176 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
177 buffer, buffer_size, buffer_offset);
178 *records_offset += field_data[0] + 1;
179 break;
180 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
181 field_data[0] += metadata->program_info_length;
182 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, *records_offset, buffer,
183 buffer_size, buffer_offset);
184 *records_offset += 2;
185 stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->program_info,
186 metadata->program_info_length, *records_offset,
187 buffer, buffer_size, buffer_offset);
188 *records_offset += metadata->program_info_length;
189 break;
190 case LE_AUDIO_METADATA_TYPE_LANGUAGE:
191 field_data[0] += 3;
192 little_endian_store_24(field_data, 2, metadata->language_code);
193 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
194 buffer, buffer_size, buffer_offset);
195 *records_offset += field_data[0] + 1;
196 break;
197 case LE_AUDIO_METADATA_TYPE_CCID_LIST:
198 field_data[0] += metadata->ccids_num;
199 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, *records_offset, buffer,
200 buffer_size, buffer_offset);
201 *records_offset += 2;
202 stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->ccids, metadata->ccids_num,
203 *records_offset, buffer, buffer_size,
204 buffer_offset);
205 *records_offset += metadata->ccids_num;
206 break;
207 case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
208 field_data[0] += 1;
209 field_data[2] = (uint8_t) metadata->parental_rating;
210 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
211 buffer, buffer_size, buffer_offset);
212 *records_offset += field_data[0] + 1;
213 break;
214 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
215 field_data[0] += metadata->program_info_uri_length;
216 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, *records_offset, buffer,
217 buffer_size, buffer_offset);
218 *records_offset += 2;
219 stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->program_info_uri,
220 metadata->program_info_uri_length,
221 *records_offset, buffer, buffer_size,
222 buffer_offset);
223 *records_offset += metadata->program_info_uri_length;
224 break;
225 case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
226 field_data[0] += 2 + metadata->extended_metadata_length;
227 field_data[1] = LE_AUDIO_METADATA_TYPE_EXTENDED_METADATA;
228 little_endian_store_16(field_data, 2, metadata->extended_metadata_type);
229 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 4, *records_offset, buffer,
230 buffer_size, buffer_offset);
231 *records_offset += 4;
232 stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->extended_metadata,
233 metadata->extended_metadata_length,
234 *records_offset, buffer, buffer_size,
235 buffer_offset);
236 *records_offset += metadata->extended_metadata_length;
237 break;
238 case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
239 field_data[0] += 2 + metadata->vendor_specific_metadata_length;
240 field_data[1] = LE_AUDIO_METADATA_TYPE_VENDOR_SPECIFIC_METADATA;
241 little_endian_store_16(field_data, 2, metadata->vendor_specific_company_id);
242 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 4, *records_offset, buffer,
243 buffer_size, buffer_offset);
244 *records_offset += 4;
245 stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->vendor_specific_metadata,
246 metadata->vendor_specific_metadata_length,
247 *records_offset, buffer, buffer_size,
248 buffer_offset);
249 *records_offset += metadata->vendor_specific_metadata_length;
250 break;
251 default:
252 btstack_assert(false);
253 break;
254 }
255 }
256 }
257
258 field_data[0] = *records_offset - metadata_length_pos - 1;
259 le_audio_util_virtual_memcpy_helper(field_data, 1, metadata_length_pos, buffer, buffer_size, buffer_offset);
260 return stored_bytes;
261 }
262
263 // parse metadata, first unsupported type is stored in metadata.unsupported_type
le_audio_util_metadata_parse(const uint8_t * buffer,uint8_t buffer_size,le_audio_metadata_t * metadata)264 uint16_t le_audio_util_metadata_parse(const uint8_t *buffer, uint8_t buffer_size, le_audio_metadata_t * metadata){
265
266 // reset capabilities
267 memset(metadata, 0, sizeof(le_audio_metadata_t));
268
269 // parse config to get sampling frequency and frame duration
270 uint8_t offset = 0;
271 uint8_t metadata_config_length = buffer[offset++];
272 if (buffer_size < metadata_config_length){
273 return 0;
274 }
275
276 metadata->metadata_mask = 0;
277
278 while ((offset + 1) < metadata_config_length){
279 uint8_t ltv_len = buffer[offset++];
280
281 le_audio_metadata_type_t ltv_type = (le_audio_metadata_type_t)buffer[offset];
282 le_audio_parental_rating_t parental_rating;
283
284 switch (ltv_type){
285 case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
286 metadata->preferred_audio_contexts_mask = little_endian_read_16(buffer, offset+1);
287 metadata->metadata_mask |= (1 << ltv_type);
288 break;
289 case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
290 metadata->streaming_audio_contexts_mask = little_endian_read_16(buffer, offset+1);
291 metadata->metadata_mask |= (1 << ltv_type);
292 break;
293 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
294 metadata->program_info_length = btstack_min(ltv_len, LE_AUDIO_PROGRAM_INFO_MAX_LENGTH);
295 memcpy(metadata->program_info, &buffer[offset+1], metadata->program_info_length);
296 metadata->metadata_mask |= (1 << ltv_type);
297 break;
298 case LE_AUDIO_METADATA_TYPE_LANGUAGE:
299 metadata->language_code = little_endian_read_24(buffer, offset+1);
300 metadata->metadata_mask |= (1 << ltv_type);
301 break;
302 case LE_AUDIO_METADATA_TYPE_CCID_LIST:
303 if (ltv_len > 1){
304 metadata->ccids_num = btstack_min(ltv_len - 1, LE_CCIDS_MAX_NUM);
305 memcpy(metadata->ccids, &buffer[offset+1], metadata->ccids_num);
306 metadata->metadata_mask |= (1 << ltv_type);
307 }
308 break;
309 case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
310 parental_rating = (le_audio_parental_rating_t)buffer[offset+1];
311 metadata->parental_rating = parental_rating;
312 metadata->metadata_mask |= (1 << ltv_type);
313 break;
314 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
315 metadata->program_info_uri_length = btstack_min(ltv_len, LE_AUDIO_PROGRAM_INFO_URI_MAX_LENGTH);
316 memcpy(metadata->program_info_uri, &buffer[offset+1], metadata->program_info_uri_length);
317 metadata->metadata_mask |= (1 << ltv_type);
318 break;
319 case LE_AUDIO_METADATA_TYPE_EXTENDED_METADATA:
320 if (ltv_len < 2){
321 break;
322 }
323 metadata->extended_metadata_length = btstack_min(ltv_len - 2, LE_AUDIO_EXTENDED_METADATA_MAX_LENGHT);
324 metadata->extended_metadata_type = little_endian_read_16(buffer, offset+1);
325 memcpy(metadata->extended_metadata, &buffer[offset+3], metadata->extended_metadata_length);
326 metadata->metadata_mask |= (1 << LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION);
327 break;
328 case LE_AUDIO_METADATA_TYPE_VENDOR_SPECIFIC_METADATA:
329 if (ltv_len < 2){
330 break;
331 }
332 metadata->vendor_specific_metadata_length = btstack_min(ltv_len - 2, LE_AUDIO_VENDOR_SPECIFIC_METADATA_MAX_LENGTH);
333 metadata->vendor_specific_company_id = little_endian_read_16(buffer, offset+1);
334 memcpy(metadata->vendor_specific_metadata, &buffer[offset+3], metadata->vendor_specific_metadata_length);
335 metadata->metadata_mask |= (1 << LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION);
336 break;
337 default:
338 metadata->metadata_mask |= (1 << LE_AUDIO_METADATA_TYPE_RFU);
339 metadata->unsupported_type = ltv_type;
340 break;
341 }
342 offset += ltv_len;
343 }
344 return offset;
345 }
346
le_audio_util_metadata_serialize(const le_audio_metadata_t * metadata,uint8_t * event,uint16_t event_size)347 uint16_t le_audio_util_metadata_serialize(const le_audio_metadata_t *metadata, uint8_t * event, uint16_t event_size){
348 UNUSED(event_size);
349
350 uint8_t pos = 0;
351
352 event[pos++] = (uint8_t)metadata->metadata_mask;
353 little_endian_store_16(event, pos, metadata->preferred_audio_contexts_mask);
354 pos += 2;
355 little_endian_store_16(event, pos, metadata->streaming_audio_contexts_mask);
356 pos += 2;
357
358 event[pos++] = metadata->program_info_length;
359 memcpy(&event[pos], &metadata->program_info[0], metadata->program_info_length);
360 pos += metadata->program_info_length;
361
362 little_endian_store_24(event, pos, metadata->language_code);
363 pos += 3;
364
365 event[pos++] = metadata->ccids_num;
366 memcpy(&event[pos], &metadata->ccids[0], metadata->ccids_num);
367 pos += metadata->ccids_num;
368
369 event[pos++] = (uint8_t)metadata->parental_rating;
370
371 event[pos++] = metadata->program_info_uri_length;
372 memcpy(&event[pos], &metadata->program_info_uri[0], metadata->program_info_uri_length);
373 pos += metadata->program_info_uri_length;
374
375 little_endian_store_16(event, pos, metadata->extended_metadata_type);
376 pos += 2;
377
378 event[pos++] = metadata->extended_metadata_length;
379 memcpy(&event[pos], &metadata->extended_metadata[0], metadata->extended_metadata_length);
380 pos += metadata->extended_metadata_length;
381
382 little_endian_store_16(event, pos, metadata->vendor_specific_company_id);
383 pos += 2;
384
385 event[pos++] = metadata->vendor_specific_metadata_length;
386 memcpy(&event[pos], &metadata->vendor_specific_metadata[0], metadata->vendor_specific_metadata_length);
387 pos += metadata->vendor_specific_metadata_length;
388
389 return pos;
390 }
391
le_audio_util_get_value_size_for_metadata_type(const le_audio_metadata_t * metadata,le_audio_metadata_type_t metadata_type)392 static uint16_t le_audio_util_get_value_size_for_metadata_type(const le_audio_metadata_t *metadata, le_audio_metadata_type_t metadata_type){
393 switch (metadata_type){
394 case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
395 case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
396 return 2;
397
398 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
399 return metadata->program_info_length;
400
401 case LE_AUDIO_METADATA_TYPE_LANGUAGE:
402 return 3;
403
404 case LE_AUDIO_METADATA_TYPE_CCID_LIST:
405 return metadata->ccids_num;
406
407 case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
408 return 1;
409
410 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
411 return metadata->program_info_uri_length;
412
413 case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
414 return 2 + metadata->extended_metadata_length;
415
416 case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
417 return 2 + metadata->vendor_specific_metadata_length;
418 default:
419 break;
420 }
421 return 0;
422 }
423
le_audio_util_metadata_serialize_using_mask(const le_audio_metadata_t * metadata,uint8_t * tlv_buffer,uint16_t tlv_buffer_size)424 uint16_t le_audio_util_metadata_serialize_using_mask(const le_audio_metadata_t *metadata, uint8_t * tlv_buffer, uint16_t tlv_buffer_size){
425 uint16_t metadata_type;
426 uint16_t pos = 0;
427
428 uint16_t remaining_bytes = tlv_buffer_size;
429
430 for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
431 if ((metadata->metadata_mask & (1 << metadata_type)) == 0){
432 continue;
433 }
434
435 uint8_t payload_length = le_audio_util_get_value_size_for_metadata_type(metadata, (le_audio_metadata_type_t)metadata_type);
436 // ensure that there is enough space in TLV to store length (1), type(1) and payload
437 if (remaining_bytes < (2 + payload_length)){
438 return pos;
439 }
440
441 tlv_buffer[pos++] = 1 + payload_length; // add one extra byte to count size of type (1 byte)
442 tlv_buffer[pos++] = metadata_type;
443
444 switch ((le_audio_metadata_type_t)metadata_type){
445 case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
446 little_endian_store_16(tlv_buffer, pos, metadata->preferred_audio_contexts_mask);
447 break;
448 case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
449 little_endian_store_16(tlv_buffer, pos, metadata->streaming_audio_contexts_mask);
450 break;
451 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
452 memcpy(&tlv_buffer[pos], metadata->program_info, metadata->program_info_length);
453 break;
454 case LE_AUDIO_METADATA_TYPE_LANGUAGE:
455 little_endian_store_24(tlv_buffer, pos, metadata->language_code);
456 break;
457 case LE_AUDIO_METADATA_TYPE_CCID_LIST:
458 memcpy(&tlv_buffer[pos], metadata->ccids, metadata->ccids_num);
459 break;
460 case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
461 break;
462 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
463 memcpy(&tlv_buffer[pos], metadata->program_info_uri, metadata->program_info_uri_length);
464 break;
465 case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
466 little_endian_store_16(tlv_buffer, pos, metadata->extended_metadata_type);
467 memcpy(&tlv_buffer[pos + 2], metadata->extended_metadata, metadata->extended_metadata_length);
468 break;
469 case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
470 little_endian_store_16(tlv_buffer, pos, metadata->vendor_specific_company_id);
471 memcpy(&tlv_buffer[pos + 2], metadata->vendor_specific_metadata, metadata->vendor_specific_metadata_length);
472 break;
473 default:
474 break;
475 }
476 pos += payload_length;
477 remaining_bytes -= (payload_length + 2);
478 }
479 return pos;
480 }
481
le_audio_util_get_btstack_lc3_frame_duration(le_audio_codec_frame_duration_index_t frame_duration_index)482 btstack_lc3_frame_duration_t le_audio_util_get_btstack_lc3_frame_duration(le_audio_codec_frame_duration_index_t frame_duration_index){
483 switch (frame_duration_index){
484 case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US:
485 return BTSTACK_LC3_FRAME_DURATION_7500US;
486 case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US:
487 return BTSTACK_LC3_FRAME_DURATION_10000US;
488 default:
489 btstack_assert(false);
490 break;
491 }
492 return 0;
493 }
494
le_audio_get_frame_duration_us(le_audio_codec_frame_duration_index_t frame_duration_index)495 uint16_t le_audio_get_frame_duration_us(le_audio_codec_frame_duration_index_t frame_duration_index){
496 switch (frame_duration_index){
497 case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US:
498 return 7500;
499 case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US:
500 return 10000;
501 default:
502 return 0;
503 }
504 }
505
le_audio_get_frame_duration_index(uint16_t frame_duration_us)506 le_audio_codec_frame_duration_index_t le_audio_get_frame_duration_index(uint16_t frame_duration_us){
507 switch (frame_duration_us){
508 case 7500:
509 return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US;
510 case 10000:
511 return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US;
512 default:
513 return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_RFU;
514 }
515 }
516
le_audio_get_sampling_frequency_hz(le_audio_codec_sampling_frequency_index_t sampling_frequency_index)517 uint32_t le_audio_get_sampling_frequency_hz(le_audio_codec_sampling_frequency_index_t sampling_frequency_index){
518 switch (sampling_frequency_index){
519 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ:
520 return 8000;
521 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_11025_HZ:
522 return 11025;
523 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ:
524 return 16000;
525 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_22050_HZ:
526 return 22050;
527 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ:
528 return 24000;
529 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ:
530 return 32000;
531 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ:
532 return 44100;
533 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ:
534 return 48000;
535 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_88200_HZ:
536 return 88200;
537 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_96000_HZ:
538 return 96000;
539 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_176400_HZ:
540 return 176400;
541 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_192000_HZ:
542 return 192000;
543 case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_384000_HZ:
544 return 384000;
545 default:
546 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_INVALID;
547 }
548 }
549
le_audio_get_sampling_frequency_index(uint32_t sampling_frequency_hz)550 le_audio_codec_sampling_frequency_index_t le_audio_get_sampling_frequency_index(uint32_t sampling_frequency_hz){
551 switch (sampling_frequency_hz){
552 case 0:
553 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_INVALID;
554 case 8000:
555 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ;
556 case 11025:
557 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_11025_HZ;
558 case 16000:
559 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ;
560 case 22050:
561 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_22050_HZ;
562 case 24000:
563 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ;
564 case 32000:
565 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ;
566 case 44100:
567 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ;
568 case 48000:
569 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ;
570 case 88200:
571 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_88200_HZ;
572 case 96000:
573 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_96000_HZ;
574 case 176400:
575 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_176400_HZ;
576 case 192000:
577 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_192000_HZ;
578 case 384000:
579 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_384000_HZ;
580 default:
581 return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_RFU;
582 }
583 }
584
le_audio_util_metadata_using_mask_from_metadata_event(const uint8_t * packet,uint16_t packet_size,le_audio_metadata_t * metadata_out)585 void le_audio_util_metadata_using_mask_from_metadata_event(const uint8_t * packet, uint16_t packet_size, le_audio_metadata_t * metadata_out){
586 UNUSED(packet_size);
587 btstack_assert(metadata_out != NULL);
588 if (packet_size == 0){
589 return;
590 }
591
592 memset(metadata_out, 0, sizeof(le_audio_metadata_t));
593 metadata_out->metadata_mask = leaudio_subevent_ascs_server_metadata_get_metadata_mask(packet);
594
595 uint16_t metadata_type;
596 for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
597 if ((metadata_out->metadata_mask & (1 << metadata_type) ) != 0 ){
598
599 switch ((le_audio_metadata_type_t)metadata_type){
600 case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
601 metadata_out->preferred_audio_contexts_mask = leaudio_subevent_ascs_server_metadata_get_preferred_audio_contexts_mask(packet);
602 break;
603
604 case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
605 metadata_out->streaming_audio_contexts_mask = leaudio_subevent_ascs_server_metadata_get_streaming_audio_contexts_mask(packet);
606 break;
607
608 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
609 metadata_out->program_info_length = leaudio_subevent_ascs_server_metadata_get_program_info_length(packet);
610 memcpy(metadata_out->program_info, leaudio_subevent_ascs_server_metadata_get_program_info(packet), metadata_out->program_info_length);
611 break;
612
613 case LE_AUDIO_METADATA_TYPE_LANGUAGE:
614 metadata_out->language_code = leaudio_subevent_ascs_server_metadata_get_language_code(packet);
615 break;
616
617 case LE_AUDIO_METADATA_TYPE_CCID_LIST:
618 metadata_out->ccids_num = leaudio_subevent_ascs_server_metadata_get_ccids_num(packet);
619 memcpy(metadata_out->ccids, leaudio_subevent_ascs_server_metadata_get_ccids(packet), metadata_out->ccids_num);
620 break;
621
622 case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
623 metadata_out->parental_rating = (le_audio_parental_rating_t)leaudio_subevent_ascs_server_metadata_get_parental_rating(packet);
624 break;
625
626 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
627 metadata_out->program_info_uri_length = leaudio_subevent_ascs_server_metadata_get_program_info_uri_length(packet);
628 memcpy(metadata_out->program_info_uri, leaudio_subevent_ascs_server_metadata_get_program_info_uri(packet), metadata_out->program_info_uri_length);
629 break;
630
631 case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
632 metadata_out->extended_metadata_type = leaudio_subevent_ascs_server_metadata_get_extended_metadata_type(packet);
633 metadata_out->extended_metadata_length = leaudio_subevent_ascs_server_metadata_get_extended_metadata_value_length(packet);
634 memcpy(metadata_out->extended_metadata, leaudio_subevent_ascs_server_metadata_get_extended_metadata_value(packet), metadata_out->extended_metadata_length);
635 break;
636
637 case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
638 metadata_out->vendor_specific_company_id = leaudio_subevent_ascs_server_metadata_get_vendor_specific_metadata_type(packet);
639 metadata_out->vendor_specific_metadata_length = leaudio_subevent_ascs_server_metadata_get_vendor_specific_metadata_value_length(packet);
640 memcpy(metadata_out->vendor_specific_metadata, leaudio_subevent_ascs_server_metadata_get_vendor_specific_metadata_value(packet), metadata_out->vendor_specific_metadata_length);
641 break;
642
643 default:
644 btstack_assert(false);
645 break;
646 }
647 }
648 }
649 }
650
le_audio_util_metadata_using_mask_from_enable_event(const uint8_t * packet,uint16_t packet_size,le_audio_metadata_t * metadata_out)651 void le_audio_util_metadata_using_mask_from_enable_event(const uint8_t * packet, uint16_t packet_size, le_audio_metadata_t * metadata_out){
652 UNUSED(packet_size);
653 btstack_assert(metadata_out != NULL);
654 if (packet_size == 0){
655 return;
656 }
657
658 memset(metadata_out, 0, sizeof(le_audio_metadata_t));
659 metadata_out->metadata_mask = leaudio_subevent_ascs_server_metadata_get_metadata_mask(packet);
660
661 uint16_t metadata_type;
662 for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
663 if ((metadata_out->metadata_mask & (1 << metadata_type) ) != 0 ){
664
665 switch ((le_audio_metadata_type_t)metadata_type){
666 case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
667 metadata_out->preferred_audio_contexts_mask = leaudio_subevent_ascs_server_enable_get_preferred_audio_contexts_mask(packet);
668 break;
669
670 case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
671 metadata_out->streaming_audio_contexts_mask = leaudio_subevent_ascs_server_enable_get_streaming_audio_contexts_mask(packet);
672 break;
673
674 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
675 metadata_out->program_info_length = leaudio_subevent_ascs_server_enable_get_program_info_length(packet);
676 memcpy(metadata_out->program_info, leaudio_subevent_ascs_server_enable_get_program_info(packet), metadata_out->program_info_length);
677 break;
678
679 case LE_AUDIO_METADATA_TYPE_LANGUAGE:
680 metadata_out->language_code = leaudio_subevent_ascs_server_enable_get_language_code(packet);
681 break;
682
683 case LE_AUDIO_METADATA_TYPE_CCID_LIST:
684 metadata_out->ccids_num = leaudio_subevent_ascs_server_enable_get_ccids_num(packet);
685 memcpy(metadata_out->ccids, leaudio_subevent_ascs_server_enable_get_ccids(packet), metadata_out->ccids_num);
686 break;
687
688 case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
689 metadata_out->parental_rating = (le_audio_parental_rating_t)leaudio_subevent_ascs_server_enable_get_parental_rating(packet);
690 break;
691
692 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
693 metadata_out->program_info_uri_length = leaudio_subevent_ascs_server_enable_get_program_info_uri_length(packet);
694 memcpy(metadata_out->program_info_uri, leaudio_subevent_ascs_server_enable_get_program_info_uri(packet), metadata_out->program_info_uri_length);
695 break;
696
697 case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
698 metadata_out->extended_metadata_type = leaudio_subevent_ascs_server_enable_get_extended_metadata_type(packet);
699 metadata_out->extended_metadata_length = leaudio_subevent_ascs_server_enable_get_extended_metadata_value_length(packet);
700 memcpy(metadata_out->extended_metadata, leaudio_subevent_ascs_server_enable_get_extended_metadata_value(packet), metadata_out->extended_metadata_length);
701 break;
702
703 case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
704 metadata_out->vendor_specific_company_id = leaudio_subevent_ascs_server_enable_get_vendor_specific_metadata_type(packet);
705 metadata_out->vendor_specific_metadata_length = leaudio_subevent_ascs_server_enable_get_vendor_specific_metadata_value_length(packet);
706 memcpy(metadata_out->vendor_specific_metadata, leaudio_subevent_ascs_server_enable_get_vendor_specific_metadata_value(packet), metadata_out->vendor_specific_metadata_length);
707 break;
708
709 default:
710 btstack_assert(false);
711 break;
712 }
713 }
714 }
715 }
716
717