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__ "broadcast_audio_scan_service_client.c" 39 40 #include "ble/att_db.h" 41 #include "ble/att_server.h" 42 #include "bluetooth_gatt.h" 43 #include "btstack_debug.h" 44 #include "btstack_defines.h" 45 #include "btstack_event.h" 46 #include "btstack_util.h" 47 #include "btstack_memory.h" 48 49 #include "le-audio/le_audio_util.h" 50 #include "le-audio/gatt-service/broadcast_audio_scan_service_client.h" 51 52 #ifdef ENABLE_TESTING_SUPPORT 53 #include <stdio.h> 54 #endif 55 56 static btstack_linked_list_t bass_connections; 57 58 static uint16_t bass_client_cid_counter = 0; 59 static btstack_packet_handler_t bass_event_callback; 60 61 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 62 63 static uint16_t bass_client_get_next_cid(void){ 64 bass_client_cid_counter = btstack_next_cid_ignoring_zero(bass_client_cid_counter); 65 return bass_client_cid_counter; 66 } 67 68 static void bass_client_finalize_connection(bass_client_connection_t * connection){ 69 btstack_linked_list_remove(&bass_connections, (btstack_linked_item_t*) connection); 70 } 71 72 static bass_client_connection_t * bass_client_get_connection_for_con_handle(hci_con_handle_t con_handle){ 73 btstack_linked_list_iterator_t it; 74 btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &bass_connections); 75 while (btstack_linked_list_iterator_has_next(&it)){ 76 bass_client_connection_t * connection = (bass_client_connection_t *)btstack_linked_list_iterator_next(&it); 77 if (connection->con_handle != con_handle) continue; 78 return connection; 79 } 80 return NULL; 81 } 82 83 static bass_client_connection_t * bass_get_client_for_cid(uint16_t bass_cid){ 84 btstack_linked_list_iterator_t it; 85 btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &bass_connections); 86 while (btstack_linked_list_iterator_has_next(&it)){ 87 bass_client_connection_t * connection = (bass_client_connection_t *)btstack_linked_list_iterator_next(&it); 88 if (connection->cid != bass_cid) continue; 89 return connection; 90 } 91 return NULL; 92 } 93 94 static bass_client_source_t * bass_get_receive_state_for_value_handle(bass_client_connection_t * connection, uint16_t value_handle){ 95 uint8_t i; 96 for (i = 0; i < connection->receive_states_instances_num; i++){ 97 if (connection->receive_states[i].receive_state_value_handle == value_handle){ 98 return &connection->receive_states[i]; 99 } 100 } 101 return NULL; 102 } 103 104 static bass_client_source_t * bass_get_source_for_source_id(bass_client_connection_t * connection, uint8_t source_id){ 105 uint8_t i; 106 for (i = 0; i < connection->receive_states_instances_num; i++){ 107 if (connection->receive_states[i].source_id == source_id){ 108 return &connection->receive_states[i]; 109 } 110 } 111 return NULL; 112 } 113 114 static void bass_client_reset_source(bass_client_source_t * source){ 115 if (source == NULL){ 116 return; 117 } 118 source->source_id = BASS_INVALID_SOURCE_INDEX; 119 source->in_use = false; 120 memset(&source->data, 0, sizeof(bass_source_data_t)); 121 } 122 123 static void bass_client_emit_connection_established(bass_client_connection_t * connection, uint8_t status){ 124 uint8_t event[8]; 125 uint16_t pos = 0; 126 event[pos++] = HCI_EVENT_GATTSERVICE_META; 127 event[pos++] = sizeof(event) - 2; 128 event[pos++] = GATTSERVICE_SUBEVENT_BASS_CONNECTED; 129 little_endian_store_16(event, pos, connection->con_handle); 130 pos += 2; 131 little_endian_store_16(event, pos, connection->cid); 132 pos += 2; 133 event[pos++] = status; 134 (*bass_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 135 } 136 137 static void bass_client_emit_scan_operation_complete(bass_client_connection_t * connection, uint8_t status, bass_opcode_t opcode){ 138 uint8_t event[7]; 139 uint16_t pos = 0; 140 event[pos++] = HCI_EVENT_GATTSERVICE_META; 141 event[pos++] = sizeof(event) - 2; 142 event[pos++] = GATTSERVICE_SUBEVENT_BASS_SCAN_OPERATION_COMPLETE; 143 little_endian_store_16(event, pos, connection->cid); 144 pos += 2; 145 event[pos++] = status; 146 event[pos++] = (uint8_t)opcode; 147 (*bass_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 148 } 149 150 static void bass_client_emit_source_operation_complete(bass_client_connection_t * connection, uint8_t status, bass_opcode_t opcode, uint8_t source_id){ 151 uint8_t event[8]; 152 uint16_t pos = 0; 153 event[pos++] = HCI_EVENT_GATTSERVICE_META; 154 event[pos++] = sizeof(event) - 2; 155 event[pos++] = GATTSERVICE_SUBEVENT_BASS_SOURCE_OPERATION_COMPLETE; 156 little_endian_store_16(event, pos, connection->cid); 157 pos += 2; 158 event[pos++] = status; 159 event[pos++] = (uint8_t)opcode; 160 event[pos++] = source_id; 161 (*bass_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 162 } 163 164 static void bass_client_emit_receive_state(bass_client_connection_t * connection, uint8_t source_id){ 165 uint8_t pos = 0; 166 uint8_t event[7]; 167 event[pos++] = HCI_EVENT_GATTSERVICE_META; 168 event[pos++] = sizeof(event) - 2; 169 event[pos++] = GATTSERVICE_SUBEVENT_BASS_NOTIFICATION_COMPLETE; 170 little_endian_store_16(event, pos, connection->cid); 171 pos += 2; 172 event[pos++] = source_id; 173 (*bass_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 174 } 175 176 static bool bass_client_remote_broadcast_receive_state_buffer_valid(uint8_t *buffer, uint16_t buffer_size){ 177 // minimal with zero subgroups 178 if (buffer_size < 15){ 179 return false; 180 } 181 182 uint16_t pos = 0; 183 184 // source_id 185 pos++; 186 187 // addr type 188 uint8_t adv_type = buffer[pos++]; 189 if (adv_type > (uint8_t)BD_ADDR_TYPE_LE_RANDOM){ 190 log_info("Unexpected adv_type 0x%02X", adv_type); 191 return false; 192 } 193 194 // address 195 pos += 6; 196 197 // advertising_sid Range: 0x00-0x0F 198 uint8_t advertising_sid = buffer[pos++]; 199 if (advertising_sid > 0x0F){ 200 log_info("Advertising sid out of range 0x%02X", advertising_sid); 201 return false; 202 } 203 204 // broadcast_id 205 pos += 3; 206 207 // pa_sync_state 208 uint8_t pa_sync_state = buffer[pos++]; 209 if (pa_sync_state >= (uint8_t)LE_AUDIO_PA_SYNC_STATE_RFU){ 210 log_info("Unexpected pa_sync_state 0x%02X", pa_sync_state); 211 return false; 212 } 213 214 // big_encryption 215 le_audio_big_encryption_t big_encryption = (le_audio_big_encryption_t) buffer[pos++]; 216 if (big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){ 217 // Bad Code 218 pos += 16; 219 } 220 221 // num subgroups 222 uint8_t num_subgroups = buffer[pos++]; 223 if (num_subgroups > BASS_SUBGROUPS_MAX_NUM){ 224 log_info("Number of subgroups %u exceedes maximum %u", num_subgroups, BASS_SUBGROUPS_MAX_NUM); 225 return false; 226 } 227 228 uint8_t i; 229 for (i = 0; i < num_subgroups; i++) { 230 // check if we can read bis_sync_state + meta_data_length 231 // bis_sync_state 232 pos += 4; 233 // meta_data_length 234 if (pos >= buffer_size){ 235 return false; 236 } 237 uint8_t metadata_length = buffer[pos++]; 238 if ((pos + metadata_length) > buffer_size){ 239 return false; 240 } 241 // metadata 242 pos += metadata_length; 243 } 244 return true; 245 } 246 247 static void handle_gatt_server_notification(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 248 UNUSED(packet_type); 249 UNUSED(channel); 250 UNUSED(size); 251 252 if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION){ 253 return; 254 } 255 256 bass_client_connection_t * connection = bass_client_get_connection_for_con_handle(channel); 257 if (connection == NULL){ 258 return; 259 } 260 261 uint16_t value_handle = gatt_event_notification_get_value_handle(packet); 262 uint16_t value_length = gatt_event_notification_get_value_length(packet); 263 uint8_t * value = (uint8_t *)gatt_event_notification_get_value(packet); 264 265 if (bass_client_remote_broadcast_receive_state_buffer_valid(value, value_length)){ 266 bass_client_source_t * source = bass_get_receive_state_for_value_handle(connection, value_handle); 267 if (source == NULL){ 268 return; 269 } 270 source->source_id = value[0]; 271 bass_util_source_data_parse(&value[1], value_length - 1, &source->data, true); 272 273 // get big encryption + bad code 274 source->big_encryption = (le_audio_big_encryption_t) value[13]; 275 if (source->big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){ 276 reverse_128(&value[14], source->bad_code); 277 } else { 278 memset(source->bad_code, 0, 16); 279 } 280 281 bass_client_emit_receive_state(connection, source->source_id); 282 } 283 } 284 285 static bool bass_client_register_notification(bass_client_connection_t * connection){ 286 bass_client_source_t * receive_state = &connection->receive_states[connection->receive_states_index]; 287 if (receive_state == NULL){ 288 return false; 289 } 290 291 gatt_client_characteristic_t characteristic; 292 characteristic.value_handle = receive_state->receive_state_value_handle; 293 characteristic.properties = receive_state->receive_state_properties; 294 characteristic.end_handle = connection->end_handle; 295 296 uint8_t status = gatt_client_write_client_characteristic_configuration( 297 &handle_gatt_client_event, 298 connection->con_handle, 299 &characteristic, 300 GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 301 302 // notification supported, register for value updates 303 if (status == ERROR_CODE_SUCCESS){ 304 gatt_client_listen_for_characteristic_value_updates( 305 &connection->notification_listener, 306 &handle_gatt_server_notification, 307 connection->con_handle, &characteristic); 308 } 309 return status; 310 } 311 312 static uint16_t bass_client_prepare_add_source_buffer(bass_client_connection_t * connection){ 313 const bass_source_data_t * receive_state = connection->control_point_operation_data; 314 315 uint16_t buffer_offset = connection->buffer_offset; 316 uint8_t * buffer = connection->buffer; 317 uint16_t buffer_size = btstack_min(sizeof(connection->buffer), connection->mtu); 318 319 btstack_assert(buffer_offset == 0); 320 321 uint8_t field_data[6]; 322 uint16_t source_offset = 0; 323 uint16_t stored_bytes = 0; 324 memset(buffer, 0, buffer_size); 325 326 field_data[0] = (uint8_t)BASS_OPCODE_ADD_SOURCE; 327 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 328 buffer_offset); 329 source_offset++; 330 331 stored_bytes += bass_util_source_data_header_virtual_memcpy(receive_state, &source_offset, buffer_offset, buffer, 332 buffer_size); 333 334 field_data[0] = (uint8_t)receive_state->pa_sync; 335 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 336 buffer_offset); 337 source_offset++; 338 339 little_endian_store_16(field_data, 0, receive_state->pa_interval); 340 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, source_offset, buffer, buffer_size, 341 buffer_offset); 342 source_offset += 2; 343 344 stored_bytes += bass_util_source_data_subgroups_virtual_memcpy(receive_state, false, &source_offset, buffer_offset, 345 buffer, 346 buffer_size); 347 348 return stored_bytes; 349 } 350 351 static uint16_t bass_client_prepare_modify_source_buffer(bass_client_connection_t * connection){ 352 const bass_source_data_t * receive_state = connection->control_point_operation_data; 353 354 uint16_t buffer_offset = connection->buffer_offset; 355 uint8_t * buffer = connection->buffer; 356 uint16_t buffer_size = btstack_min(sizeof(connection->buffer), connection->mtu); 357 358 btstack_assert(buffer_offset == 0); 359 360 uint8_t field_data[6]; 361 uint16_t source_offset = 0; 362 uint16_t stored_bytes = 0; 363 memset(buffer, 0, buffer_size); 364 365 field_data[0] = (uint8_t)BASS_OPCODE_MODIFY_SOURCE; 366 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 367 buffer_offset); 368 source_offset++; 369 370 field_data[0] = connection->control_point_operation_source_id; 371 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 372 buffer_offset); 373 source_offset++; 374 375 field_data[0] = (uint8_t)receive_state->pa_sync; 376 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 377 buffer_offset); 378 source_offset++; 379 380 little_endian_store_16(field_data, 0, receive_state->pa_interval); 381 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, source_offset, buffer, buffer_size, 382 buffer_offset); 383 source_offset += 2; 384 385 stored_bytes += bass_util_source_data_subgroups_virtual_memcpy(receive_state, false, &source_offset, buffer_offset, 386 buffer, 387 buffer_size); 388 return stored_bytes; 389 } 390 391 static uint16_t bass_client_receive_state_len(const bass_source_data_t * source_data){ 392 uint16_t source_len = 0; 393 // opcode(1), address_type(1), address(6), adv_sid(1), broadcast_id(3), pa_sync(1), subgroups_num(1) 394 source_len = 1 + 1 + 6 + 1 + 3 + 1 + 1; 395 396 uint8_t i; 397 for (i = 0; i < source_data->subgroups_num; i++){ 398 bass_subgroup_t subgroup = source_data->subgroups[i]; 399 // bis_sync(4), metadata_length(1), metadata_length 400 source_len += 4 + 1 + subgroup.metadata_length; 401 } 402 return source_len; 403 } 404 405 static void bass_client_run_for_connection(bass_client_connection_t * connection){ 406 uint8_t status; 407 gatt_client_characteristic_t characteristic; 408 gatt_client_service_t service; 409 410 uint8_t value[18]; 411 uint16_t stored_bytes; 412 413 switch (connection->state){ 414 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED: 415 break; 416 417 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_START_SCAN: 418 #ifdef ENABLE_TESTING_SUPPORT 419 printf(" Write START SCAN [0x%04X]:\n", 420 connection->control_point_value_handle); 421 #endif 422 423 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_START_SCAN; 424 value[0] = BASS_OPCODE_REMOTE_SCAN_STARTED; 425 // see GATT_EVENT_QUERY_COMPLETE for end of write 426 status = gatt_client_write_value_of_characteristic( 427 &handle_gatt_client_event, connection->con_handle, 428 connection->control_point_value_handle, 1, &value[0]); 429 UNUSED(status); 430 break; 431 432 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_STOP_SCAN: 433 #ifdef ENABLE_TESTING_SUPPORT 434 printf(" Write START SCAN [0x%04X]:\n", 435 connection->control_point_value_handle); 436 #endif 437 438 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_STOP_SCAN; 439 value[0] = BASS_OPCODE_REMOTE_SCAN_STOPPED; 440 // see GATT_EVENT_QUERY_COMPLETE for end of write 441 status = gatt_client_write_value_of_characteristic( 442 &handle_gatt_client_event, connection->con_handle, 443 connection->control_point_value_handle, 1, &value[0]); 444 UNUSED(status); 445 break; 446 447 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_ADD_SOURCE: 448 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE; 449 #ifdef ENABLE_TESTING_SUPPORT 450 printf(" ADD SOURCE [0x%04X]:\n", connection->control_point_value_handle); 451 #endif 452 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE; 453 stored_bytes = bass_client_prepare_add_source_buffer(connection); 454 connection->buffer_offset += stored_bytes; 455 456 gatt_client_write_long_value_of_characteristic(&handle_gatt_client_event, connection->con_handle, 457 connection->control_point_value_handle, stored_bytes, connection->buffer); 458 break; 459 460 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_MODIFY_SOURCE: 461 #ifdef ENABLE_TESTING_SUPPORT 462 printf(" MODIFY SOURCE [%d]:\n", connection->control_point_operation_source_id); 463 #endif 464 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_MODIFY_SOURCE; 465 stored_bytes = bass_client_prepare_modify_source_buffer(connection); 466 connection->buffer_offset += stored_bytes; 467 468 gatt_client_write_long_value_of_characteristic(&handle_gatt_client_event, connection->con_handle, 469 connection->control_point_value_handle, stored_bytes, connection->buffer); 470 471 break; 472 473 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_REMOVE_SOURCE: 474 #ifdef ENABLE_TESTING_SUPPORT 475 printf(" REMOVE SOURCE [%d]:\n", connection->control_point_operation_source_id); 476 #endif 477 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_REMOVE_SOURCE; 478 value[0] = BASS_OPCODE_REMOVE_SOURCE; 479 value[1] = connection->control_point_operation_source_id; 480 // see GATT_EVENT_QUERY_COMPLETE for end of write 481 status = gatt_client_write_value_of_characteristic( 482 &handle_gatt_client_event, connection->con_handle, 483 connection->control_point_value_handle, 2, &value[0]); 484 UNUSED(status); 485 break; 486 487 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_SET_BROADCAST_CODE: 488 #ifdef ENABLE_TESTING_SUPPORT 489 printf(" SET BROADCAST CODE [%d]:\n", connection->control_point_operation_source_id); 490 #endif 491 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_SET_BROADCAST_CODE; 492 value[0] = BASS_OPCODE_SET_BROADCAST_CODE; 493 value[1] = connection->control_point_operation_source_id; 494 reverse_128(connection->broadcast_code, &value[2]); 495 496 // see GATT_EVENT_QUERY_COMPLETE for end of write 497 status = gatt_client_write_value_of_characteristic( 498 &handle_gatt_client_event, connection->con_handle, 499 connection->control_point_value_handle, 18, &value[0]); 500 UNUSED(status); 501 break; 502 503 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE: 504 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT; 505 gatt_client_discover_primary_services_by_uuid16(&handle_gatt_client_event, connection->con_handle, ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE); 506 break; 507 508 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS: 509 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT; 510 511 service.start_group_handle = connection->start_handle; 512 service.end_group_handle = connection->end_handle; 513 service.uuid16 = ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE; 514 515 gatt_client_discover_characteristics_for_service( 516 &handle_gatt_client_event, 517 connection->con_handle, 518 &service); 519 520 break; 521 522 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS: 523 #ifdef ENABLE_TESTING_SUPPORT 524 printf("Read client characteristic descriptors [index %d]:\n", connection->receive_states_index); 525 #endif 526 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_DESCRIPTORS_RESULT; 527 characteristic.value_handle = connection->receive_states[connection->receive_states_index].receive_state_value_handle; 528 characteristic.properties = connection->receive_states[connection->receive_states_index].receive_state_properties; 529 characteristic.end_handle = connection->end_handle; 530 531 (void) gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, connection->con_handle, &characteristic); 532 break; 533 534 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION: 535 #ifdef ENABLE_TESTING_SUPPORT 536 printf("Read client characteristic value [index %d, handle 0x%04X]:\n", connection->receive_states_index, connection->receive_states[connection->receive_states_index].receive_state_ccc_handle); 537 #endif 538 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT; 539 540 // result in GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT 541 (void) gatt_client_read_characteristic_descriptor_using_descriptor_handle( 542 &handle_gatt_client_event, 543 connection->con_handle, 544 connection->receive_states[connection->receive_states_index].receive_state_ccc_handle); 545 break; 546 547 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION: 548 #ifdef ENABLE_TESTING_SUPPORT 549 printf("Register notification [index %d, handle 0x%04X]:\n", connection->receive_states_index, connection->receive_states[connection->receive_states_index].receive_state_ccc_handle); 550 #endif 551 552 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED; 553 554 status = bass_client_register_notification(connection); 555 if (status == ERROR_CODE_SUCCESS) return; 556 557 if (connection->receive_states[connection->receive_states_index].receive_state_ccc_handle != 0){ 558 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION; 559 break; 560 } 561 562 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 563 bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS); 564 break; 565 default: 566 break; 567 } 568 } 569 // @return true if client valid / run function should be called 570 static bool bass_client_handle_query_complete(bass_client_connection_t * connection, uint8_t status){ 571 switch (connection->state){ 572 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT: 573 if (status != ATT_ERROR_SUCCESS){ 574 bass_client_emit_connection_established(connection, status); 575 bass_client_finalize_connection(connection); 576 return false; 577 } 578 579 if (connection->service_instances_num == 0){ 580 bass_client_emit_connection_established(connection, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 581 bass_client_finalize_connection(connection); 582 return false; 583 } 584 connection->receive_states_index = 0; 585 connection->receive_states_instances_num = 0; 586 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS; 587 break; 588 589 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT: 590 if (status != ATT_ERROR_SUCCESS){ 591 bass_client_emit_connection_established(connection, status); 592 bass_client_finalize_connection(connection); 593 return false; 594 } 595 596 connection->receive_states_index = 0; 597 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS; 598 break; 599 600 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_DESCRIPTORS_RESULT: 601 if (connection->receive_states_index < (connection->receive_states_instances_num - 1)){ 602 connection->receive_states_index++; 603 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS; 604 break; 605 } 606 connection->receive_states_index = 0; 607 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION; 608 break; 609 610 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED: 611 if (connection->receive_states_index < (connection->receive_states_instances_num - 1)){ 612 connection->receive_states_index++; 613 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION; 614 break; 615 } 616 617 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 618 bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS); 619 break; 620 621 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT: 622 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 623 bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS); 624 break; 625 626 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_START_SCAN: 627 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 628 bass_client_emit_scan_operation_complete(connection, status, BASS_OPCODE_REMOTE_SCAN_STARTED); 629 break; 630 631 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_STOP_SCAN: 632 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 633 bass_client_emit_scan_operation_complete(connection, status, BASS_OPCODE_REMOTE_SCAN_STOPPED); 634 break; 635 636 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE: 637 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 638 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_ADD_SOURCE, BASS_INVALID_SOURCE_INDEX); 639 break; 640 641 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_MODIFY_SOURCE: 642 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 643 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_MODIFY_SOURCE, connection->control_point_operation_source_id); 644 break; 645 646 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_REMOVE_SOURCE: 647 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 648 bass_client_reset_source(bass_get_source_for_source_id(connection, connection->control_point_operation_source_id)); 649 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_REMOVE_SOURCE, connection->control_point_operation_source_id); 650 break; 651 652 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_SET_BROADCAST_CODE: 653 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 654 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_SET_BROADCAST_CODE, connection->control_point_operation_source_id); 655 break; 656 657 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED: 658 if (status != ATT_ERROR_SUCCESS){ 659 break; 660 } 661 662 break; 663 664 default: 665 break; 666 667 } 668 return true; 669 } 670 671 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 672 UNUSED(packet_type); 673 UNUSED(channel); 674 UNUSED(size); 675 676 bass_client_connection_t * connection = NULL; 677 gatt_client_service_t service; 678 gatt_client_characteristic_t characteristic; 679 gatt_client_characteristic_descriptor_t characteristic_descriptor; 680 681 bool call_run = true; 682 683 switch(hci_event_packet_get_type(packet)){ 684 case GATT_EVENT_MTU: 685 connection = bass_client_get_connection_for_con_handle(gatt_event_mtu_get_handle(packet)); 686 btstack_assert(connection != NULL); 687 connection->mtu = gatt_event_mtu_get_MTU(packet); 688 break; 689 690 case GATT_EVENT_SERVICE_QUERY_RESULT: 691 connection = bass_client_get_connection_for_con_handle(gatt_event_service_query_result_get_handle(packet)); 692 btstack_assert(connection != NULL); 693 694 if (connection->service_instances_num < 1){ 695 gatt_event_service_query_result_get_service(packet, &service); 696 connection->start_handle = service.start_group_handle; 697 connection->end_handle = service.end_group_handle; 698 699 #ifdef ENABLE_TESTING_SUPPORT 700 printf("BASS Service: start handle 0x%04X, end handle 0x%04X\n", connection->start_handle, connection->end_handle); 701 #endif 702 connection->service_instances_num++; 703 } else { 704 log_info("Found more then one BASS Service instance. "); 705 } 706 break; 707 708 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 709 connection = bass_client_get_connection_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet)); 710 btstack_assert(connection != NULL); 711 712 gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 713 714 switch (characteristic.uuid16){ 715 case ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_AUDIO_SCAN_CONTROL_POINT: 716 connection->control_point_value_handle = characteristic.value_handle; 717 break; 718 case ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE: 719 if (connection->receive_states_instances_num < connection->max_receive_states_num){ 720 connection->receive_states[connection->receive_states_instances_num].receive_state_value_handle = characteristic.value_handle; 721 connection->receive_states[connection->receive_states_instances_num].receive_state_properties = characteristic.properties; 722 connection->receive_states_instances_num++; 723 } else { 724 log_info("Found more BASS receive_states chrs then it can be stored. "); 725 } 726 break; 727 default: 728 btstack_assert(false); 729 return; 730 } 731 732 #ifdef ENABLE_TESTING_SUPPORT 733 printf("BASS Characteristic:\n Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X, %s\n", 734 characteristic.start_handle, 735 characteristic.properties, 736 characteristic.value_handle, characteristic.uuid16, 737 characteristic.uuid16 == ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE ? "RECEIVE_STATE" : "CONTROL_POINT"); 738 #endif 739 break; 740 741 742 case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT: 743 connection = bass_client_get_connection_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet)); 744 btstack_assert(connection != NULL); 745 gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor); 746 747 if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION){ 748 connection->receive_states[connection->receive_states_index].receive_state_ccc_handle = characteristic_descriptor.handle; 749 750 #ifdef ENABLE_TESTING_SUPPORT 751 printf(" BASS Characteristic Configuration Descriptor: Handle 0x%04X, UUID 0x%04X\n", 752 characteristic_descriptor.handle, 753 characteristic_descriptor.uuid16); 754 #endif 755 } 756 break; 757 758 759 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: 760 connection = bass_client_get_connection_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet)); 761 btstack_assert(connection != NULL); 762 763 if (connection->state == BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT){ 764 #ifdef ENABLE_TESTING_SUPPORT 765 printf(" Received CCC value: "); 766 printf_hexdump(gatt_event_characteristic_value_query_result_get_value(packet), gatt_event_characteristic_value_query_result_get_value_length(packet)); 767 #endif 768 break; 769 } 770 771 if (gatt_event_characteristic_value_query_result_get_value_length(packet) == 0 ){ 772 break; 773 } 774 775 // TODO 776 // bass_client_emit_receive_state(connection, 777 // gatt_event_characteristic_value_query_result_get_value_handle(packet), 778 // ATT_ERROR_SUCCESS, 779 // gatt_event_notification_get_value(packet), 780 // gatt_event_notification_get_value_length(packet)); 781 break; 782 783 case GATT_EVENT_QUERY_COMPLETE: 784 connection = bass_client_get_connection_for_con_handle(gatt_event_query_complete_get_handle(packet)); 785 btstack_assert(connection != NULL); 786 call_run = bass_client_handle_query_complete(connection, gatt_event_query_complete_get_att_status(packet)); 787 break; 788 789 default: 790 break; 791 } 792 793 if (call_run && (connection != NULL)){ 794 bass_client_run_for_connection(connection); 795 } 796 } 797 798 void broadcast_audio_scan_service_client_init(btstack_packet_handler_t packet_handler){ 799 btstack_assert(packet_handler != NULL); 800 bass_event_callback = packet_handler; 801 } 802 803 uint8_t broadcast_audio_scan_service_client_connect(bass_client_connection_t * connection, 804 bass_client_source_t * receive_states, uint8_t receive_states_num, 805 hci_con_handle_t con_handle, uint16_t * bass_cid){ 806 807 btstack_assert(receive_states != NULL); 808 btstack_assert(receive_states_num > 0); 809 810 if (bass_client_get_connection_for_con_handle(con_handle) != NULL){ 811 return ERROR_CODE_COMMAND_DISALLOWED; 812 } 813 814 uint16_t cid = bass_client_get_next_cid(); 815 if (bass_cid != NULL) { 816 *bass_cid = cid; 817 } 818 819 connection->cid = cid; 820 connection->con_handle = con_handle; 821 connection->mtu = ATT_DEFAULT_MTU; 822 823 connection->max_receive_states_num = receive_states_num; 824 connection->receive_states = receive_states; 825 826 uint8_t i; 827 for (i = 0; i < connection->max_receive_states_num; i++){ 828 connection->receive_states[i].in_use = false; 829 connection->receive_states[i].source_id = BASS_INVALID_SOURCE_INDEX; 830 } 831 832 connection->service_instances_num = 0; 833 connection->receive_states_instances_num = 0; 834 connection->receive_states_index = 0; 835 836 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE; 837 btstack_linked_list_add(&bass_connections, (btstack_linked_item_t *) connection); 838 839 bass_client_run_for_connection(connection); 840 return ERROR_CODE_SUCCESS; 841 } 842 843 uint8_t broadcast_audio_scan_service_client_scanning_started(uint16_t bass_cid){ 844 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 845 if (connection == NULL){ 846 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 847 } 848 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 849 return ERROR_CODE_COMMAND_DISALLOWED; 850 } 851 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_START_SCAN; 852 bass_client_run_for_connection(connection); 853 return ERROR_CODE_SUCCESS; 854 } 855 856 uint8_t broadcast_audio_scan_service_client_scanning_stopped(uint16_t bass_cid){ 857 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 858 if (connection == NULL){ 859 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 860 } 861 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 862 return ERROR_CODE_COMMAND_DISALLOWED; 863 } 864 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_STOP_SCAN; 865 bass_client_run_for_connection(connection); 866 return ERROR_CODE_SUCCESS; 867 } 868 869 uint8_t broadcast_audio_scan_service_client_add_source(uint16_t bass_cid, const bass_source_data_t * add_source_data){ 870 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 871 if (connection == NULL){ 872 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 873 } 874 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 875 return ERROR_CODE_COMMAND_DISALLOWED; 876 } 877 878 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_ADD_SOURCE; 879 connection->control_point_operation_data = add_source_data; 880 connection->buffer_offset = 0; 881 connection->data_size = bass_client_receive_state_len(add_source_data); 882 883 bass_client_run_for_connection(connection); 884 return ERROR_CODE_SUCCESS; 885 } 886 887 uint8_t broadcast_audio_scan_service_client_modify_source(uint16_t bass_cid, uint8_t source_id, const bass_source_data_t * modify_source_data){ 888 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 889 if (connection == NULL){ 890 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 891 } 892 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 893 return ERROR_CODE_COMMAND_DISALLOWED; 894 } 895 896 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_MODIFY_SOURCE; 897 connection->control_point_operation_data = modify_source_data; 898 connection->control_point_operation_source_id = source_id; 899 connection->buffer_offset = 0; 900 connection->data_size = bass_client_receive_state_len(modify_source_data); 901 902 bass_client_run_for_connection(connection); 903 return ERROR_CODE_SUCCESS; 904 } 905 906 uint8_t broadcast_audio_scan_service_client_remove_source(uint16_t bass_cid, uint8_t source_id){ 907 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 908 if (connection == NULL){ 909 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 910 } 911 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 912 return ERROR_CODE_COMMAND_DISALLOWED; 913 } 914 915 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_REMOVE_SOURCE; 916 connection->control_point_operation_source_id = source_id; 917 918 bass_client_run_for_connection(connection); 919 return ERROR_CODE_SUCCESS; 920 } 921 922 uint8_t broadcast_audio_scan_service_client_set_broadcast_code(uint16_t bass_cid, uint8_t source_id, const uint8_t * broadcast_code){ 923 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 924 if (connection == NULL){ 925 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 926 } 927 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 928 return ERROR_CODE_COMMAND_DISALLOWED; 929 } 930 931 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_SET_BROADCAST_CODE; 932 connection->control_point_operation_source_id = source_id; 933 connection->broadcast_code = broadcast_code; 934 935 bass_client_run_for_connection(connection); 936 return ERROR_CODE_SUCCESS; 937 } 938 939 const bass_source_data_t * broadcast_audio_scan_service_client_get_source_data(uint16_t bass_cid, uint8_t source_id){ 940 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 941 if (connection == NULL){ 942 return NULL; 943 } 944 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 945 return NULL; 946 } 947 return (const bass_source_data_t *) &bass_get_source_for_source_id(connection, source_id)->data; 948 } 949 950 uint8_t broadcast_audio_scan_service_client_get_encryption_state(uint16_t bass_cid, uint8_t source_id, 951 le_audio_big_encryption_t * out_big_encryption, uint8_t * out_bad_code){ 952 btstack_assert(out_big_encryption != NULL); 953 btstack_assert(out_bad_code != NULL); 954 955 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 956 if (connection == NULL){ 957 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 958 } 959 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 960 return ERROR_CODE_COMMAND_DISALLOWED; 961 } 962 bass_client_source_t * source = bass_get_source_for_source_id(connection, source_id); 963 if (source == NULL){ 964 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 965 } 966 *out_big_encryption = source->big_encryption; 967 memcpy(out_bad_code, source->bad_code, 16); 968 return ERROR_CODE_SUCCESS; 969 } 970 971 void broadcast_audio_scan_service_client_deinit(uint16_t bass_cid){ 972 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 973 if (connection == NULL){ 974 return; 975 } 976 // finalize connections 977 bass_client_finalize_connection(connection); 978 } 979 980