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