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_get_source_from_buffer(&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_copy_source_common_data_to_buffer(receive_state, &source_offset, buffer_offset, buffer, buffer_size); 332 333 field_data[0] = (uint8_t)receive_state->pa_sync; 334 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 335 buffer_offset); 336 source_offset++; 337 338 little_endian_store_16(field_data, 0, receive_state->pa_interval); 339 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, source_offset, buffer, buffer_size, 340 buffer_offset); 341 source_offset += 2; 342 343 stored_bytes += bass_util_store_source_subgroups_into_buffer(receive_state, false, &source_offset, buffer_offset, 344 buffer, 345 buffer_size); 346 347 return stored_bytes; 348 } 349 350 static uint16_t bass_client_prepare_modify_source_buffer(bass_client_connection_t * connection){ 351 const bass_source_data_t * receive_state = connection->control_point_operation_data; 352 353 uint16_t buffer_offset = connection->buffer_offset; 354 uint8_t * buffer = connection->buffer; 355 uint16_t buffer_size = btstack_min(sizeof(connection->buffer), connection->mtu); 356 357 btstack_assert(buffer_offset == 0); 358 359 uint8_t field_data[6]; 360 uint16_t source_offset = 0; 361 uint16_t stored_bytes = 0; 362 memset(buffer, 0, buffer_size); 363 364 field_data[0] = (uint8_t)BASS_OPCODE_MODIFY_SOURCE; 365 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 366 buffer_offset); 367 source_offset++; 368 369 field_data[0] = connection->control_point_operation_source_id; 370 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 371 buffer_offset); 372 source_offset++; 373 374 field_data[0] = (uint8_t)receive_state->pa_sync; 375 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 376 buffer_offset); 377 source_offset++; 378 379 little_endian_store_16(field_data, 0, receive_state->pa_interval); 380 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, source_offset, buffer, buffer_size, 381 buffer_offset); 382 source_offset += 2; 383 384 stored_bytes += bass_util_store_source_subgroups_into_buffer(receive_state, false, &source_offset, buffer_offset, 385 buffer, 386 buffer_size); 387 return stored_bytes; 388 } 389 390 static uint16_t bass_client_receive_state_len(const bass_source_data_t * source_data){ 391 uint16_t source_len = 0; 392 // opcode(1), address_type(1), address(6), adv_sid(1), broadcast_id(3), pa_sync(1), subgroups_num(1) 393 source_len = 1 + 1 + 6 + 1 + 3 + 1 + 1; 394 395 uint8_t i; 396 for (i = 0; i < source_data->subgroups_num; i++){ 397 bass_subgroup_t subgroup = source_data->subgroups[i]; 398 // bis_sync(4), metadata_length(1), metadata_length 399 source_len += 4 + 1 + subgroup.metadata_length; 400 } 401 return source_len; 402 } 403 404 static void bass_client_run_for_connection(bass_client_connection_t * connection){ 405 uint8_t status; 406 gatt_client_characteristic_t characteristic; 407 gatt_client_service_t service; 408 409 uint8_t value[18]; 410 uint16_t stored_bytes; 411 412 switch (connection->state){ 413 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED: 414 break; 415 416 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_START_SCAN: 417 #ifdef ENABLE_TESTING_SUPPORT 418 printf(" Write START SCAN [0x%04X]:\n", 419 connection->control_point_value_handle); 420 #endif 421 422 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_START_SCAN; 423 value[0] = BASS_OPCODE_REMOTE_SCAN_STARTED; 424 // see GATT_EVENT_QUERY_COMPLETE for end of write 425 status = gatt_client_write_value_of_characteristic( 426 &handle_gatt_client_event, connection->con_handle, 427 connection->control_point_value_handle, 1, &value[0]); 428 UNUSED(status); 429 break; 430 431 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_STOP_SCAN: 432 #ifdef ENABLE_TESTING_SUPPORT 433 printf(" Write START SCAN [0x%04X]:\n", 434 connection->control_point_value_handle); 435 #endif 436 437 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_STOP_SCAN; 438 value[0] = BASS_OPCODE_REMOTE_SCAN_STOPPED; 439 // see GATT_EVENT_QUERY_COMPLETE for end of write 440 status = gatt_client_write_value_of_characteristic( 441 &handle_gatt_client_event, connection->con_handle, 442 connection->control_point_value_handle, 1, &value[0]); 443 UNUSED(status); 444 break; 445 446 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_ADD_SOURCE: 447 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE; 448 #ifdef ENABLE_TESTING_SUPPORT 449 printf(" ADD SOURCE [0x%04X]:\n", connection->control_point_value_handle); 450 #endif 451 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE; 452 stored_bytes = bass_client_prepare_add_source_buffer(connection); 453 connection->buffer_offset += stored_bytes; 454 455 gatt_client_write_long_value_of_characteristic(&handle_gatt_client_event, connection->con_handle, 456 connection->control_point_value_handle, stored_bytes, connection->buffer); 457 break; 458 459 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_MODIFY_SOURCE: 460 #ifdef ENABLE_TESTING_SUPPORT 461 printf(" MODIFY SOURCE [%d]:\n", connection->control_point_operation_source_id); 462 #endif 463 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_MODIFY_SOURCE; 464 stored_bytes = bass_client_prepare_modify_source_buffer(connection); 465 connection->buffer_offset += stored_bytes; 466 467 gatt_client_write_long_value_of_characteristic(&handle_gatt_client_event, connection->con_handle, 468 connection->control_point_value_handle, stored_bytes, connection->buffer); 469 470 break; 471 472 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_REMOVE_SOURCE: 473 #ifdef ENABLE_TESTING_SUPPORT 474 printf(" REMOVE SOURCE [%d]:\n", connection->control_point_operation_source_id); 475 #endif 476 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_REMOVE_SOURCE; 477 value[0] = BASS_OPCODE_REMOVE_SOURCE; 478 value[1] = connection->control_point_operation_source_id; 479 // see GATT_EVENT_QUERY_COMPLETE for end of write 480 status = gatt_client_write_value_of_characteristic( 481 &handle_gatt_client_event, connection->con_handle, 482 connection->control_point_value_handle, 2, &value[0]); 483 UNUSED(status); 484 break; 485 486 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_SET_BROADCAST_CODE: 487 #ifdef ENABLE_TESTING_SUPPORT 488 printf(" SET BROADCAST CODE [%d]:\n", connection->control_point_operation_source_id); 489 #endif 490 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_SET_BROADCAST_CODE; 491 value[0] = BASS_OPCODE_SET_BROADCAST_CODE; 492 value[1] = connection->control_point_operation_source_id; 493 reverse_128(connection->broadcast_code, &value[2]); 494 495 // see GATT_EVENT_QUERY_COMPLETE for end of write 496 status = gatt_client_write_value_of_characteristic( 497 &handle_gatt_client_event, connection->con_handle, 498 connection->control_point_value_handle, 18, &value[0]); 499 UNUSED(status); 500 break; 501 502 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE: 503 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT; 504 gatt_client_discover_primary_services_by_uuid16(&handle_gatt_client_event, connection->con_handle, ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE); 505 break; 506 507 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS: 508 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT; 509 510 service.start_group_handle = connection->start_handle; 511 service.end_group_handle = connection->end_handle; 512 service.uuid16 = ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE; 513 514 gatt_client_discover_characteristics_for_service( 515 &handle_gatt_client_event, 516 connection->con_handle, 517 &service); 518 519 break; 520 521 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS: 522 #ifdef ENABLE_TESTING_SUPPORT 523 printf("Read client characteristic descriptors [index %d]:\n", connection->receive_states_index); 524 #endif 525 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_DESCRIPTORS_RESULT; 526 characteristic.value_handle = connection->receive_states[connection->receive_states_index].receive_state_value_handle; 527 characteristic.properties = connection->receive_states[connection->receive_states_index].receive_state_properties; 528 characteristic.end_handle = connection->end_handle; 529 530 (void) gatt_client_discover_characteristic_descriptors(&handle_gatt_client_event, connection->con_handle, &characteristic); 531 break; 532 533 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION: 534 #ifdef ENABLE_TESTING_SUPPORT 535 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); 536 #endif 537 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT; 538 539 // result in GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT 540 (void) gatt_client_read_characteristic_descriptor_using_descriptor_handle( 541 &handle_gatt_client_event, 542 connection->con_handle, 543 connection->receive_states[connection->receive_states_index].receive_state_ccc_handle); 544 break; 545 546 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION: 547 #ifdef ENABLE_TESTING_SUPPORT 548 printf("Register notification [index %d, handle 0x%04X]:\n", connection->receive_states_index, connection->receive_states[connection->receive_states_index].receive_state_ccc_handle); 549 #endif 550 551 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED; 552 553 status = bass_client_register_notification(connection); 554 if (status == ERROR_CODE_SUCCESS) return; 555 556 if (connection->receive_states[connection->receive_states_index].receive_state_ccc_handle != 0){ 557 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION; 558 break; 559 } 560 561 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 562 bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS); 563 break; 564 default: 565 break; 566 } 567 } 568 // @return true if client valid / run function should be called 569 static bool bass_client_handle_query_complete(bass_client_connection_t * connection, uint8_t status){ 570 switch (connection->state){ 571 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT: 572 if (status != ATT_ERROR_SUCCESS){ 573 bass_client_emit_connection_established(connection, status); 574 bass_client_finalize_connection(connection); 575 return false; 576 } 577 578 if (connection->service_instances_num == 0){ 579 bass_client_emit_connection_established(connection, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 580 bass_client_finalize_connection(connection); 581 return false; 582 } 583 connection->receive_states_index = 0; 584 connection->receive_states_instances_num = 0; 585 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS; 586 break; 587 588 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT: 589 if (status != ATT_ERROR_SUCCESS){ 590 bass_client_emit_connection_established(connection, status); 591 bass_client_finalize_connection(connection); 592 return false; 593 } 594 595 connection->receive_states_index = 0; 596 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS; 597 break; 598 599 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_DESCRIPTORS_RESULT: 600 if (connection->receive_states_index < (connection->receive_states_instances_num - 1)){ 601 connection->receive_states_index++; 602 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS; 603 break; 604 } 605 connection->receive_states_index = 0; 606 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION; 607 break; 608 609 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED: 610 if (connection->receive_states_index < (connection->receive_states_instances_num - 1)){ 611 connection->receive_states_index++; 612 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION; 613 break; 614 } 615 616 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 617 bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS); 618 break; 619 620 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT: 621 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 622 bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS); 623 break; 624 625 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_START_SCAN: 626 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 627 bass_client_emit_scan_operation_complete(connection, status, BASS_OPCODE_REMOTE_SCAN_STARTED); 628 break; 629 630 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_STOP_SCAN: 631 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 632 bass_client_emit_scan_operation_complete(connection, status, BASS_OPCODE_REMOTE_SCAN_STOPPED); 633 break; 634 635 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE: 636 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 637 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_ADD_SOURCE, BASS_INVALID_SOURCE_INDEX); 638 break; 639 640 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_MODIFY_SOURCE: 641 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 642 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_MODIFY_SOURCE, connection->control_point_operation_source_id); 643 break; 644 645 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_REMOVE_SOURCE: 646 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 647 bass_client_reset_source(bass_get_source_for_source_id(connection, connection->control_point_operation_source_id)); 648 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_REMOVE_SOURCE, connection->control_point_operation_source_id); 649 break; 650 651 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_SET_BROADCAST_CODE: 652 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 653 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_SET_BROADCAST_CODE, connection->control_point_operation_source_id); 654 break; 655 656 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED: 657 if (status != ATT_ERROR_SUCCESS){ 658 break; 659 } 660 661 break; 662 663 default: 664 break; 665 666 } 667 return true; 668 } 669 670 static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 671 UNUSED(packet_type); 672 UNUSED(channel); 673 UNUSED(size); 674 675 bass_client_connection_t * connection = NULL; 676 gatt_client_service_t service; 677 gatt_client_characteristic_t characteristic; 678 gatt_client_characteristic_descriptor_t characteristic_descriptor; 679 680 bool call_run = true; 681 682 switch(hci_event_packet_get_type(packet)){ 683 case GATT_EVENT_MTU: 684 connection = bass_client_get_connection_for_con_handle(gatt_event_mtu_get_handle(packet)); 685 btstack_assert(connection != NULL); 686 connection->mtu = gatt_event_mtu_get_MTU(packet); 687 break; 688 689 case GATT_EVENT_SERVICE_QUERY_RESULT: 690 connection = bass_client_get_connection_for_con_handle(gatt_event_service_query_result_get_handle(packet)); 691 btstack_assert(connection != NULL); 692 693 if (connection->service_instances_num < 1){ 694 gatt_event_service_query_result_get_service(packet, &service); 695 connection->start_handle = service.start_group_handle; 696 connection->end_handle = service.end_group_handle; 697 698 #ifdef ENABLE_TESTING_SUPPORT 699 printf("BASS Service: start handle 0x%04X, end handle 0x%04X\n", connection->start_handle, connection->end_handle); 700 #endif 701 connection->service_instances_num++; 702 } else { 703 log_info("Found more then one BASS Service instance. "); 704 } 705 break; 706 707 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 708 connection = bass_client_get_connection_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet)); 709 btstack_assert(connection != NULL); 710 711 gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 712 713 switch (characteristic.uuid16){ 714 case ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_AUDIO_SCAN_CONTROL_POINT: 715 connection->control_point_value_handle = characteristic.value_handle; 716 break; 717 case ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE: 718 if (connection->receive_states_instances_num < connection->max_receive_states_num){ 719 connection->receive_states[connection->receive_states_instances_num].receive_state_value_handle = characteristic.value_handle; 720 connection->receive_states[connection->receive_states_instances_num].receive_state_properties = characteristic.properties; 721 connection->receive_states_instances_num++; 722 } else { 723 log_info("Found more BASS receive_states chrs then it can be stored. "); 724 } 725 break; 726 default: 727 btstack_assert(false); 728 return; 729 } 730 731 #ifdef ENABLE_TESTING_SUPPORT 732 printf("BASS Characteristic:\n Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X, %s\n", 733 characteristic.start_handle, 734 characteristic.properties, 735 characteristic.value_handle, characteristic.uuid16, 736 characteristic.uuid16 == ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE ? "RECEIVE_STATE" : "CONTROL_POINT"); 737 #endif 738 break; 739 740 741 case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT: 742 connection = bass_client_get_connection_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet)); 743 btstack_assert(connection != NULL); 744 gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor); 745 746 if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION){ 747 connection->receive_states[connection->receive_states_index].receive_state_ccc_handle = characteristic_descriptor.handle; 748 749 #ifdef ENABLE_TESTING_SUPPORT 750 printf(" BASS Characteristic Configuration Descriptor: Handle 0x%04X, UUID 0x%04X\n", 751 characteristic_descriptor.handle, 752 characteristic_descriptor.uuid16); 753 #endif 754 } 755 break; 756 757 758 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: 759 connection = bass_client_get_connection_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet)); 760 btstack_assert(connection != NULL); 761 762 if (connection->state == BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT){ 763 #ifdef ENABLE_TESTING_SUPPORT 764 printf(" Received CCC value: "); 765 printf_hexdump(gatt_event_characteristic_value_query_result_get_value(packet), gatt_event_characteristic_value_query_result_get_value_length(packet)); 766 #endif 767 break; 768 } 769 770 if (gatt_event_characteristic_value_query_result_get_value_length(packet) == 0 ){ 771 break; 772 } 773 774 // TODO 775 // bass_client_emit_receive_state(connection, 776 // gatt_event_characteristic_value_query_result_get_value_handle(packet), 777 // ATT_ERROR_SUCCESS, 778 // gatt_event_notification_get_value(packet), 779 // gatt_event_notification_get_value_length(packet)); 780 break; 781 782 case GATT_EVENT_QUERY_COMPLETE: 783 connection = bass_client_get_connection_for_con_handle(gatt_event_query_complete_get_handle(packet)); 784 btstack_assert(connection != NULL); 785 call_run = bass_client_handle_query_complete(connection, gatt_event_query_complete_get_att_status(packet)); 786 break; 787 788 default: 789 break; 790 } 791 792 if (call_run && (connection != NULL)){ 793 bass_client_run_for_connection(connection); 794 } 795 } 796 797 void broadcast_audio_scan_service_client_init(btstack_packet_handler_t packet_handler){ 798 btstack_assert(packet_handler != NULL); 799 bass_event_callback = packet_handler; 800 } 801 802 uint8_t broadcast_audio_scan_service_client_connect(bass_client_connection_t * connection, 803 bass_client_source_t * receive_states, uint8_t receive_states_num, 804 hci_con_handle_t con_handle, uint16_t * bass_cid){ 805 806 btstack_assert(receive_states != NULL); 807 btstack_assert(receive_states_num > 0); 808 809 if (bass_client_get_connection_for_con_handle(con_handle) != NULL){ 810 return ERROR_CODE_COMMAND_DISALLOWED; 811 } 812 813 uint16_t cid = bass_client_get_next_cid(); 814 if (bass_cid != NULL) { 815 *bass_cid = cid; 816 } 817 818 connection->cid = cid; 819 connection->con_handle = con_handle; 820 connection->mtu = ATT_DEFAULT_MTU; 821 822 connection->max_receive_states_num = receive_states_num; 823 connection->receive_states = receive_states; 824 825 uint8_t i; 826 for (i = 0; i < connection->max_receive_states_num; i++){ 827 connection->receive_states[i].in_use = false; 828 connection->receive_states[i].source_id = BASS_INVALID_SOURCE_INDEX; 829 } 830 831 connection->service_instances_num = 0; 832 connection->receive_states_instances_num = 0; 833 connection->receive_states_index = 0; 834 835 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE; 836 btstack_linked_list_add(&bass_connections, (btstack_linked_item_t *) connection); 837 838 bass_client_run_for_connection(connection); 839 return ERROR_CODE_SUCCESS; 840 } 841 842 uint8_t broadcast_audio_scan_service_client_scanning_started(uint16_t bass_cid){ 843 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 844 if (connection == NULL){ 845 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 846 } 847 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 848 return ERROR_CODE_COMMAND_DISALLOWED; 849 } 850 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_START_SCAN; 851 bass_client_run_for_connection(connection); 852 return ERROR_CODE_SUCCESS; 853 } 854 855 uint8_t broadcast_audio_scan_service_client_scanning_stopped(uint16_t bass_cid){ 856 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 857 if (connection == NULL){ 858 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 859 } 860 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 861 return ERROR_CODE_COMMAND_DISALLOWED; 862 } 863 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_STOP_SCAN; 864 bass_client_run_for_connection(connection); 865 return ERROR_CODE_SUCCESS; 866 } 867 868 uint8_t broadcast_audio_scan_service_client_add_source(uint16_t bass_cid, const bass_source_data_t * add_source_data){ 869 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 870 if (connection == NULL){ 871 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 872 } 873 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 874 return ERROR_CODE_COMMAND_DISALLOWED; 875 } 876 877 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_ADD_SOURCE; 878 connection->control_point_operation_data = add_source_data; 879 connection->buffer_offset = 0; 880 connection->data_size = bass_client_receive_state_len(add_source_data); 881 882 bass_client_run_for_connection(connection); 883 return ERROR_CODE_SUCCESS; 884 } 885 886 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){ 887 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 888 if (connection == NULL){ 889 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 890 } 891 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 892 return ERROR_CODE_COMMAND_DISALLOWED; 893 } 894 895 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_MODIFY_SOURCE; 896 connection->control_point_operation_data = modify_source_data; 897 connection->control_point_operation_source_id = source_id; 898 connection->buffer_offset = 0; 899 connection->data_size = bass_client_receive_state_len(modify_source_data); 900 901 bass_client_run_for_connection(connection); 902 return ERROR_CODE_SUCCESS; 903 } 904 905 uint8_t broadcast_audio_scan_service_client_remove_source(uint16_t bass_cid, uint8_t source_id){ 906 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 907 if (connection == NULL){ 908 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 909 } 910 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 911 return ERROR_CODE_COMMAND_DISALLOWED; 912 } 913 914 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_REMOVE_SOURCE; 915 connection->control_point_operation_source_id = source_id; 916 917 bass_client_run_for_connection(connection); 918 return ERROR_CODE_SUCCESS; 919 } 920 921 uint8_t broadcast_audio_scan_service_client_set_broadcast_code(uint16_t bass_cid, uint8_t source_id, const uint8_t * broadcast_code){ 922 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 923 if (connection == NULL){ 924 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 925 } 926 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 927 return ERROR_CODE_COMMAND_DISALLOWED; 928 } 929 930 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_SET_BROADCAST_CODE; 931 connection->control_point_operation_source_id = source_id; 932 connection->broadcast_code = broadcast_code; 933 934 bass_client_run_for_connection(connection); 935 return ERROR_CODE_SUCCESS; 936 } 937 938 const bass_source_data_t * broadcast_audio_scan_service_client_get_source_data(uint16_t bass_cid, uint8_t source_id){ 939 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 940 if (connection == NULL){ 941 return NULL; 942 } 943 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 944 return NULL; 945 } 946 return (const bass_source_data_t *) &bass_get_source_for_source_id(connection, source_id)->data; 947 } 948 949 uint8_t broadcast_audio_scan_service_client_get_encryption_state(uint16_t bass_cid, uint8_t source_id, 950 le_audio_big_encryption_t * out_big_encryption, uint8_t * out_bad_code){ 951 btstack_assert(out_big_encryption != NULL); 952 btstack_assert(out_bad_code != NULL); 953 954 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 955 if (connection == NULL){ 956 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 957 } 958 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 959 return ERROR_CODE_COMMAND_DISALLOWED; 960 } 961 bass_client_source_t * source = bass_get_source_for_source_id(connection, source_id); 962 if (source == NULL){ 963 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 964 } 965 *out_big_encryption = source->big_encryption; 966 memcpy(out_bad_code, source->bad_code, 16); 967 return ERROR_CODE_SUCCESS; 968 } 969 970 void broadcast_audio_scan_service_client_deinit(uint16_t bass_cid){ 971 bass_client_connection_t * connection = bass_get_client_for_cid(bass_cid); 972 if (connection == NULL){ 973 return; 974 } 975 // finalize connections 976 bass_client_finalize_connection(connection); 977 } 978 979