xref: /btstack/src/le-audio/le_audio_util.c (revision db806f4fd8e8d1df92cc0c13d105eac7ed7a8d1e)
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 
44 
45 static const le_audio_codec_configuration_t codec_specific_config_settings[] = {
46     {"8_1",  LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ,  LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US,   26},
47     {"8_2",  LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ,  LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US,  30},
48     {"16_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US,   30},
49     {"16_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US,  40},
50     {"24_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US,   45},
51     {"24_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US,  60},
52     {"32_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US,   60},
53     {"32_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US,  80},
54     {"441_1",LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US,   97},
55     {"441_2",LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 130},
56     {"48_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US,   75},
57     {"48_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 100},
58     {"48_3", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US,   90},
59     {"48_4", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 120},
60     {"48_5", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US,  117},
61     {"48_6", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 155},
62 };
63 
64 static const le_audio_qos_configuration_t qos_config_settings[] = {
65     {"8_1_1",    7500, 0,  26, 2, 8},
66     {"8_2_1",   10000, 0,  30, 2, 10},
67     {"16_1_1",   7500, 0,  30, 2, 8},
68     {"16_2_1",  10000, 0,  40, 2, 10},
69     {"24_1_1",   7500, 0,  45, 2, 8},
70     {"24_2_1",  10000, 0,  60, 2, 10},
71     {"32_1_1",   7500, 0,  60, 2, 8},
72     {"32_2_1",  10000, 0,  80, 2, 10},
73     {"441_1_1",  8163, 1,  97, 5, 24},
74     {"441_2_1", 10884, 1, 130, 5, 31},
75     {"48_1_1",   7500, 0,  75, 5, 15},
76     {"48_2_1",  10000, 0, 100, 5, 20},
77     {"48_3_1",   7500, 0,  90, 5, 15},
78     {"48_4_1",  10000, 0, 120, 5, 20},
79     {"48_5_1",   7500, 0, 117, 5, 15},
80     {"48_6_1",  10000, 0, 115, 5, 20},
81 
82     {"8_1_2",    7500, 0,  26, 13, 75},
83     {"8_2_2",   10000, 0,  30, 13, 95},
84     {"16_1_2",   7500, 0,  30, 13, 75},
85     {"16_2_2",  10000, 0,  40, 13, 95},
86     {"24_1_2",   7500, 0,  45, 13, 75},
87     {"24_2_2",  10000, 0,  60, 13, 95},
88     {"32_1_2",   7500, 0,  60, 13, 75},
89     {"32_2_2",  10000, 0,  80, 13, 95},
90     {"441_1_2",  8163, 1,  97, 13, 80},
91     {"441_2_2", 10884, 1, 130, 13, 85},
92     {"48_1_2",   7500, 0,  75, 13, 75},
93     {"48_2_2",  10000, 0, 100, 13, 95},
94     {"48_3_2",   7500, 0,  90, 13, 75},
95     {"48_4_2",  10000, 0, 120, 13, 100},
96     {"48_5_2",   7500, 0, 117, 13, 75},
97     {"48_6_2",  10000, 0, 115, 13, 100}
98 };
99 
100 static uint8_t codec_offset(le_audio_codec_sampling_frequency_index_t sampling_frequency_index,
101     le_audio_codec_frame_duration_index_t frame_duration_index,
102     le_audio_quality_t audio_quality){
103 
104     btstack_assert(audio_quality <= LE_AUDIO_QUALITY_HIGH);
105 
106     if (sampling_frequency_index == LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ){
107         return 10 + (audio_quality - LE_AUDIO_QUALITY_LOW) * 2 + (frame_duration_index - LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US);
108     }
109     return (sampling_frequency_index - LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ) * 2 + (frame_duration_index - LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US);
110 }
111 
112 const le_audio_codec_configuration_t * le_audio_util_get_codec_setting(
113     le_audio_codec_sampling_frequency_index_t sampling_frequency_index,
114     le_audio_codec_frame_duration_index_t frame_duration_index,
115     le_audio_quality_t audio_quality){
116 
117     return &codec_specific_config_settings[codec_offset(sampling_frequency_index, frame_duration_index, audio_quality)];
118 }
119 
120 const le_audio_qos_configuration_t * le_audio_util_get_qos_setting(
121     le_audio_codec_sampling_frequency_index_t sampling_frequency_index,
122     le_audio_codec_frame_duration_index_t frame_duration_index,
123     le_audio_quality_t audio_quality, uint8_t num_channels){
124 
125     btstack_assert((num_channels >= 1) && (num_channels <= 2));
126 
127     return &qos_config_settings[(num_channels - 1) * 16 + codec_offset(sampling_frequency_index, frame_duration_index, audio_quality)];
128 }
129 
130 
131 // help with buffer == NULL
132 uint16_t le_audio_util_virtual_memcpy_helper(
133     const uint8_t * field_data, uint16_t field_len, uint16_t field_offset,
134     uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset){
135 
136     // only calc total size
137     if (buffer == NULL) {
138         return field_len;
139     }
140     return btstack_virtual_memcpy(field_data, field_len, field_offset, buffer, buffer_size, buffer_offset);
141 }
142 
143 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){
144     uint16_t metadata_type;
145     uint8_t  field_data[7];
146     uint16_t stored_bytes = 0;
147 
148     uint16_t metadata_length_pos = *records_offset;
149     field_data[0] = 0;
150     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, *records_offset, buffer, buffer_size,
151                                                         buffer_offset);
152     *records_offset += 1;
153 
154     if (metadata_length == 0){
155         return stored_bytes;
156     }
157 
158     for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
159         if ((metadata->metadata_mask & (1 << metadata_type) ) != 0 ){
160             // reserve field_data[0] for num butes to store
161             field_data[0] = 1;
162             field_data[1] = metadata_type;
163 
164             switch ((le_audio_metadata_type_t)metadata_type){
165                 case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
166                     field_data[0] += 2;
167                     little_endian_store_16(field_data, 2, metadata->preferred_audio_contexts_mask);
168                     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
169                                                                         buffer, buffer_size, buffer_offset);
170                     *records_offset += field_data[0] + 1;
171                     break;
172                 case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
173                     field_data[0] += 2;
174                     little_endian_store_16(field_data, 2, metadata->streaming_audio_contexts_mask);
175                     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
176                                                                         buffer, buffer_size, buffer_offset);
177                     *records_offset += field_data[0] + 1;
178                     break;
179                 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
180                     field_data[0] += metadata->program_info_length;
181                     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, *records_offset, buffer,
182                                                                         buffer_size, buffer_offset);
183                     *records_offset += 2;
184                     stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->program_info,
185                                                                         metadata->program_info_length, *records_offset,
186                                                                         buffer, buffer_size, buffer_offset);
187                     *records_offset += metadata->program_info_length;
188                     break;
189                 case LE_AUDIO_METADATA_TYPE_LANGUAGE:
190                     field_data[0] += 3;
191                     little_endian_store_24(field_data, 2, metadata->language_code);
192                     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
193                                                                         buffer, buffer_size, buffer_offset);
194                     *records_offset += field_data[0] + 1;
195                     break;
196                 case LE_AUDIO_METADATA_TYPE_CCID_LIST:
197                     field_data[0] += metadata->ccids_num;
198                     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, *records_offset, buffer,
199                                                                         buffer_size, buffer_offset);
200                     *records_offset += 2;
201                     stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->ccids, metadata->ccids_num,
202                                                                         *records_offset, buffer, buffer_size,
203                                                                         buffer_offset);
204                     *records_offset += metadata->ccids_num;
205                     break;
206                 case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
207                     field_data[0] += 1;
208                     field_data[2] = (uint8_t) metadata->parental_rating;
209                     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
210                                                                         buffer, buffer_size, buffer_offset);
211                     *records_offset += field_data[0] + 1;
212                     break;
213                 case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
214                     field_data[0] += metadata->program_info_uri_length;
215                     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, *records_offset, buffer,
216                                                                         buffer_size, buffer_offset);
217                     *records_offset += 2;
218                     stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->program_info_uri,
219                                                                         metadata->program_info_uri_length,
220                                                                         *records_offset, buffer, buffer_size,
221                                                                         buffer_offset);
222                     *records_offset += metadata->program_info_uri_length;
223                     break;
224                 case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
225                     field_data[0] += 2 + metadata->extended_metadata_length;
226                     field_data[1] = LE_AUDIO_METADATA_TYPE_EXTENDED_METADATA;
227                     little_endian_store_16(field_data, 2, metadata->extended_metadata_type);
228                     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 4, *records_offset, buffer,
229                                                                         buffer_size, buffer_offset);
230                     *records_offset += 4;
231                     stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->extended_metadata,
232                                                                         metadata->extended_metadata_length,
233                                                                         *records_offset, buffer, buffer_size,
234                                                                         buffer_offset);
235                     *records_offset += metadata->extended_metadata_length;
236                     break;
237                 case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
238                     field_data[0] += 2 + metadata->vendor_specific_metadata_length;
239                     field_data[1] = LE_AUDIO_METADATA_TYPE_VENDOR_SPECIFIC_METADATA;
240                     little_endian_store_16(field_data, 2, metadata->vendor_specific_company_id);
241                     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 4, *records_offset, buffer,
242                                                                         buffer_size, buffer_offset);
243                     *records_offset += 4;
244                     stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->vendor_specific_metadata,
245                                                                         metadata->vendor_specific_metadata_length,
246                                                                         *records_offset, buffer, buffer_size,
247                                                                         buffer_offset);
248                     *records_offset += metadata->vendor_specific_metadata_length;
249                     break;
250                 default:
251                     btstack_assert(false);
252                     break;
253             }
254         }
255     }
256 
257     field_data[0] =  *records_offset - metadata_length_pos - 1;
258     le_audio_util_virtual_memcpy_helper(field_data, 1, metadata_length_pos, buffer, buffer_size, buffer_offset);
259     return stored_bytes;
260 }
261 
262 
263 uint16_t le_audio_util_metadata_parse(const uint8_t *buffer, uint8_t buffer_size, le_audio_metadata_t * metadata){
264 
265     // reset capabilities
266     memset(metadata, 0, sizeof(le_audio_metadata_t));
267 
268     // parse config to get sampling frequency and frame duration
269     uint8_t offset = 0;
270     uint8_t metadata_config_length = buffer[offset++];
271     if (buffer_size < metadata_config_length){
272         return 0;
273     }
274 
275     metadata->metadata_mask = 0;
276 
277     while ((offset + 1) < metadata_config_length){
278         uint8_t ltv_len = buffer[offset++];
279 
280         le_audio_metadata_type_t ltv_type = (le_audio_metadata_type_t)buffer[offset];
281         le_audio_parental_rating_t parental_rating;
282 
283         switch (ltv_type){
284             case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
285                 metadata->preferred_audio_contexts_mask = little_endian_read_16(buffer, offset+1);
286                 metadata->metadata_mask |= (1 << ltv_type);
287                 break;
288             case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
289                 metadata->streaming_audio_contexts_mask = little_endian_read_16(buffer, offset+1);
290                 metadata->metadata_mask |= (1 << ltv_type);
291                 break;
292             case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
293                 metadata->program_info_length = btstack_min(ltv_len, LE_AUDIO_PROGRAM_INFO_MAX_LENGTH);
294                 memcpy(metadata->program_info, &buffer[offset+1], metadata->program_info_length);
295                 metadata->metadata_mask |= (1 << ltv_type);
296                 break;
297             case LE_AUDIO_METADATA_TYPE_LANGUAGE:
298                 metadata->language_code = little_endian_read_24(buffer, offset+1);
299                 metadata->metadata_mask |= (1 << ltv_type);
300                 break;
301             case LE_AUDIO_METADATA_TYPE_CCID_LIST:
302                 metadata->ccids_num = btstack_min(ltv_len, LE_CCIDS_MAX_NUM);
303                 memcpy(metadata->ccids, &buffer[offset+1], metadata->ccids_num);
304                 metadata->metadata_mask |= (1 << ltv_type);
305                 break;
306             case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
307                 parental_rating = (le_audio_parental_rating_t)buffer[offset+1];
308                 metadata->parental_rating = parental_rating;
309                 metadata->metadata_mask |= (1 << ltv_type);
310                 break;
311             case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
312                 metadata->program_info_uri_length = btstack_min(ltv_len, LE_AUDIO_PROGRAM_INFO_URI_MAX_LENGTH);
313                 memcpy(metadata->program_info_uri, &buffer[offset+1], metadata->program_info_uri_length);
314                 metadata->metadata_mask |= (1 << ltv_type);
315                 break;
316             case LE_AUDIO_METADATA_TYPE_EXTENDED_METADATA:
317                 if (ltv_len < 2){
318                     break;
319                 }
320                 metadata->extended_metadata_length = btstack_min(ltv_len - 2, LE_AUDIO_EXTENDED_METADATA_MAX_LENGHT);
321                 metadata->extended_metadata_type = little_endian_read_16(buffer, offset+1);
322                 memcpy(metadata->extended_metadata, &buffer[offset+3], metadata->extended_metadata_length);
323                 metadata->metadata_mask |= (1 << LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION);
324                 break;
325             case LE_AUDIO_METADATA_TYPE_VENDOR_SPECIFIC_METADATA:
326                 if (ltv_len < 2){
327                     break;
328                 }
329                 metadata->vendor_specific_metadata_length = btstack_min(ltv_len - 2, LE_AUDIO_VENDOR_SPECIFIC_METADATA_MAX_LENGTH);
330                 metadata->vendor_specific_company_id = little_endian_read_16(buffer, offset+1);
331                 memcpy(metadata->vendor_specific_metadata, &buffer[offset+3], metadata->vendor_specific_metadata_length);
332                 metadata->metadata_mask |= (1 << LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION);
333                 break;
334             default:
335                 metadata->metadata_mask |= (1 << LE_AUDIO_METADATA_TYPE_RFU);
336                 break;
337         }
338         offset += ltv_len;
339     }
340     return offset;
341 }
342 
343 uint16_t le_audio_util_metadata_serialize(const le_audio_metadata_t *metadata, uint8_t * event, uint16_t event_size){
344     UNUSED(event_size);
345 
346     uint8_t pos = 0;
347 
348     event[pos++] = (uint8_t)metadata->metadata_mask;
349     little_endian_store_16(event, pos, metadata->preferred_audio_contexts_mask);
350     pos += 2;
351     little_endian_store_16(event, pos, metadata->streaming_audio_contexts_mask);
352     pos += 2;
353 
354     event[pos++] = metadata->program_info_length;
355     memcpy(&event[pos], &metadata->program_info[0], metadata->program_info_length);
356     pos += metadata->program_info_length;
357 
358     little_endian_store_24(event, pos, metadata->language_code);
359     pos += 3;
360 
361     event[pos++] = metadata->ccids_num;
362     memcpy(&event[pos], &metadata->ccids[0], metadata->ccids_num);
363     pos += metadata->ccids_num;
364 
365     event[pos++] = (uint8_t)metadata->parental_rating;
366 
367     event[pos++] = metadata->program_info_uri_length;
368     memcpy(&event[pos], &metadata->program_info_uri[0], metadata->program_info_uri_length);
369     pos += metadata->program_info_uri_length;
370 
371     little_endian_store_16(event, pos, metadata->extended_metadata_type);
372     pos += 2;
373 
374     event[pos++] = metadata->extended_metadata_length;
375     memcpy(&event[pos], &metadata->extended_metadata[0], metadata->extended_metadata_length);
376     pos += metadata->extended_metadata_length;
377 
378     little_endian_store_16(event, pos, metadata->vendor_specific_company_id);
379     pos += 2;
380 
381     event[pos++] = metadata->vendor_specific_metadata_length;
382     memcpy(&event[pos], &metadata->vendor_specific_metadata[0], metadata->vendor_specific_metadata_length);
383     pos += metadata->vendor_specific_metadata_length;
384 
385     return pos;
386 }
387 
388 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){
389     switch (metadata_type){
390         case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
391         case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
392             return 2;
393 
394         case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
395             return metadata->program_info_length;
396 
397         case LE_AUDIO_METADATA_TYPE_LANGUAGE:
398             return 3;
399 
400         case LE_AUDIO_METADATA_TYPE_CCID_LIST:
401             return metadata->ccids_num;
402 
403         case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
404             return 1;
405 
406         case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
407             return metadata->program_info_uri_length;
408 
409         case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
410             return 2 + metadata->extended_metadata_length;
411 
412         case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
413             return 2 + metadata->vendor_specific_metadata_length;
414         default:
415             break;
416     }
417     return 0;
418 }
419 
420 uint16_t le_audio_util_metadata_serialize_using_mask(const le_audio_metadata_t *metadata, uint8_t * tlv_buffer, uint16_t tlv_buffer_size){
421     uint16_t metadata_type;
422     uint16_t pos = 0;
423 
424     uint16_t remaining_bytes = tlv_buffer_size;
425 
426     for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
427         if ((metadata->metadata_mask & (1 << metadata_type)) == 0){
428             continue;
429         }
430 
431         uint8_t payload_length = le_audio_util_get_value_size_for_metadata_type(metadata, (le_audio_metadata_type_t)metadata_type);
432         // ensure that there is enough space in TLV to store length (1), type(1) and payload
433         if (remaining_bytes < (2 + payload_length)){
434             return pos;
435         }
436 
437         tlv_buffer[pos++] = 1 + payload_length; // add one extra byte to count size of type (1 byte)
438         tlv_buffer[pos++] = metadata_type;
439 
440         switch ((le_audio_metadata_type_t)metadata_type){
441             case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
442                 little_endian_store_16(tlv_buffer, pos, metadata->preferred_audio_contexts_mask);
443                 break;
444             case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
445                 little_endian_store_16(tlv_buffer, pos, metadata->streaming_audio_contexts_mask);
446                 break;
447             case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
448                 memcpy(&tlv_buffer[pos], metadata->program_info, metadata->program_info_length);
449                 break;
450             case LE_AUDIO_METADATA_TYPE_LANGUAGE:
451                 little_endian_store_24(tlv_buffer, pos, metadata->language_code);
452                 break;
453             case LE_AUDIO_METADATA_TYPE_CCID_LIST:
454                 memcpy(&tlv_buffer[pos], metadata->ccids, metadata->ccids_num);
455                 break;
456             case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
457                 break;
458             case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
459                 memcpy(&tlv_buffer[pos], metadata->program_info_uri, metadata->program_info_uri_length);
460                 break;
461             case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
462                 little_endian_store_16(tlv_buffer, pos, metadata->extended_metadata_type);
463                 memcpy(&tlv_buffer[pos + 2], metadata->extended_metadata, metadata->extended_metadata_length);
464                 break;
465             case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
466                 little_endian_store_16(tlv_buffer, pos, metadata->vendor_specific_company_id);
467                 memcpy(&tlv_buffer[pos + 2], metadata->vendor_specific_metadata, metadata->vendor_specific_metadata_length);
468                 break;
469             default:
470                 break;
471         }
472         pos += payload_length;
473         remaining_bytes -= (payload_length + 2);
474     }
475     return pos;
476 }
477 
478 btstack_lc3_frame_duration_t le_audio_util_get_btstack_lc3_frame_duration(le_audio_codec_frame_duration_index_t frame_duration_index){
479     switch (frame_duration_index){
480         case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US:
481             return BTSTACK_LC3_FRAME_DURATION_7500US;
482         case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US:
483             return BTSTACK_LC3_FRAME_DURATION_10000US;
484         default:
485             btstack_assert(false);
486             break;
487     }
488     return 0;
489 }
490 
491 uint16_t le_audio_get_frame_duration_us(le_audio_codec_frame_duration_index_t frame_duration_index){
492     switch (frame_duration_index){
493         case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US:
494             return 7500;
495         case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US:
496             return 10000;
497         default:
498             return 0;
499     }
500 }
501 
502 le_audio_codec_frame_duration_index_t le_audio_get_frame_duration_index(uint16_t frame_duration_us){
503     switch (frame_duration_us){
504         case 7500:
505             return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US;
506         case 10000:
507             return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US;
508         default:
509             return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_RFU;
510     }
511 }
512 
513 uint32_t le_audio_get_sampling_frequency_hz(le_audio_codec_sampling_frequency_index_t sampling_frequency_index){
514     switch (sampling_frequency_index){
515         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ:
516                 return 8000;
517         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_11025_HZ:
518                 return 11025;
519         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ:
520                 return 16000;
521         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_22050_HZ:
522                 return 22050;
523         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ:
524                 return 24000;
525         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ:
526                 return 32000;
527         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ:
528                 return 44100;
529         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ:
530                 return 48000;
531         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_88200_HZ:
532                 return 88200;
533         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_96000_HZ:
534                 return 96000;
535         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_176400_HZ:
536                 return 176400;
537         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_192000_HZ:
538                 return 192000;
539         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_384000_HZ:
540                 return 384000;
541         default:
542             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_INVALID;
543     }
544 }
545 
546 le_audio_codec_sampling_frequency_index_t le_audio_get_sampling_frequency_index(uint32_t sampling_frequency_hz){
547     switch (sampling_frequency_hz){
548         case 0:
549             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_INVALID;
550         case 8000:
551             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ;
552         case 11025:
553             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_11025_HZ;
554         case 16000:
555             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ;
556         case 22050:
557             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_22050_HZ;
558         case 24000:
559             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ;
560         case 32000:
561             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ;
562         case 44100:
563             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ;
564         case 48000:
565             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ;
566         case 88200:
567             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_88200_HZ;
568         case 96000:
569             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_96000_HZ;
570         case 176400:
571             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_176400_HZ;
572         case 192000:
573             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_192000_HZ;
574         case 384000:
575             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_384000_HZ;
576         default:
577             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_RFU;
578     }
579 }
580 
581 
582