15deb0bb6SMatthias Ringwald /*
25deb0bb6SMatthias Ringwald * Copyright (C) 2022 BlueKitchen GmbH
35deb0bb6SMatthias Ringwald *
45deb0bb6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without
55deb0bb6SMatthias Ringwald * modification, are permitted provided that the following conditions
65deb0bb6SMatthias Ringwald * are met:
75deb0bb6SMatthias Ringwald *
85deb0bb6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
95deb0bb6SMatthias Ringwald * notice, this list of conditions and the following disclaimer.
105deb0bb6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
115deb0bb6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
125deb0bb6SMatthias Ringwald * documentation and/or other materials provided with the distribution.
135deb0bb6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
145deb0bb6SMatthias Ringwald * contributors may be used to endorse or promote products derived
155deb0bb6SMatthias Ringwald * from this software without specific prior written permission.
165deb0bb6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
175deb0bb6SMatthias Ringwald * personal benefit and not for any commercial purpose or for
185deb0bb6SMatthias Ringwald * monetary gain.
195deb0bb6SMatthias Ringwald *
205deb0bb6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
215deb0bb6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
225deb0bb6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
235deb0bb6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
245deb0bb6SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
255deb0bb6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
265deb0bb6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
275deb0bb6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
285deb0bb6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
295deb0bb6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
305deb0bb6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
315deb0bb6SMatthias Ringwald * SUCH DAMAGE.
325deb0bb6SMatthias Ringwald *
335deb0bb6SMatthias Ringwald * Please inquire about commercial licensing options at
345deb0bb6SMatthias Ringwald * [email protected]
355deb0bb6SMatthias Ringwald *
365deb0bb6SMatthias Ringwald */
375deb0bb6SMatthias Ringwald
385deb0bb6SMatthias Ringwald #define BTSTACK_FILE__ "le_audio_util.c"
395deb0bb6SMatthias Ringwald
405deb0bb6SMatthias Ringwald #include "btstack_util.h"
415deb0bb6SMatthias Ringwald #include "btstack_debug.h"
425deb0bb6SMatthias Ringwald #include "le-audio/le_audio_util.h"
43*d21278d0SMatthias Ringwald #include "btstack_event.h"
445deb0bb6SMatthias Ringwald
459ef2c435SMilanka Ringwald
469ef2c435SMilanka Ringwald static const le_audio_codec_configuration_t codec_specific_config_settings[] = {
479ef2c435SMilanka Ringwald {"8_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 26},
489ef2c435SMilanka Ringwald {"8_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 30},
499ef2c435SMilanka Ringwald {"16_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 30},
509ef2c435SMilanka Ringwald {"16_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 40},
519ef2c435SMilanka Ringwald {"24_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 45},
529ef2c435SMilanka Ringwald {"24_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 60},
539ef2c435SMilanka Ringwald {"32_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 60},
549ef2c435SMilanka Ringwald {"32_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 80},
559ef2c435SMilanka Ringwald {"441_1",LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 97},
569ef2c435SMilanka Ringwald {"441_2",LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 130},
579ef2c435SMilanka Ringwald {"48_1", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 75},
589ef2c435SMilanka Ringwald {"48_2", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 100},
599ef2c435SMilanka Ringwald {"48_3", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 90},
609ef2c435SMilanka Ringwald {"48_4", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 120},
619ef2c435SMilanka Ringwald {"48_5", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US, 117},
629ef2c435SMilanka Ringwald {"48_6", LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ, LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US, 155},
639ef2c435SMilanka Ringwald };
649ef2c435SMilanka Ringwald
659ef2c435SMilanka Ringwald static const le_audio_qos_configuration_t qos_config_settings[] = {
664ea63b4dSMilanka Ringwald {"8_1_1", 7500, 0, 26, 2, 8},
674ea63b4dSMilanka Ringwald {"8_2_1", 10000, 0, 30, 2, 10},
684ea63b4dSMilanka Ringwald {"16_1_1", 7500, 0, 30, 2, 8},
694ea63b4dSMilanka Ringwald {"16_2_1", 10000, 0, 40, 2, 10},
704ea63b4dSMilanka Ringwald {"24_1_1", 7500, 0, 45, 2, 8},
714ea63b4dSMilanka Ringwald {"24_2_1", 10000, 0, 60, 2, 10},
724ea63b4dSMilanka Ringwald {"32_1_1", 7500, 0, 60, 2, 8},
734ea63b4dSMilanka Ringwald {"32_2_1", 10000, 0, 80, 2, 10},
744ea63b4dSMilanka Ringwald {"441_1_1", 8163, 1, 97, 5, 24},
754ea63b4dSMilanka Ringwald {"441_2_1", 10884, 1, 130, 5, 31},
764ea63b4dSMilanka Ringwald {"48_1_1", 7500, 0, 75, 5, 15},
774ea63b4dSMilanka Ringwald {"48_2_1", 10000, 0, 100, 5, 20},
784ea63b4dSMilanka Ringwald {"48_3_1", 7500, 0, 90, 5, 15},
794ea63b4dSMilanka Ringwald {"48_4_1", 10000, 0, 120, 5, 20},
804ea63b4dSMilanka Ringwald {"48_5_1", 7500, 0, 117, 5, 15},
814ea63b4dSMilanka Ringwald {"48_6_1", 10000, 0, 115, 5, 20},
829ef2c435SMilanka Ringwald
834ea63b4dSMilanka Ringwald {"8_1_2", 7500, 0, 26, 13, 75},
844ea63b4dSMilanka Ringwald {"8_2_2", 10000, 0, 30, 13, 95},
854ea63b4dSMilanka Ringwald {"16_1_2", 7500, 0, 30, 13, 75},
864ea63b4dSMilanka Ringwald {"16_2_2", 10000, 0, 40, 13, 95},
874ea63b4dSMilanka Ringwald {"24_1_2", 7500, 0, 45, 13, 75},
884ea63b4dSMilanka Ringwald {"24_2_2", 10000, 0, 60, 13, 95},
894ea63b4dSMilanka Ringwald {"32_1_2", 7500, 0, 60, 13, 75},
904ea63b4dSMilanka Ringwald {"32_2_2", 10000, 0, 80, 13, 95},
914ea63b4dSMilanka Ringwald {"441_1_2", 8163, 1, 97, 13, 80},
924ea63b4dSMilanka Ringwald {"441_2_2", 10884, 1, 130, 13, 85},
934ea63b4dSMilanka Ringwald {"48_1_2", 7500, 0, 75, 13, 75},
944ea63b4dSMilanka Ringwald {"48_2_2", 10000, 0, 100, 13, 95},
954ea63b4dSMilanka Ringwald {"48_3_2", 7500, 0, 90, 13, 75},
964ea63b4dSMilanka Ringwald {"48_4_2", 10000, 0, 120, 13, 100},
974ea63b4dSMilanka Ringwald {"48_5_2", 7500, 0, 117, 13, 75},
984ea63b4dSMilanka Ringwald {"48_6_2", 10000, 0, 115, 13, 100}
999ef2c435SMilanka Ringwald };
1009ef2c435SMilanka Ringwald
codec_offset(le_audio_codec_sampling_frequency_index_t sampling_frequency_index,le_audio_codec_frame_duration_index_t frame_duration_index,le_audio_quality_t audio_quality)1019ef2c435SMilanka Ringwald static uint8_t codec_offset(le_audio_codec_sampling_frequency_index_t sampling_frequency_index,
1029ef2c435SMilanka Ringwald le_audio_codec_frame_duration_index_t frame_duration_index,
1039ef2c435SMilanka Ringwald le_audio_quality_t audio_quality){
1049ef2c435SMilanka Ringwald
1059ef2c435SMilanka Ringwald btstack_assert(audio_quality <= LE_AUDIO_QUALITY_HIGH);
1069ef2c435SMilanka Ringwald
1079ef2c435SMilanka Ringwald if (sampling_frequency_index == LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ){
1089ef2c435SMilanka Ringwald return 10 + (audio_quality - LE_AUDIO_QUALITY_LOW) * 2 + (frame_duration_index - LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US);
1099ef2c435SMilanka Ringwald }
1109ef2c435SMilanka Ringwald return (sampling_frequency_index - LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ) * 2 + (frame_duration_index - LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US);
1119ef2c435SMilanka Ringwald }
1129ef2c435SMilanka Ringwald
le_audio_util_get_codec_setting(le_audio_codec_sampling_frequency_index_t sampling_frequency_index,le_audio_codec_frame_duration_index_t frame_duration_index,le_audio_quality_t audio_quality)1139ef2c435SMilanka Ringwald const le_audio_codec_configuration_t * le_audio_util_get_codec_setting(
1149ef2c435SMilanka Ringwald le_audio_codec_sampling_frequency_index_t sampling_frequency_index,
1159ef2c435SMilanka Ringwald le_audio_codec_frame_duration_index_t frame_duration_index,
1169ef2c435SMilanka Ringwald le_audio_quality_t audio_quality){
1179ef2c435SMilanka Ringwald
1189ef2c435SMilanka Ringwald return &codec_specific_config_settings[codec_offset(sampling_frequency_index, frame_duration_index, audio_quality)];
1199ef2c435SMilanka Ringwald }
1209ef2c435SMilanka Ringwald
le_audio_util_get_qos_setting(le_audio_codec_sampling_frequency_index_t sampling_frequency_index,le_audio_codec_frame_duration_index_t frame_duration_index,le_audio_quality_t audio_quality,uint8_t num_channels)1219ef2c435SMilanka Ringwald const le_audio_qos_configuration_t * le_audio_util_get_qos_setting(
1229ef2c435SMilanka Ringwald le_audio_codec_sampling_frequency_index_t sampling_frequency_index,
1239ef2c435SMilanka Ringwald le_audio_codec_frame_duration_index_t frame_duration_index,
1249ef2c435SMilanka Ringwald le_audio_quality_t audio_quality, uint8_t num_channels){
1259ef2c435SMilanka Ringwald
1269ef2c435SMilanka Ringwald btstack_assert((num_channels >= 1) && (num_channels <= 2));
1279ef2c435SMilanka Ringwald
1284ea63b4dSMilanka Ringwald return &qos_config_settings[(num_channels - 1) * 16 + codec_offset(sampling_frequency_index, frame_duration_index, audio_quality)];
1299ef2c435SMilanka Ringwald }
1309ef2c435SMilanka Ringwald
1319ef2c435SMilanka Ringwald
1325deb0bb6SMatthias Ringwald // help with buffer == NULL
le_audio_util_virtual_memcpy_helper(const uint8_t * field_data,uint16_t field_len,uint16_t field_offset,uint8_t * buffer,uint16_t buffer_size,uint16_t buffer_offset)13354461c80SMatthias Ringwald uint16_t le_audio_util_virtual_memcpy_helper(
1345deb0bb6SMatthias Ringwald const uint8_t * field_data, uint16_t field_len, uint16_t field_offset,
1355deb0bb6SMatthias Ringwald uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset){
1365deb0bb6SMatthias Ringwald
1375deb0bb6SMatthias Ringwald // only calc total size
1385deb0bb6SMatthias Ringwald if (buffer == NULL) {
1395deb0bb6SMatthias Ringwald return field_len;
1405deb0bb6SMatthias Ringwald }
1415deb0bb6SMatthias Ringwald return btstack_virtual_memcpy(field_data, field_len, field_offset, buffer, buffer_size, buffer_offset);
1425deb0bb6SMatthias Ringwald }
1435deb0bb6SMatthias Ringwald
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)14454461c80SMatthias Ringwald 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){
1455deb0bb6SMatthias Ringwald uint16_t metadata_type;
1465deb0bb6SMatthias Ringwald uint8_t field_data[7];
1475deb0bb6SMatthias Ringwald uint16_t stored_bytes = 0;
1485deb0bb6SMatthias Ringwald
1495deb0bb6SMatthias Ringwald uint16_t metadata_length_pos = *records_offset;
1505deb0bb6SMatthias Ringwald field_data[0] = 0;
15154461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, *records_offset, buffer, buffer_size,
15254461c80SMatthias Ringwald buffer_offset);
1535deb0bb6SMatthias Ringwald *records_offset += 1;
1545deb0bb6SMatthias Ringwald
1555deb0bb6SMatthias Ringwald if (metadata_length == 0){
1565deb0bb6SMatthias Ringwald return stored_bytes;
1575deb0bb6SMatthias Ringwald }
1585deb0bb6SMatthias Ringwald
1595deb0bb6SMatthias Ringwald for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
1605deb0bb6SMatthias Ringwald if ((metadata->metadata_mask & (1 << metadata_type) ) != 0 ){
1615deb0bb6SMatthias Ringwald // reserve field_data[0] for num butes to store
1625deb0bb6SMatthias Ringwald field_data[0] = 1;
1635deb0bb6SMatthias Ringwald field_data[1] = metadata_type;
1645deb0bb6SMatthias Ringwald
1655deb0bb6SMatthias Ringwald switch ((le_audio_metadata_type_t)metadata_type){
1665deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
1675deb0bb6SMatthias Ringwald field_data[0] += 2;
1685deb0bb6SMatthias Ringwald little_endian_store_16(field_data, 2, metadata->preferred_audio_contexts_mask);
16954461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
17054461c80SMatthias Ringwald buffer, buffer_size, buffer_offset);
1715deb0bb6SMatthias Ringwald *records_offset += field_data[0] + 1;
1725deb0bb6SMatthias Ringwald break;
1735deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
1745deb0bb6SMatthias Ringwald field_data[0] += 2;
1755deb0bb6SMatthias Ringwald little_endian_store_16(field_data, 2, metadata->streaming_audio_contexts_mask);
17654461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
17754461c80SMatthias Ringwald buffer, buffer_size, buffer_offset);
1785deb0bb6SMatthias Ringwald *records_offset += field_data[0] + 1;
1795deb0bb6SMatthias Ringwald break;
1805deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
1815deb0bb6SMatthias Ringwald field_data[0] += metadata->program_info_length;
18254461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, *records_offset, buffer,
18354461c80SMatthias Ringwald buffer_size, buffer_offset);
1845deb0bb6SMatthias Ringwald *records_offset += 2;
18554461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->program_info,
18654461c80SMatthias Ringwald metadata->program_info_length, *records_offset,
18754461c80SMatthias Ringwald buffer, buffer_size, buffer_offset);
1885deb0bb6SMatthias Ringwald *records_offset += metadata->program_info_length;
1895deb0bb6SMatthias Ringwald break;
1905deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_LANGUAGE:
1915deb0bb6SMatthias Ringwald field_data[0] += 3;
1925deb0bb6SMatthias Ringwald little_endian_store_24(field_data, 2, metadata->language_code);
19354461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
19454461c80SMatthias Ringwald buffer, buffer_size, buffer_offset);
1955deb0bb6SMatthias Ringwald *records_offset += field_data[0] + 1;
1965deb0bb6SMatthias Ringwald break;
1975deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_CCID_LIST:
1985deb0bb6SMatthias Ringwald field_data[0] += metadata->ccids_num;
19954461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, *records_offset, buffer,
20054461c80SMatthias Ringwald buffer_size, buffer_offset);
2015deb0bb6SMatthias Ringwald *records_offset += 2;
20254461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->ccids, metadata->ccids_num,
20354461c80SMatthias Ringwald *records_offset, buffer, buffer_size,
20454461c80SMatthias Ringwald buffer_offset);
2055deb0bb6SMatthias Ringwald *records_offset += metadata->ccids_num;
2065deb0bb6SMatthias Ringwald break;
2075deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
2085deb0bb6SMatthias Ringwald field_data[0] += 1;
2095deb0bb6SMatthias Ringwald field_data[2] = (uint8_t) metadata->parental_rating;
21054461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, field_data[0] + 1, *records_offset,
21154461c80SMatthias Ringwald buffer, buffer_size, buffer_offset);
2125deb0bb6SMatthias Ringwald *records_offset += field_data[0] + 1;
2135deb0bb6SMatthias Ringwald break;
2145deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
2155deb0bb6SMatthias Ringwald field_data[0] += metadata->program_info_uri_length;
21654461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, *records_offset, buffer,
21754461c80SMatthias Ringwald buffer_size, buffer_offset);
2185deb0bb6SMatthias Ringwald *records_offset += 2;
21954461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->program_info_uri,
22054461c80SMatthias Ringwald metadata->program_info_uri_length,
22154461c80SMatthias Ringwald *records_offset, buffer, buffer_size,
22254461c80SMatthias Ringwald buffer_offset);
2235deb0bb6SMatthias Ringwald *records_offset += metadata->program_info_uri_length;
2245deb0bb6SMatthias Ringwald break;
2255deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
2265deb0bb6SMatthias Ringwald field_data[0] += 2 + metadata->extended_metadata_length;
2275deb0bb6SMatthias Ringwald field_data[1] = LE_AUDIO_METADATA_TYPE_EXTENDED_METADATA;
2285deb0bb6SMatthias Ringwald little_endian_store_16(field_data, 2, metadata->extended_metadata_type);
22954461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 4, *records_offset, buffer,
23054461c80SMatthias Ringwald buffer_size, buffer_offset);
2315deb0bb6SMatthias Ringwald *records_offset += 4;
23254461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->extended_metadata,
23354461c80SMatthias Ringwald metadata->extended_metadata_length,
23454461c80SMatthias Ringwald *records_offset, buffer, buffer_size,
23554461c80SMatthias Ringwald buffer_offset);
2365deb0bb6SMatthias Ringwald *records_offset += metadata->extended_metadata_length;
2375deb0bb6SMatthias Ringwald break;
2385deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
2395deb0bb6SMatthias Ringwald field_data[0] += 2 + metadata->vendor_specific_metadata_length;
2405deb0bb6SMatthias Ringwald field_data[1] = LE_AUDIO_METADATA_TYPE_VENDOR_SPECIFIC_METADATA;
2415deb0bb6SMatthias Ringwald little_endian_store_16(field_data, 2, metadata->vendor_specific_company_id);
24254461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 4, *records_offset, buffer,
24354461c80SMatthias Ringwald buffer_size, buffer_offset);
2445deb0bb6SMatthias Ringwald *records_offset += 4;
24554461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(metadata->vendor_specific_metadata,
24654461c80SMatthias Ringwald metadata->vendor_specific_metadata_length,
24754461c80SMatthias Ringwald *records_offset, buffer, buffer_size,
24854461c80SMatthias Ringwald buffer_offset);
2495deb0bb6SMatthias Ringwald *records_offset += metadata->vendor_specific_metadata_length;
2505deb0bb6SMatthias Ringwald break;
2515deb0bb6SMatthias Ringwald default:
2525deb0bb6SMatthias Ringwald btstack_assert(false);
2535deb0bb6SMatthias Ringwald break;
2545deb0bb6SMatthias Ringwald }
2555deb0bb6SMatthias Ringwald }
2565deb0bb6SMatthias Ringwald }
2575deb0bb6SMatthias Ringwald
2585deb0bb6SMatthias Ringwald field_data[0] = *records_offset - metadata_length_pos - 1;
25954461c80SMatthias Ringwald le_audio_util_virtual_memcpy_helper(field_data, 1, metadata_length_pos, buffer, buffer_size, buffer_offset);
2605deb0bb6SMatthias Ringwald return stored_bytes;
2615deb0bb6SMatthias Ringwald }
2625deb0bb6SMatthias Ringwald
263*d21278d0SMatthias Ringwald // parse metadata, first unsupported type is stored in metadata.unsupported_type
le_audio_util_metadata_parse(const uint8_t * buffer,uint8_t buffer_size,le_audio_metadata_t * metadata)264f67c2203SMatthias Ringwald uint16_t le_audio_util_metadata_parse(const uint8_t *buffer, uint8_t buffer_size, le_audio_metadata_t * metadata){
265856b442cSMatthias Ringwald
266856b442cSMatthias Ringwald // reset capabilities
267856b442cSMatthias Ringwald memset(metadata, 0, sizeof(le_audio_metadata_t));
268856b442cSMatthias Ringwald
2695deb0bb6SMatthias Ringwald // parse config to get sampling frequency and frame duration
2705deb0bb6SMatthias Ringwald uint8_t offset = 0;
271856b442cSMatthias Ringwald uint8_t metadata_config_length = buffer[offset++];
272856b442cSMatthias Ringwald if (buffer_size < metadata_config_length){
2735deb0bb6SMatthias Ringwald return 0;
2745deb0bb6SMatthias Ringwald }
2755deb0bb6SMatthias Ringwald
2765deb0bb6SMatthias Ringwald metadata->metadata_mask = 0;
2775deb0bb6SMatthias Ringwald
278856b442cSMatthias Ringwald while ((offset + 1) < metadata_config_length){
2795deb0bb6SMatthias Ringwald uint8_t ltv_len = buffer[offset++];
2805deb0bb6SMatthias Ringwald
2815deb0bb6SMatthias Ringwald le_audio_metadata_type_t ltv_type = (le_audio_metadata_type_t)buffer[offset];
2825deb0bb6SMatthias Ringwald le_audio_parental_rating_t parental_rating;
2835deb0bb6SMatthias Ringwald
2845deb0bb6SMatthias Ringwald switch (ltv_type){
2855deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
2865deb0bb6SMatthias Ringwald metadata->preferred_audio_contexts_mask = little_endian_read_16(buffer, offset+1);
2875deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << ltv_type);
2885deb0bb6SMatthias Ringwald break;
2895deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
2905deb0bb6SMatthias Ringwald metadata->streaming_audio_contexts_mask = little_endian_read_16(buffer, offset+1);
2915deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << ltv_type);
2925deb0bb6SMatthias Ringwald break;
2935deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
2945deb0bb6SMatthias Ringwald metadata->program_info_length = btstack_min(ltv_len, LE_AUDIO_PROGRAM_INFO_MAX_LENGTH);
2955deb0bb6SMatthias Ringwald memcpy(metadata->program_info, &buffer[offset+1], metadata->program_info_length);
2965deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << ltv_type);
2975deb0bb6SMatthias Ringwald break;
2985deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_LANGUAGE:
2995deb0bb6SMatthias Ringwald metadata->language_code = little_endian_read_24(buffer, offset+1);
3005deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << ltv_type);
3015deb0bb6SMatthias Ringwald break;
3025deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_CCID_LIST:
303*d21278d0SMatthias Ringwald if (ltv_len > 1){
304*d21278d0SMatthias Ringwald metadata->ccids_num = btstack_min(ltv_len - 1, LE_CCIDS_MAX_NUM);
3055deb0bb6SMatthias Ringwald memcpy(metadata->ccids, &buffer[offset+1], metadata->ccids_num);
3065deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << ltv_type);
307*d21278d0SMatthias Ringwald }
3085deb0bb6SMatthias Ringwald break;
3095deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
3105deb0bb6SMatthias Ringwald parental_rating = (le_audio_parental_rating_t)buffer[offset+1];
3115deb0bb6SMatthias Ringwald metadata->parental_rating = parental_rating;
3125deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << ltv_type);
3135deb0bb6SMatthias Ringwald break;
3145deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
3155deb0bb6SMatthias Ringwald metadata->program_info_uri_length = btstack_min(ltv_len, LE_AUDIO_PROGRAM_INFO_URI_MAX_LENGTH);
3165deb0bb6SMatthias Ringwald memcpy(metadata->program_info_uri, &buffer[offset+1], metadata->program_info_uri_length);
3175deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << ltv_type);
3185deb0bb6SMatthias Ringwald break;
3195deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_EXTENDED_METADATA:
3205deb0bb6SMatthias Ringwald if (ltv_len < 2){
3215deb0bb6SMatthias Ringwald break;
3225deb0bb6SMatthias Ringwald }
3235deb0bb6SMatthias Ringwald metadata->extended_metadata_length = btstack_min(ltv_len - 2, LE_AUDIO_EXTENDED_METADATA_MAX_LENGHT);
3245deb0bb6SMatthias Ringwald metadata->extended_metadata_type = little_endian_read_16(buffer, offset+1);
3255deb0bb6SMatthias Ringwald memcpy(metadata->extended_metadata, &buffer[offset+3], metadata->extended_metadata_length);
3265deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION);
3275deb0bb6SMatthias Ringwald break;
3285deb0bb6SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_VENDOR_SPECIFIC_METADATA:
3295deb0bb6SMatthias Ringwald if (ltv_len < 2){
3305deb0bb6SMatthias Ringwald break;
3315deb0bb6SMatthias Ringwald }
3325deb0bb6SMatthias Ringwald metadata->vendor_specific_metadata_length = btstack_min(ltv_len - 2, LE_AUDIO_VENDOR_SPECIFIC_METADATA_MAX_LENGTH);
3335deb0bb6SMatthias Ringwald metadata->vendor_specific_company_id = little_endian_read_16(buffer, offset+1);
3345deb0bb6SMatthias Ringwald memcpy(metadata->vendor_specific_metadata, &buffer[offset+3], metadata->vendor_specific_metadata_length);
3355deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION);
3365deb0bb6SMatthias Ringwald break;
3375deb0bb6SMatthias Ringwald default:
3385deb0bb6SMatthias Ringwald metadata->metadata_mask |= (1 << LE_AUDIO_METADATA_TYPE_RFU);
339*d21278d0SMatthias Ringwald metadata->unsupported_type = ltv_type;
3405deb0bb6SMatthias Ringwald break;
3415deb0bb6SMatthias Ringwald }
3425deb0bb6SMatthias Ringwald offset += ltv_len;
3435deb0bb6SMatthias Ringwald }
3445deb0bb6SMatthias Ringwald return offset;
3455deb0bb6SMatthias Ringwald }
3465deb0bb6SMatthias Ringwald
le_audio_util_metadata_serialize(const le_audio_metadata_t * metadata,uint8_t * event,uint16_t event_size)347f67c2203SMatthias Ringwald uint16_t le_audio_util_metadata_serialize(const le_audio_metadata_t *metadata, uint8_t * event, uint16_t event_size){
348a2763e0cSDirk Helbig UNUSED(event_size);
349a2763e0cSDirk Helbig
3505deb0bb6SMatthias Ringwald uint8_t pos = 0;
3515deb0bb6SMatthias Ringwald
3525deb0bb6SMatthias Ringwald event[pos++] = (uint8_t)metadata->metadata_mask;
3535deb0bb6SMatthias Ringwald little_endian_store_16(event, pos, metadata->preferred_audio_contexts_mask);
3545deb0bb6SMatthias Ringwald pos += 2;
3555deb0bb6SMatthias Ringwald little_endian_store_16(event, pos, metadata->streaming_audio_contexts_mask);
3565deb0bb6SMatthias Ringwald pos += 2;
3575deb0bb6SMatthias Ringwald
3585deb0bb6SMatthias Ringwald event[pos++] = metadata->program_info_length;
3595deb0bb6SMatthias Ringwald memcpy(&event[pos], &metadata->program_info[0], metadata->program_info_length);
3605deb0bb6SMatthias Ringwald pos += metadata->program_info_length;
3615deb0bb6SMatthias Ringwald
3625deb0bb6SMatthias Ringwald little_endian_store_24(event, pos, metadata->language_code);
3635deb0bb6SMatthias Ringwald pos += 3;
3645deb0bb6SMatthias Ringwald
3655deb0bb6SMatthias Ringwald event[pos++] = metadata->ccids_num;
3665deb0bb6SMatthias Ringwald memcpy(&event[pos], &metadata->ccids[0], metadata->ccids_num);
3675deb0bb6SMatthias Ringwald pos += metadata->ccids_num;
3685deb0bb6SMatthias Ringwald
3695deb0bb6SMatthias Ringwald event[pos++] = (uint8_t)metadata->parental_rating;
3705deb0bb6SMatthias Ringwald
3715deb0bb6SMatthias Ringwald event[pos++] = metadata->program_info_uri_length;
3725deb0bb6SMatthias Ringwald memcpy(&event[pos], &metadata->program_info_uri[0], metadata->program_info_uri_length);
3735deb0bb6SMatthias Ringwald pos += metadata->program_info_uri_length;
3745deb0bb6SMatthias Ringwald
3755deb0bb6SMatthias Ringwald little_endian_store_16(event, pos, metadata->extended_metadata_type);
3765deb0bb6SMatthias Ringwald pos += 2;
3775deb0bb6SMatthias Ringwald
3785deb0bb6SMatthias Ringwald event[pos++] = metadata->extended_metadata_length;
3795deb0bb6SMatthias Ringwald memcpy(&event[pos], &metadata->extended_metadata[0], metadata->extended_metadata_length);
3805deb0bb6SMatthias Ringwald pos += metadata->extended_metadata_length;
3815deb0bb6SMatthias Ringwald
3825deb0bb6SMatthias Ringwald little_endian_store_16(event, pos, metadata->vendor_specific_company_id);
3835deb0bb6SMatthias Ringwald pos += 2;
3845deb0bb6SMatthias Ringwald
3855deb0bb6SMatthias Ringwald event[pos++] = metadata->vendor_specific_metadata_length;
3865deb0bb6SMatthias Ringwald memcpy(&event[pos], &metadata->vendor_specific_metadata[0], metadata->vendor_specific_metadata_length);
3875deb0bb6SMatthias Ringwald pos += metadata->vendor_specific_metadata_length;
3885deb0bb6SMatthias Ringwald
3895deb0bb6SMatthias Ringwald return pos;
3905deb0bb6SMatthias Ringwald }
391fd6b825bSMatthias Ringwald
le_audio_util_get_value_size_for_metadata_type(const le_audio_metadata_t * metadata,le_audio_metadata_type_t metadata_type)392f67c2203SMatthias Ringwald 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){
393fd6b825bSMatthias Ringwald switch (metadata_type){
394fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
395fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
396fd6b825bSMatthias Ringwald return 2;
397fd6b825bSMatthias Ringwald
398fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
399fd6b825bSMatthias Ringwald return metadata->program_info_length;
400fd6b825bSMatthias Ringwald
401fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_LANGUAGE:
402fd6b825bSMatthias Ringwald return 3;
403fd6b825bSMatthias Ringwald
404fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_CCID_LIST:
405fd6b825bSMatthias Ringwald return metadata->ccids_num;
406fd6b825bSMatthias Ringwald
407fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
408fd6b825bSMatthias Ringwald return 1;
409fd6b825bSMatthias Ringwald
410fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
411fd6b825bSMatthias Ringwald return metadata->program_info_uri_length;
412fd6b825bSMatthias Ringwald
413fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
414fd6b825bSMatthias Ringwald return 2 + metadata->extended_metadata_length;
415fd6b825bSMatthias Ringwald
416fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
417fd6b825bSMatthias Ringwald return 2 + metadata->vendor_specific_metadata_length;
418fd6b825bSMatthias Ringwald default:
419fd6b825bSMatthias Ringwald break;
420fd6b825bSMatthias Ringwald }
421fd6b825bSMatthias Ringwald return 0;
422fd6b825bSMatthias Ringwald }
423fd6b825bSMatthias Ringwald
le_audio_util_metadata_serialize_using_mask(const le_audio_metadata_t * metadata,uint8_t * tlv_buffer,uint16_t tlv_buffer_size)424f67c2203SMatthias Ringwald uint16_t le_audio_util_metadata_serialize_using_mask(const le_audio_metadata_t *metadata, uint8_t * tlv_buffer, uint16_t tlv_buffer_size){
425fd6b825bSMatthias Ringwald uint16_t metadata_type;
426fd6b825bSMatthias Ringwald uint16_t pos = 0;
427fd6b825bSMatthias Ringwald
428fd6b825bSMatthias Ringwald uint16_t remaining_bytes = tlv_buffer_size;
429fd6b825bSMatthias Ringwald
430fd6b825bSMatthias Ringwald for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
431fd6b825bSMatthias Ringwald if ((metadata->metadata_mask & (1 << metadata_type)) == 0){
432fd6b825bSMatthias Ringwald continue;
433fd6b825bSMatthias Ringwald }
434fd6b825bSMatthias Ringwald
435fd6b825bSMatthias Ringwald uint8_t payload_length = le_audio_util_get_value_size_for_metadata_type(metadata, (le_audio_metadata_type_t)metadata_type);
436fd6b825bSMatthias Ringwald // ensure that there is enough space in TLV to store length (1), type(1) and payload
437fd6b825bSMatthias Ringwald if (remaining_bytes < (2 + payload_length)){
438fd6b825bSMatthias Ringwald return pos;
439fd6b825bSMatthias Ringwald }
440fd6b825bSMatthias Ringwald
441fd6b825bSMatthias Ringwald tlv_buffer[pos++] = 1 + payload_length; // add one extra byte to count size of type (1 byte)
442fd6b825bSMatthias Ringwald tlv_buffer[pos++] = metadata_type;
443fd6b825bSMatthias Ringwald
444fd6b825bSMatthias Ringwald switch ((le_audio_metadata_type_t)metadata_type){
445fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
446fd6b825bSMatthias Ringwald little_endian_store_16(tlv_buffer, pos, metadata->preferred_audio_contexts_mask);
447fd6b825bSMatthias Ringwald break;
448fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
449fd6b825bSMatthias Ringwald little_endian_store_16(tlv_buffer, pos, metadata->streaming_audio_contexts_mask);
450fd6b825bSMatthias Ringwald break;
451fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
452fd6b825bSMatthias Ringwald memcpy(&tlv_buffer[pos], metadata->program_info, metadata->program_info_length);
453fd6b825bSMatthias Ringwald break;
454fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_LANGUAGE:
455fd6b825bSMatthias Ringwald little_endian_store_24(tlv_buffer, pos, metadata->language_code);
456fd6b825bSMatthias Ringwald break;
457fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_CCID_LIST:
458fd6b825bSMatthias Ringwald memcpy(&tlv_buffer[pos], metadata->ccids, metadata->ccids_num);
459fd6b825bSMatthias Ringwald break;
460fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
461fd6b825bSMatthias Ringwald break;
462fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
463fd6b825bSMatthias Ringwald memcpy(&tlv_buffer[pos], metadata->program_info_uri, metadata->program_info_uri_length);
464fd6b825bSMatthias Ringwald break;
465fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
466fd6b825bSMatthias Ringwald little_endian_store_16(tlv_buffer, pos, metadata->extended_metadata_type);
467fd6b825bSMatthias Ringwald memcpy(&tlv_buffer[pos + 2], metadata->extended_metadata, metadata->extended_metadata_length);
468fd6b825bSMatthias Ringwald break;
469fd6b825bSMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
470fd6b825bSMatthias Ringwald little_endian_store_16(tlv_buffer, pos, metadata->vendor_specific_company_id);
471fd6b825bSMatthias Ringwald memcpy(&tlv_buffer[pos + 2], metadata->vendor_specific_metadata, metadata->vendor_specific_metadata_length);
472fd6b825bSMatthias Ringwald break;
473fd6b825bSMatthias Ringwald default:
474fd6b825bSMatthias Ringwald break;
475fd6b825bSMatthias Ringwald }
476fd6b825bSMatthias Ringwald pos += payload_length;
477fd6b825bSMatthias Ringwald remaining_bytes -= (payload_length + 2);
478fd6b825bSMatthias Ringwald }
479fd6b825bSMatthias Ringwald return pos;
480fd6b825bSMatthias Ringwald }
481597c9a4eSMilanka Ringwald
le_audio_util_get_btstack_lc3_frame_duration(le_audio_codec_frame_duration_index_t frame_duration_index)48209d23cbeSMilanka Ringwald btstack_lc3_frame_duration_t le_audio_util_get_btstack_lc3_frame_duration(le_audio_codec_frame_duration_index_t frame_duration_index){
48309d23cbeSMilanka Ringwald switch (frame_duration_index){
484597c9a4eSMilanka Ringwald case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US:
485597c9a4eSMilanka Ringwald return BTSTACK_LC3_FRAME_DURATION_7500US;
486597c9a4eSMilanka Ringwald case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US:
487597c9a4eSMilanka Ringwald return BTSTACK_LC3_FRAME_DURATION_10000US;
488597c9a4eSMilanka Ringwald default:
489597c9a4eSMilanka Ringwald btstack_assert(false);
490597c9a4eSMilanka Ringwald break;
491597c9a4eSMilanka Ringwald }
492597c9a4eSMilanka Ringwald return 0;
493597c9a4eSMilanka Ringwald }
494597c9a4eSMilanka Ringwald
le_audio_get_frame_duration_us(le_audio_codec_frame_duration_index_t frame_duration_index)49509d23cbeSMilanka Ringwald uint16_t le_audio_get_frame_duration_us(le_audio_codec_frame_duration_index_t frame_duration_index){
49609d23cbeSMilanka Ringwald switch (frame_duration_index){
497597c9a4eSMilanka Ringwald case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US:
498597c9a4eSMilanka Ringwald return 7500;
499597c9a4eSMilanka Ringwald case LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US:
500597c9a4eSMilanka Ringwald return 10000;
501597c9a4eSMilanka Ringwald default:
502597c9a4eSMilanka Ringwald return 0;
503597c9a4eSMilanka Ringwald }
504597c9a4eSMilanka Ringwald }
50509d23cbeSMilanka Ringwald
le_audio_get_frame_duration_index(uint16_t frame_duration_us)50609d23cbeSMilanka Ringwald le_audio_codec_frame_duration_index_t le_audio_get_frame_duration_index(uint16_t frame_duration_us){
50709d23cbeSMilanka Ringwald switch (frame_duration_us){
50809d23cbeSMilanka Ringwald case 7500:
50909d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_7500US;
51009d23cbeSMilanka Ringwald case 10000:
51109d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_10000US;
51209d23cbeSMilanka Ringwald default:
51309d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_FRAME_DURATION_INDEX_RFU;
51409d23cbeSMilanka Ringwald }
51509d23cbeSMilanka Ringwald }
51609d23cbeSMilanka Ringwald
le_audio_get_sampling_frequency_hz(le_audio_codec_sampling_frequency_index_t sampling_frequency_index)51709d23cbeSMilanka Ringwald uint32_t le_audio_get_sampling_frequency_hz(le_audio_codec_sampling_frequency_index_t sampling_frequency_index){
51809d23cbeSMilanka Ringwald switch (sampling_frequency_index){
51909d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ:
52009d23cbeSMilanka Ringwald return 8000;
52109d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_11025_HZ:
52209d23cbeSMilanka Ringwald return 11025;
52309d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ:
52409d23cbeSMilanka Ringwald return 16000;
52509d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_22050_HZ:
52609d23cbeSMilanka Ringwald return 22050;
52709d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ:
52809d23cbeSMilanka Ringwald return 24000;
52909d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ:
53009d23cbeSMilanka Ringwald return 32000;
53109d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ:
53209d23cbeSMilanka Ringwald return 44100;
53309d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ:
53409d23cbeSMilanka Ringwald return 48000;
53509d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_88200_HZ:
53609d23cbeSMilanka Ringwald return 88200;
53709d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_96000_HZ:
53809d23cbeSMilanka Ringwald return 96000;
53909d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_176400_HZ:
54009d23cbeSMilanka Ringwald return 176400;
54109d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_192000_HZ:
54209d23cbeSMilanka Ringwald return 192000;
54309d23cbeSMilanka Ringwald case LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_384000_HZ:
54409d23cbeSMilanka Ringwald return 384000;
54509d23cbeSMilanka Ringwald default:
54677a8d8daSMatthias Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_INVALID;
54709d23cbeSMilanka Ringwald }
54809d23cbeSMilanka Ringwald }
54909d23cbeSMilanka Ringwald
le_audio_get_sampling_frequency_index(uint32_t sampling_frequency_hz)55009d23cbeSMilanka Ringwald le_audio_codec_sampling_frequency_index_t le_audio_get_sampling_frequency_index(uint32_t sampling_frequency_hz){
55109d23cbeSMilanka Ringwald switch (sampling_frequency_hz){
55209d23cbeSMilanka Ringwald case 0:
55309d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_INVALID;
55409d23cbeSMilanka Ringwald case 8000:
55509d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_8000_HZ;
55609d23cbeSMilanka Ringwald case 11025:
55709d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_11025_HZ;
55809d23cbeSMilanka Ringwald case 16000:
55909d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_16000_HZ;
56009d23cbeSMilanka Ringwald case 22050:
56109d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_22050_HZ;
56209d23cbeSMilanka Ringwald case 24000:
56309d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_24000_HZ;
56409d23cbeSMilanka Ringwald case 32000:
56509d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_32000_HZ;
56609d23cbeSMilanka Ringwald case 44100:
56709d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_44100_HZ;
56809d23cbeSMilanka Ringwald case 48000:
56909d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_48000_HZ;
57009d23cbeSMilanka Ringwald case 88200:
57109d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_88200_HZ;
57209d23cbeSMilanka Ringwald case 96000:
57309d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_96000_HZ;
57409d23cbeSMilanka Ringwald case 176400:
57509d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_176400_HZ;
57609d23cbeSMilanka Ringwald case 192000:
57709d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_192000_HZ;
57809d23cbeSMilanka Ringwald case 384000:
57909d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_384000_HZ;
58009d23cbeSMilanka Ringwald default:
58109d23cbeSMilanka Ringwald return LE_AUDIO_CODEC_SAMPLING_FREQUENCY_INDEX_RFU;
58209d23cbeSMilanka Ringwald }
58309d23cbeSMilanka Ringwald }
58409d23cbeSMilanka Ringwald
le_audio_util_metadata_using_mask_from_metadata_event(const uint8_t * packet,uint16_t packet_size,le_audio_metadata_t * metadata_out)585*d21278d0SMatthias Ringwald 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*d21278d0SMatthias Ringwald UNUSED(packet_size);
587*d21278d0SMatthias Ringwald btstack_assert(metadata_out != NULL);
588*d21278d0SMatthias Ringwald if (packet_size == 0){
589*d21278d0SMatthias Ringwald return;
590*d21278d0SMatthias Ringwald }
591*d21278d0SMatthias Ringwald
592*d21278d0SMatthias Ringwald memset(metadata_out, 0, sizeof(le_audio_metadata_t));
593*d21278d0SMatthias Ringwald metadata_out->metadata_mask = leaudio_subevent_ascs_server_metadata_get_metadata_mask(packet);
594*d21278d0SMatthias Ringwald
595*d21278d0SMatthias Ringwald uint16_t metadata_type;
596*d21278d0SMatthias Ringwald for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
597*d21278d0SMatthias Ringwald if ((metadata_out->metadata_mask & (1 << metadata_type) ) != 0 ){
598*d21278d0SMatthias Ringwald
599*d21278d0SMatthias Ringwald switch ((le_audio_metadata_type_t)metadata_type){
600*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
601*d21278d0SMatthias Ringwald metadata_out->preferred_audio_contexts_mask = leaudio_subevent_ascs_server_metadata_get_preferred_audio_contexts_mask(packet);
602*d21278d0SMatthias Ringwald break;
603*d21278d0SMatthias Ringwald
604*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
605*d21278d0SMatthias Ringwald metadata_out->streaming_audio_contexts_mask = leaudio_subevent_ascs_server_metadata_get_streaming_audio_contexts_mask(packet);
606*d21278d0SMatthias Ringwald break;
607*d21278d0SMatthias Ringwald
608*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
609*d21278d0SMatthias Ringwald metadata_out->program_info_length = leaudio_subevent_ascs_server_metadata_get_program_info_length(packet);
610*d21278d0SMatthias Ringwald memcpy(metadata_out->program_info, leaudio_subevent_ascs_server_metadata_get_program_info(packet), metadata_out->program_info_length);
611*d21278d0SMatthias Ringwald break;
612*d21278d0SMatthias Ringwald
613*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_LANGUAGE:
614*d21278d0SMatthias Ringwald metadata_out->language_code = leaudio_subevent_ascs_server_metadata_get_language_code(packet);
615*d21278d0SMatthias Ringwald break;
616*d21278d0SMatthias Ringwald
617*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_CCID_LIST:
618*d21278d0SMatthias Ringwald metadata_out->ccids_num = leaudio_subevent_ascs_server_metadata_get_ccids_num(packet);
619*d21278d0SMatthias Ringwald memcpy(metadata_out->ccids, leaudio_subevent_ascs_server_metadata_get_ccids(packet), metadata_out->ccids_num);
620*d21278d0SMatthias Ringwald break;
621*d21278d0SMatthias Ringwald
622*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
623*d21278d0SMatthias Ringwald metadata_out->parental_rating = (le_audio_parental_rating_t)leaudio_subevent_ascs_server_metadata_get_parental_rating(packet);
624*d21278d0SMatthias Ringwald break;
625*d21278d0SMatthias Ringwald
626*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
627*d21278d0SMatthias Ringwald metadata_out->program_info_uri_length = leaudio_subevent_ascs_server_metadata_get_program_info_uri_length(packet);
628*d21278d0SMatthias Ringwald memcpy(metadata_out->program_info_uri, leaudio_subevent_ascs_server_metadata_get_program_info_uri(packet), metadata_out->program_info_uri_length);
629*d21278d0SMatthias Ringwald break;
630*d21278d0SMatthias Ringwald
631*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
632*d21278d0SMatthias Ringwald metadata_out->extended_metadata_type = leaudio_subevent_ascs_server_metadata_get_extended_metadata_type(packet);
633*d21278d0SMatthias Ringwald metadata_out->extended_metadata_length = leaudio_subevent_ascs_server_metadata_get_extended_metadata_value_length(packet);
634*d21278d0SMatthias Ringwald memcpy(metadata_out->extended_metadata, leaudio_subevent_ascs_server_metadata_get_extended_metadata_value(packet), metadata_out->extended_metadata_length);
635*d21278d0SMatthias Ringwald break;
636*d21278d0SMatthias Ringwald
637*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
638*d21278d0SMatthias Ringwald metadata_out->vendor_specific_company_id = leaudio_subevent_ascs_server_metadata_get_vendor_specific_metadata_type(packet);
639*d21278d0SMatthias Ringwald metadata_out->vendor_specific_metadata_length = leaudio_subevent_ascs_server_metadata_get_vendor_specific_metadata_value_length(packet);
640*d21278d0SMatthias Ringwald memcpy(metadata_out->vendor_specific_metadata, leaudio_subevent_ascs_server_metadata_get_vendor_specific_metadata_value(packet), metadata_out->vendor_specific_metadata_length);
641*d21278d0SMatthias Ringwald break;
642*d21278d0SMatthias Ringwald
643*d21278d0SMatthias Ringwald default:
644*d21278d0SMatthias Ringwald btstack_assert(false);
645*d21278d0SMatthias Ringwald break;
646*d21278d0SMatthias Ringwald }
647*d21278d0SMatthias Ringwald }
648*d21278d0SMatthias Ringwald }
649*d21278d0SMatthias Ringwald }
650*d21278d0SMatthias Ringwald
le_audio_util_metadata_using_mask_from_enable_event(const uint8_t * packet,uint16_t packet_size,le_audio_metadata_t * metadata_out)651*d21278d0SMatthias Ringwald 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*d21278d0SMatthias Ringwald UNUSED(packet_size);
653*d21278d0SMatthias Ringwald btstack_assert(metadata_out != NULL);
654*d21278d0SMatthias Ringwald if (packet_size == 0){
655*d21278d0SMatthias Ringwald return;
656*d21278d0SMatthias Ringwald }
657*d21278d0SMatthias Ringwald
658*d21278d0SMatthias Ringwald memset(metadata_out, 0, sizeof(le_audio_metadata_t));
659*d21278d0SMatthias Ringwald metadata_out->metadata_mask = leaudio_subevent_ascs_server_metadata_get_metadata_mask(packet);
660*d21278d0SMatthias Ringwald
661*d21278d0SMatthias Ringwald uint16_t metadata_type;
662*d21278d0SMatthias Ringwald for (metadata_type = (uint16_t)LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS; metadata_type < (uint16_t) LE_AUDIO_METADATA_TYPE_RFU; metadata_type++){
663*d21278d0SMatthias Ringwald if ((metadata_out->metadata_mask & (1 << metadata_type) ) != 0 ){
664*d21278d0SMatthias Ringwald
665*d21278d0SMatthias Ringwald switch ((le_audio_metadata_type_t)metadata_type){
666*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PREFERRED_AUDIO_CONTEXTS:
667*d21278d0SMatthias Ringwald metadata_out->preferred_audio_contexts_mask = leaudio_subevent_ascs_server_enable_get_preferred_audio_contexts_mask(packet);
668*d21278d0SMatthias Ringwald break;
669*d21278d0SMatthias Ringwald
670*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_STREAMING_AUDIO_CONTEXTS:
671*d21278d0SMatthias Ringwald metadata_out->streaming_audio_contexts_mask = leaudio_subevent_ascs_server_enable_get_streaming_audio_contexts_mask(packet);
672*d21278d0SMatthias Ringwald break;
673*d21278d0SMatthias Ringwald
674*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO:
675*d21278d0SMatthias Ringwald metadata_out->program_info_length = leaudio_subevent_ascs_server_enable_get_program_info_length(packet);
676*d21278d0SMatthias Ringwald memcpy(metadata_out->program_info, leaudio_subevent_ascs_server_enable_get_program_info(packet), metadata_out->program_info_length);
677*d21278d0SMatthias Ringwald break;
678*d21278d0SMatthias Ringwald
679*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_LANGUAGE:
680*d21278d0SMatthias Ringwald metadata_out->language_code = leaudio_subevent_ascs_server_enable_get_language_code(packet);
681*d21278d0SMatthias Ringwald break;
682*d21278d0SMatthias Ringwald
683*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_CCID_LIST:
684*d21278d0SMatthias Ringwald metadata_out->ccids_num = leaudio_subevent_ascs_server_enable_get_ccids_num(packet);
685*d21278d0SMatthias Ringwald memcpy(metadata_out->ccids, leaudio_subevent_ascs_server_enable_get_ccids(packet), metadata_out->ccids_num);
686*d21278d0SMatthias Ringwald break;
687*d21278d0SMatthias Ringwald
688*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PARENTAL_RATING:
689*d21278d0SMatthias Ringwald metadata_out->parental_rating = (le_audio_parental_rating_t)leaudio_subevent_ascs_server_enable_get_parental_rating(packet);
690*d21278d0SMatthias Ringwald break;
691*d21278d0SMatthias Ringwald
692*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI:
693*d21278d0SMatthias Ringwald metadata_out->program_info_uri_length = leaudio_subevent_ascs_server_enable_get_program_info_uri_length(packet);
694*d21278d0SMatthias Ringwald memcpy(metadata_out->program_info_uri, leaudio_subevent_ascs_server_enable_get_program_info_uri(packet), metadata_out->program_info_uri_length);
695*d21278d0SMatthias Ringwald break;
696*d21278d0SMatthias Ringwald
697*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_EXTENDED_METADATA_BIT_POSITION:
698*d21278d0SMatthias Ringwald metadata_out->extended_metadata_type = leaudio_subevent_ascs_server_enable_get_extended_metadata_type(packet);
699*d21278d0SMatthias Ringwald metadata_out->extended_metadata_length = leaudio_subevent_ascs_server_enable_get_extended_metadata_value_length(packet);
700*d21278d0SMatthias Ringwald memcpy(metadata_out->extended_metadata, leaudio_subevent_ascs_server_enable_get_extended_metadata_value(packet), metadata_out->extended_metadata_length);
701*d21278d0SMatthias Ringwald break;
702*d21278d0SMatthias Ringwald
703*d21278d0SMatthias Ringwald case LE_AUDIO_METADATA_TYPE_MAPPED_VENDOR_SPECIFIC_METADATA_BIT_POSITION:
704*d21278d0SMatthias Ringwald metadata_out->vendor_specific_company_id = leaudio_subevent_ascs_server_enable_get_vendor_specific_metadata_type(packet);
705*d21278d0SMatthias Ringwald metadata_out->vendor_specific_metadata_length = leaudio_subevent_ascs_server_enable_get_vendor_specific_metadata_value_length(packet);
706*d21278d0SMatthias Ringwald memcpy(metadata_out->vendor_specific_metadata, leaudio_subevent_ascs_server_enable_get_vendor_specific_metadata_value(packet), metadata_out->vendor_specific_metadata_length);
707*d21278d0SMatthias Ringwald break;
708*d21278d0SMatthias Ringwald
709*d21278d0SMatthias Ringwald default:
710*d21278d0SMatthias Ringwald btstack_assert(false);
711*d21278d0SMatthias Ringwald break;
712*d21278d0SMatthias Ringwald }
713*d21278d0SMatthias Ringwald }
714*d21278d0SMatthias Ringwald }
715*d21278d0SMatthias Ringwald }
7169ef2c435SMilanka Ringwald
717