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