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_client_connections; 57 58 static uint16_t bass_client_cid_counter = 0; 59 static btstack_packet_handler_t bass_client_event_callback; 60 61 static void bass_client_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_client_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_client_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_client_get_connection_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_client_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_client_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_client_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_client_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_CLIENT_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_client_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_client_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_CLIENT_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_client_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_client_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_CLIENT_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_client_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_client_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_CLIENT_NOTIFICATION_COMPLETE; 175 little_endian_store_16(event, pos, connection->cid); 176 pos += 2; 177 event[pos++] = source_id; 178 (*bass_client_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 bass_client_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_client_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 &bass_client_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 &bass_client_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 &bass_client_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 &bass_client_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(&bass_client_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(&bass_client_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 &bass_client_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 &bass_client_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(&bass_client_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 &bass_client_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(&bass_client_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 &bass_client_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( 654 bass_client_get_source_for_source_id(connection, connection->control_point_operation_source_id)); 655 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_REMOVE_SOURCE, connection->control_point_operation_source_id); 656 break; 657 658 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_SET_BROADCAST_CODE: 659 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 660 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_SET_BROADCAST_CODE, connection->control_point_operation_source_id); 661 break; 662 663 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED: 664 if (status != ATT_ERROR_SUCCESS){ 665 break; 666 } 667 668 break; 669 670 default: 671 break; 672 673 } 674 return true; 675 } 676 677 static void bass_client_handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 678 UNUSED(packet_type); 679 UNUSED(channel); 680 UNUSED(size); 681 682 bass_client_connection_t * connection = NULL; 683 gatt_client_service_t service; 684 gatt_client_characteristic_t characteristic; 685 gatt_client_characteristic_descriptor_t characteristic_descriptor; 686 687 bool call_run = true; 688 689 switch(hci_event_packet_get_type(packet)){ 690 case GATT_EVENT_MTU: 691 connection = bass_client_get_connection_for_con_handle(gatt_event_mtu_get_handle(packet)); 692 btstack_assert(connection != NULL); 693 connection->mtu = gatt_event_mtu_get_MTU(packet); 694 break; 695 696 case GATT_EVENT_SERVICE_QUERY_RESULT: 697 connection = bass_client_get_connection_for_con_handle(gatt_event_service_query_result_get_handle(packet)); 698 btstack_assert(connection != NULL); 699 700 if (connection->service_instances_num < 1){ 701 gatt_event_service_query_result_get_service(packet, &service); 702 connection->start_handle = service.start_group_handle; 703 connection->end_handle = service.end_group_handle; 704 705 #ifdef ENABLE_TESTING_SUPPORT 706 printf("BASS Service: start handle 0x%04X, end handle 0x%04X\n", connection->start_handle, connection->end_handle); 707 #endif 708 connection->service_instances_num++; 709 } else { 710 log_info("Found more then one BASS Service instance. "); 711 } 712 break; 713 714 case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 715 connection = bass_client_get_connection_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet)); 716 btstack_assert(connection != NULL); 717 718 gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 719 720 switch (characteristic.uuid16){ 721 case ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_AUDIO_SCAN_CONTROL_POINT: 722 connection->control_point_value_handle = characteristic.value_handle; 723 break; 724 case ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE: 725 if (connection->receive_states_instances_num < connection->max_receive_states_num){ 726 connection->receive_states[connection->receive_states_instances_num].receive_state_value_handle = characteristic.value_handle; 727 connection->receive_states[connection->receive_states_instances_num].receive_state_properties = characteristic.properties; 728 connection->receive_states[connection->receive_states_index].receive_state_end_handle = characteristic.end_handle; 729 connection->receive_states_instances_num++; 730 } else { 731 log_info("Found more BASS receive_states chrs then it can be stored. "); 732 } 733 break; 734 default: 735 btstack_assert(false); 736 return; 737 } 738 739 #ifdef ENABLE_TESTING_SUPPORT 740 printf("BASS Characteristic:\n Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X, %s\n", 741 characteristic.start_handle, 742 characteristic.properties, 743 characteristic.value_handle, characteristic.uuid16, 744 characteristic.uuid16 == ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE ? "RECEIVE_STATE" : "CONTROL_POINT"); 745 #endif 746 break; 747 748 749 case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT: 750 connection = bass_client_get_connection_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet)); 751 btstack_assert(connection != NULL); 752 gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor); 753 754 if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION){ 755 connection->receive_states[connection->receive_states_index].receive_state_ccc_handle = characteristic_descriptor.handle; 756 757 #ifdef ENABLE_TESTING_SUPPORT 758 printf(" BASS Characteristic Configuration Descriptor: Handle 0x%04X, UUID 0x%04X\n", 759 characteristic_descriptor.handle, 760 characteristic_descriptor.uuid16); 761 #endif 762 } 763 break; 764 765 766 case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: 767 connection = bass_client_get_connection_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet)); 768 btstack_assert(connection != NULL); 769 770 if (connection->state == BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT){ 771 #ifdef ENABLE_TESTING_SUPPORT 772 printf(" Received CCC value: "); 773 printf_hexdump(gatt_event_characteristic_value_query_result_get_value(packet), gatt_event_characteristic_value_query_result_get_value_length(packet)); 774 #endif 775 break; 776 } 777 778 if (gatt_event_characteristic_value_query_result_get_value_length(packet) == 0 ){ 779 break; 780 } 781 782 // TODO 783 // bass_client_emit_receive_state(connection, 784 // gatt_event_characteristic_value_query_result_get_value_handle(packet), 785 // ATT_ERROR_SUCCESS, 786 // gatt_event_notification_get_value(packet), 787 // gatt_event_notification_get_value_length(packet)); 788 break; 789 790 case GATT_EVENT_QUERY_COMPLETE: 791 connection = bass_client_get_connection_for_con_handle(gatt_event_query_complete_get_handle(packet)); 792 btstack_assert(connection != NULL); 793 call_run = bass_client_handle_query_complete(connection, gatt_event_query_complete_get_att_status(packet)); 794 break; 795 796 default: 797 break; 798 } 799 800 if (call_run && (connection != NULL)){ 801 bass_client_run_for_connection(connection); 802 } 803 } 804 805 void broadcast_audio_scan_service_client_init(btstack_packet_handler_t packet_handler){ 806 btstack_assert(packet_handler != NULL); 807 bass_client_event_callback = packet_handler; 808 } 809 810 uint8_t broadcast_audio_scan_service_client_connect(bass_client_connection_t * connection, 811 bass_client_source_t * receive_states, uint8_t receive_states_num, 812 hci_con_handle_t con_handle, uint16_t * bass_cid){ 813 814 btstack_assert(receive_states != NULL); 815 btstack_assert(receive_states_num > 0); 816 817 if (bass_client_get_connection_for_con_handle(con_handle) != NULL){ 818 return ERROR_CODE_COMMAND_DISALLOWED; 819 } 820 821 uint16_t cid = bass_client_get_next_cid(); 822 if (bass_cid != NULL) { 823 *bass_cid = cid; 824 } 825 826 connection->cid = cid; 827 connection->con_handle = con_handle; 828 connection->mtu = ATT_DEFAULT_MTU; 829 830 connection->max_receive_states_num = receive_states_num; 831 connection->receive_states = receive_states; 832 833 uint8_t i; 834 for (i = 0; i < connection->max_receive_states_num; i++){ 835 connection->receive_states[i].in_use = false; 836 connection->receive_states[i].source_id = BASS_INVALID_SOURCE_INDEX; 837 } 838 839 connection->service_instances_num = 0; 840 connection->receive_states_instances_num = 0; 841 connection->receive_states_index = 0; 842 843 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE; 844 btstack_linked_list_add(&bass_client_connections, (btstack_linked_item_t *) connection); 845 846 bass_client_run_for_connection(connection); 847 return ERROR_CODE_SUCCESS; 848 } 849 850 uint8_t broadcast_audio_scan_service_client_scanning_started(uint16_t bass_cid){ 851 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 852 if (connection == NULL){ 853 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 854 } 855 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 856 return ERROR_CODE_COMMAND_DISALLOWED; 857 } 858 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_START_SCAN; 859 bass_client_run_for_connection(connection); 860 return ERROR_CODE_SUCCESS; 861 } 862 863 uint8_t broadcast_audio_scan_service_client_scanning_stopped(uint16_t bass_cid){ 864 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 865 if (connection == NULL){ 866 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 867 } 868 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 869 return ERROR_CODE_COMMAND_DISALLOWED; 870 } 871 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_STOP_SCAN; 872 bass_client_run_for_connection(connection); 873 return ERROR_CODE_SUCCESS; 874 } 875 876 uint8_t broadcast_audio_scan_service_client_add_source(uint16_t bass_cid, const bass_source_data_t * add_source_data){ 877 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 878 if (connection == NULL){ 879 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 880 } 881 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 882 return ERROR_CODE_COMMAND_DISALLOWED; 883 } 884 885 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_ADD_SOURCE; 886 connection->control_point_operation_data = add_source_data; 887 connection->buffer_offset = 0; 888 connection->data_size = bass_client_receive_state_len(add_source_data); 889 890 bass_client_run_for_connection(connection); 891 return ERROR_CODE_SUCCESS; 892 } 893 894 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){ 895 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 896 if (connection == NULL){ 897 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 898 } 899 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 900 return ERROR_CODE_COMMAND_DISALLOWED; 901 } 902 903 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_MODIFY_SOURCE; 904 connection->control_point_operation_data = modify_source_data; 905 connection->control_point_operation_source_id = source_id; 906 connection->buffer_offset = 0; 907 connection->data_size = bass_client_receive_state_len(modify_source_data); 908 909 bass_client_run_for_connection(connection); 910 return ERROR_CODE_SUCCESS; 911 } 912 913 uint8_t broadcast_audio_scan_service_client_remove_source(uint16_t bass_cid, uint8_t source_id){ 914 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 915 if (connection == NULL){ 916 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 917 } 918 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 919 return ERROR_CODE_COMMAND_DISALLOWED; 920 } 921 922 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_REMOVE_SOURCE; 923 connection->control_point_operation_source_id = source_id; 924 925 bass_client_run_for_connection(connection); 926 return ERROR_CODE_SUCCESS; 927 } 928 929 uint8_t broadcast_audio_scan_service_client_set_broadcast_code(uint16_t bass_cid, uint8_t source_id, const uint8_t * broadcast_code){ 930 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 931 if (connection == NULL){ 932 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 933 } 934 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 935 return ERROR_CODE_COMMAND_DISALLOWED; 936 } 937 938 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_SET_BROADCAST_CODE; 939 connection->control_point_operation_source_id = source_id; 940 connection->broadcast_code = broadcast_code; 941 942 bass_client_run_for_connection(connection); 943 return ERROR_CODE_SUCCESS; 944 } 945 946 const bass_source_data_t * broadcast_audio_scan_service_client_get_source_data(uint16_t bass_cid, uint8_t source_id){ 947 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 948 if (connection == NULL){ 949 return NULL; 950 } 951 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 952 return NULL; 953 } 954 return (const bass_source_data_t *) &bass_client_get_source_for_source_id(connection, source_id)->data; 955 } 956 957 uint8_t broadcast_audio_scan_service_client_get_encryption_state(uint16_t bass_cid, uint8_t source_id, 958 le_audio_big_encryption_t * out_big_encryption, uint8_t * out_bad_code){ 959 btstack_assert(out_big_encryption != NULL); 960 btstack_assert(out_bad_code != NULL); 961 962 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 963 if (connection == NULL){ 964 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 965 } 966 if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){ 967 return ERROR_CODE_COMMAND_DISALLOWED; 968 } 969 bass_client_source_t * source = bass_client_get_source_for_source_id(connection, source_id); 970 if (source == NULL){ 971 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 972 } 973 *out_big_encryption = source->big_encryption; 974 memcpy(out_bad_code, source->bad_code, 16); 975 return ERROR_CODE_SUCCESS; 976 } 977 978 void broadcast_audio_scan_service_client_deinit(uint16_t bass_cid){ 979 bass_client_event_callback = NULL; 980 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 981 if (connection == NULL){ 982 return; 983 } 984 // finalize connections 985 bass_client_finalize_connection(connection); 986 } 987 988