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