xref: /btstack/src/le-audio/le_audio_util.c (revision e8b7768f4320b89e088aeff6b8ffd5c9b51f3338)
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     uint8_t pos = 0;
345 
346     event[pos++] = (uint8_t)metadata->metadata_mask;
347     little_endian_store_16(event, pos, metadata->preferred_audio_contexts_mask);
348     pos += 2;
349     little_endian_store_16(event, pos, metadata->streaming_audio_contexts_mask);
350     pos += 2;
351 
352     event[pos++] = metadata->program_info_length;
353     memcpy(&event[pos], &metadata->program_info[0], metadata->program_info_length);
354     pos += metadata->program_info_length;
355 
356     little_endian_store_24(event, pos, metadata->language_code);
357     pos += 3;
358 
359     event[pos++] = metadata->ccids_num;
360     memcpy(&event[pos], &metadata->ccids[0], metadata->ccids_num);
361     pos += metadata->ccids_num;
362 
363     event[pos++] = (uint8_t)metadata->parental_rating;
364 
365     event[pos++] = metadata->program_info_uri_length;
366     memcpy(&event[pos], &metadata->program_info_uri[0], metadata->program_info_uri_length);
367     pos += metadata->program_info_uri_length;
368 
369     little_endian_store_16(event, pos, metadata->extended_metadata_type);
370     pos += 2;
371 
372     event[pos++] = metadata->extended_metadata_length;
373     memcpy(&event[pos], &metadata->extended_metadata[0], metadata->extended_metadata_length);
374     pos += metadata->extended_metadata_length;
375 
376     little_endian_store_16(event, pos, metadata->vendor_specific_company_id);
377     pos += 2;
378 
379     event[pos++] = metadata->vendor_specific_metadata_length;
380     memcpy(&event[pos], &metadata->vendor_specific_metadata[0], metadata->vendor_specific_metadata_length);
381     pos += metadata->vendor_specific_metadata_length;
382 
383     return pos;
384 }
385 
386 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){
387     switch (metadata_type){
388         case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
389         case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
390             return 2;
391 
392         case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
393             return metadata->program_info_length;
394 
395         case LE_AUDIO_METADATA_TYPE_LANGUAGE:
396             return 3;
397 
398         case LE_AUDIO_METADATA_TYPE_CCID_LIST:
399             return metadata->ccids_num;
400 
401         case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
402             return 1;
403 
404         case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
405             return metadata->program_info_uri_length;
406 
407         case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
408             return 2 + metadata->extended_metadata_length;
409 
410         case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
411             return 2 + metadata->vendor_specific_metadata_length;
412         default:
413             break;
414     }
415     return 0;
416 }
417 
418 uint16_t le_audio_util_metadata_serialize_using_mask(const le_audio_metadata_t *metadata, uint8_t * tlv_buffer, uint16_t tlv_buffer_size){
419     uint16_t metadata_type;
420     uint16_t pos = 0;
421 
422     uint16_t remaining_bytes = tlv_buffer_size;
423 
424     for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
425         if ((metadata->metadata_mask & (1 << metadata_type)) == 0){
426             continue;
427         }
428 
429         uint8_t payload_length = le_audio_util_get_value_size_for_metadata_type(metadata, (le_audio_metadata_type_t)metadata_type);
430         // ensure that there is enough space in TLV to store length (1), type(1) and payload
431         if (remaining_bytes < (2 + payload_length)){
432             return pos;
433         }
434 
435         tlv_buffer[pos++] = 1 + payload_length; // add one extra byte to count size of type (1 byte)
436         tlv_buffer[pos++] = metadata_type;
437 
438         switch ((le_audio_metadata_type_t)metadata_type){
439             case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
440                 little_endian_store_16(tlv_buffer, pos, metadata->preferred_audio_contexts_mask);
441                 break;
442             case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
443                 little_endian_store_16(tlv_buffer, pos, metadata->streaming_audio_contexts_mask);
444                 break;
445             case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
446                 memcpy(&tlv_buffer[pos], metadata->program_info, metadata->program_info_length);
447                 break;
448             case LE_AUDIO_METADATA_TYPE_LANGUAGE:
449                 little_endian_store_24(tlv_buffer, pos, metadata->language_code);
450                 break;
451             case LE_AUDIO_METADATA_TYPE_CCID_LIST:
452                 memcpy(&tlv_buffer[pos], metadata->ccids, metadata->ccids_num);
453                 break;
454             case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
455                 break;
456             case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
457                 memcpy(&tlv_buffer[pos], metadata->program_info_uri, metadata->program_info_uri_length);
458                 break;
459             case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
460                 little_endian_store_16(tlv_buffer, pos, metadata->extended_metadata_type);
461                 memcpy(&tlv_buffer[pos + 2], metadata->extended_metadata, metadata->extended_metadata_length);
462                 break;
463             case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
464                 little_endian_store_16(tlv_buffer, pos, metadata->vendor_specific_company_id);
465                 memcpy(&tlv_buffer[pos + 2], metadata->vendor_specific_metadata, metadata->vendor_specific_metadata_length);
466                 break;
467             default:
468                 break;
469         }
470         pos += payload_length;
471         remaining_bytes -= (payload_length + 2);
472     }
473     return pos;
474 }
475 
476 btstack_lc3_frame_duration_t le_audio_util_get_btstack_lc3_frame_duration(le_audio_codec_frame_duration_index_t frame_duration_index){
477     switch (frame_duration_index){
478         case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US:
479             return BTSTACK_LC3_FRAME_DURATION_7500US;
480         case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US:
481             return BTSTACK_LC3_FRAME_DURATION_10000US;
482         default:
483             btstack_assert(false);
484             break;
485     }
486     return 0;
487 }
488 
489 uint16_t le_audio_get_frame_duration_us(le_audio_codec_frame_duration_index_t frame_duration_index){
490     switch (frame_duration_index){
491         case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US:
492             return 7500;
493         case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US:
494             return 10000;
495         default:
496             return 0;
497     }
498 }
499 
500 le_audio_codec_frame_duration_index_t le_audio_get_frame_duration_index(uint16_t frame_duration_us){
501     switch (frame_duration_us){
502         case 7500:
503             return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US;
504         case 10000:
505             return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US;
506         default:
507             return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_RFU;
508     }
509 }
510 
511 uint32_t le_audio_get_sampling_frequency_hz(le_audio_codec_sampling_frequency_index_t sampling_frequency_index){
512     switch (sampling_frequency_index){
513         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ:
514                 return 8000;
515         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_11025_HZ:
516                 return 11025;
517         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ:
518                 return 16000;
519         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_22050_HZ:
520                 return 22050;
521         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ:
522                 return 24000;
523         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ:
524                 return 32000;
525         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ:
526                 return 44100;
527         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ:
528                 return 48000;
529         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_88200_HZ:
530                 return 88200;
531         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_96000_HZ:
532                 return 96000;
533         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_176400_HZ:
534                 return 176400;
535         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_192000_HZ:
536                 return 192000;
537         case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_384000_HZ:
538                 return 384000;
539         default:
540             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_INVALID;
541     }
542 }
543 
544 le_audio_codec_sampling_frequency_index_t le_audio_get_sampling_frequency_index(uint32_t sampling_frequency_hz){
545     switch (sampling_frequency_hz){
546         case 0:
547             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_INVALID;
548         case 8000:
549             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ;
550         case 11025:
551             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_11025_HZ;
552         case 16000:
553             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ;
554         case 22050:
555             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_22050_HZ;
556         case 24000:
557             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ;
558         case 32000:
559             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ;
560         case 44100:
561             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ;
562         case 48000:
563             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ;
564         case 88200:
565             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_88200_HZ;
566         case 96000:
567             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_96000_HZ;
568         case 176400:
569             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_176400_HZ;
570         case 192000:
571             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_192000_HZ;
572         case 384000:
573             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_384000_HZ;
574         default:
575             return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_RFU;
576     }
577 }
578 
579 
580