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