xref: /btstack/src/le-audio/le_audio_util.c (revision ceed67ffe68ea5103bbc5647a2e000ed0e08b747)
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 
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 
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 
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
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 
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
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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