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 bass_client_connection_t * connection = bass_client_get_connection_for_con_handle(gatt_event_notification_get_handle(packet)); 261 if (connection == NULL){ 262 return; 263 } 264 265 uint16_t value_handle = gatt_event_notification_get_value_handle(packet); 266 uint16_t value_length = gatt_event_notification_get_value_length(packet); 267 uint8_t * value = (uint8_t *)gatt_event_notification_get_value(packet); 268 269 if (bass_client_remote_broadcast_receive_state_buffer_valid(value, value_length)){ 270 bass_client_source_t * source = bass_client_get_receive_state_for_value_handle(connection, value_handle); 271 if (source == NULL){ 272 return; 273 } 274 source->source_id = value[0]; 275 bass_util_source_data_parse(&value[1], value_length - 1, &source->data, true); 276 277 // get big encryption + bad code 278 source->big_encryption = (le_audio_big_encryption_t) value[13]; 279 if (source->big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){ 280 reverse_128(&value[14], source->bad_code); 281 } else { 282 memset(source->bad_code, 0, 16); 283 } 284 285 bass_client_emit_receive_state(connection, source->source_id); 286 } 287 } 288 289 static bool bass_client_register_notification(bass_client_connection_t * connection){ 290 bass_client_source_t * receive_state = &connection->receive_states[connection->receive_states_index]; 291 if (receive_state == NULL){ 292 return false; 293 } 294 295 gatt_client_characteristic_t characteristic; 296 characteristic.value_handle = receive_state->receive_state_value_handle; 297 characteristic.properties = receive_state->receive_state_properties; 298 characteristic.end_handle = receive_state->receive_state_end_handle; 299 300 uint8_t status = gatt_client_write_client_characteristic_configuration( 301 &bass_client_handle_gatt_client_event, 302 connection->con_handle, 303 &characteristic, 304 GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 305 306 // notification supported, register for value updates 307 if (status == ERROR_CODE_SUCCESS){ 308 gatt_client_listen_for_characteristic_value_updates( 309 &connection->notification_listener, 310 &bass_client_handle_gatt_server_notification, 311 connection->con_handle, &characteristic); 312 } 313 return status; 314 } 315 316 static uint16_t bass_client_prepare_add_source_buffer(bass_client_connection_t * connection){ 317 const bass_source_data_t * receive_state = connection->control_point_operation_data; 318 319 uint16_t buffer_offset = connection->buffer_offset; 320 uint8_t * buffer = connection->buffer; 321 uint16_t buffer_size = btstack_min(sizeof(connection->buffer), connection->mtu); 322 323 btstack_assert(buffer_offset == 0); 324 325 uint8_t field_data[6]; 326 uint16_t source_offset = 0; 327 uint16_t stored_bytes = 0; 328 memset(buffer, 0, buffer_size); 329 330 field_data[0] = (uint8_t)BASS_OPCODE_ADD_SOURCE; 331 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 332 buffer_offset); 333 source_offset++; 334 335 stored_bytes += bass_util_source_data_header_virtual_memcpy(receive_state, &source_offset, buffer_offset, buffer, 336 buffer_size); 337 338 field_data[0] = (uint8_t)receive_state->pa_sync; 339 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 340 buffer_offset); 341 source_offset++; 342 343 little_endian_store_16(field_data, 0, receive_state->pa_interval); 344 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, source_offset, buffer, buffer_size, 345 buffer_offset); 346 source_offset += 2; 347 348 stored_bytes += bass_util_source_data_subgroups_virtual_memcpy(receive_state, false, &source_offset, buffer_offset, 349 buffer, 350 buffer_size); 351 352 return stored_bytes; 353 } 354 355 static uint16_t bass_client_prepare_modify_source_buffer(bass_client_connection_t * connection){ 356 const bass_source_data_t * receive_state = connection->control_point_operation_data; 357 358 uint16_t buffer_offset = connection->buffer_offset; 359 uint8_t * buffer = connection->buffer; 360 uint16_t buffer_size = btstack_min(sizeof(connection->buffer), connection->mtu); 361 362 btstack_assert(buffer_offset == 0); 363 364 uint8_t field_data[6]; 365 uint16_t source_offset = 0; 366 uint16_t stored_bytes = 0; 367 memset(buffer, 0, buffer_size); 368 369 field_data[0] = (uint8_t)BASS_OPCODE_MODIFY_SOURCE; 370 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 371 buffer_offset); 372 source_offset++; 373 374 field_data[0] = connection->control_point_operation_source_id; 375 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 376 buffer_offset); 377 source_offset++; 378 379 field_data[0] = (uint8_t)receive_state->pa_sync; 380 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 381 buffer_offset); 382 source_offset++; 383 384 little_endian_store_16(field_data, 0, receive_state->pa_interval); 385 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, source_offset, buffer, buffer_size, 386 buffer_offset); 387 source_offset += 2; 388 389 stored_bytes += bass_util_source_data_subgroups_virtual_memcpy(receive_state, false, &source_offset, buffer_offset, 390 buffer, 391 buffer_size); 392 return stored_bytes; 393 } 394 395 static uint16_t bass_client_receive_state_len(const bass_source_data_t * source_data){ 396 uint16_t source_len = 0; 397 // opcode(1), address_type(1), address(6), adv_sid(1), broadcast_id(3), pa_sync(1), subgroups_num(1) 398 source_len = 1 + 1 + 6 + 1 + 3 + 1 + 1; 399 400 uint8_t i; 401 for (i = 0; i < source_data->subgroups_num; i++){ 402 bass_subgroup_t subgroup = source_data->subgroups[i]; 403 // bis_sync(4), metadata_length(1), metadata_length 404 source_len += 4 + 1 + subgroup.metadata_length; 405 } 406 return source_len; 407 } 408 409 static void bass_client_run_for_connection(bass_client_connection_t * connection){ 410 uint8_t status; 411 gatt_client_characteristic_t characteristic; 412 gatt_client_service_t service; 413 414 uint8_t value[18]; 415 uint16_t stored_bytes; 416 417 switch (connection->state){ 418 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED: 419 break; 420 421 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_START_SCAN: 422 #ifdef ENABLE_TESTING_SUPPORT 423 printf(" Write START SCAN [0x%04X]:\n", 424 connection->control_point_value_handle); 425 #endif 426 427 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_START_SCAN; 428 value[0] = BASS_OPCODE_REMOTE_SCAN_STARTED; 429 // see GATT_EVENT_QUERY_COMPLETE for end of write 430 status = gatt_client_write_value_of_characteristic( 431 &bass_client_handle_gatt_client_event, connection->con_handle, 432 connection->control_point_value_handle, 1, &value[0]); 433 UNUSED(status); 434 break; 435 436 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_STOP_SCAN: 437 #ifdef ENABLE_TESTING_SUPPORT 438 printf(" Write START SCAN [0x%04X]:\n", 439 connection->control_point_value_handle); 440 #endif 441 442 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_STOP_SCAN; 443 value[0] = BASS_OPCODE_REMOTE_SCAN_STOPPED; 444 // see GATT_EVENT_QUERY_COMPLETE for end of write 445 status = gatt_client_write_value_of_characteristic( 446 &bass_client_handle_gatt_client_event, connection->con_handle, 447 connection->control_point_value_handle, 1, &value[0]); 448 UNUSED(status); 449 break; 450 451 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_ADD_SOURCE: 452 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE; 453 #ifdef ENABLE_TESTING_SUPPORT 454 printf(" ADD SOURCE [0x%04X]:\n", connection->control_point_value_handle); 455 #endif 456 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE; 457 stored_bytes = bass_client_prepare_add_source_buffer(connection); 458 connection->buffer_offset += stored_bytes; 459 460 gatt_client_write_long_value_of_characteristic(&bass_client_handle_gatt_client_event, connection->con_handle, 461 connection->control_point_value_handle, stored_bytes, connection->buffer); 462 break; 463 464 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_MODIFY_SOURCE: 465 #ifdef ENABLE_TESTING_SUPPORT 466 printf(" MODIFY SOURCE [%d]:\n", connection->control_point_operation_source_id); 467 #endif 468 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_MODIFY_SOURCE; 469 stored_bytes = bass_client_prepare_modify_source_buffer(connection); 470 connection->buffer_offset += stored_bytes; 471 472 gatt_client_write_long_value_of_characteristic(&bass_client_handle_gatt_client_event, connection->con_handle, 473 connection->control_point_value_handle, stored_bytes, connection->buffer); 474 475 break; 476 477 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_REMOVE_SOURCE: 478 #ifdef ENABLE_TESTING_SUPPORT 479 printf(" REMOVE SOURCE [%d]:\n", connection->control_point_operation_source_id); 480 #endif 481 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_REMOVE_SOURCE; 482 value[0] = BASS_OPCODE_REMOVE_SOURCE; 483 value[1] = connection->control_point_operation_source_id; 484 // see GATT_EVENT_QUERY_COMPLETE for end of write 485 status = gatt_client_write_value_of_characteristic( 486 &bass_client_handle_gatt_client_event, connection->con_handle, 487 connection->control_point_value_handle, 2, &value[0]); 488 UNUSED(status); 489 break; 490 491 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_SET_BROADCAST_CODE: 492 #ifdef ENABLE_TESTING_SUPPORT 493 printf(" SET BROADCAST CODE [%d]:\n", connection->control_point_operation_source_id); 494 #endif 495 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_SET_BROADCAST_CODE; 496 value[0] = BASS_OPCODE_SET_BROADCAST_CODE; 497 value[1] = connection->control_point_operation_source_id; 498 reverse_128(connection->broadcast_code, &value[2]); 499 500 // see GATT_EVENT_QUERY_COMPLETE for end of write 501 status = gatt_client_write_value_of_characteristic( 502 &bass_client_handle_gatt_client_event, connection->con_handle, 503 connection->control_point_value_handle, 18, &value[0]); 504 UNUSED(status); 505 break; 506 507 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE: 508 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT; 509 gatt_client_discover_primary_services_by_uuid16(&bass_client_handle_gatt_client_event, connection->con_handle, ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE); 510 break; 511 512 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS: 513 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT; 514 515 service.start_group_handle = connection->start_handle; 516 service.end_group_handle = connection->end_handle; 517 service.uuid16 = ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE; 518 519 gatt_client_discover_characteristics_for_service( 520 &bass_client_handle_gatt_client_event, 521 connection->con_handle, 522 &service); 523 524 break; 525 526 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS: 527 #ifdef ENABLE_TESTING_SUPPORT 528 printf("Read client characteristic descriptors [index %d]:\n", connection->receive_states_index); 529 #endif 530 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_DESCRIPTORS_RESULT; 531 characteristic.value_handle = connection->receive_states[connection->receive_states_index].receive_state_value_handle; 532 characteristic.properties = connection->receive_states[connection->receive_states_index].receive_state_properties; 533 characteristic.end_handle = connection->receive_states[connection->receive_states_index].receive_state_end_handle; 534 535 (void) gatt_client_discover_characteristic_descriptors(&bass_client_handle_gatt_client_event, connection->con_handle, &characteristic); 536 break; 537 538 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION: 539 #ifdef ENABLE_TESTING_SUPPORT 540 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); 541 #endif 542 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT; 543 544 // result in GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT 545 (void) gatt_client_read_characteristic_descriptor_using_descriptor_handle( 546 &bass_client_handle_gatt_client_event, 547 connection->con_handle, 548 connection->receive_states[connection->receive_states_index].receive_state_ccc_handle); 549 break; 550 551 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION: 552 #ifdef ENABLE_TESTING_SUPPORT 553 printf("Register notification [index %d, handle 0x%04X]:\n", connection->receive_states_index, connection->receive_states[connection->receive_states_index].receive_state_ccc_handle); 554 #endif 555 556 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED; 557 558 status = bass_client_register_notification(connection); 559 if (status == ERROR_CODE_SUCCESS) return; 560 561 if (connection->receive_states[connection->receive_states_index].receive_state_ccc_handle != 0){ 562 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION; 563 break; 564 } 565 566 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 567 bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS); 568 break; 569 default: 570 break; 571 } 572 } 573 // @return true if client valid / run function should be called 574 static bool bass_client_handle_query_complete(bass_client_connection_t * connection, uint8_t status){ 575 switch (connection->state){ 576 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT: 577 if (status != ATT_ERROR_SUCCESS){ 578 bass_client_emit_connection_established(connection, status); 579 bass_client_finalize_connection(connection); 580 return false; 581 } 582 583 if (connection->service_instances_num == 0){ 584 bass_client_emit_connection_established(connection, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 585 bass_client_finalize_connection(connection); 586 return false; 587 } 588 connection->receive_states_index = 0; 589 connection->receive_states_instances_num = 0; 590 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS; 591 break; 592 593 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT: 594 if (status != ATT_ERROR_SUCCESS){ 595 bass_client_emit_connection_established(connection, status); 596 bass_client_finalize_connection(connection); 597 return false; 598 } 599 600 connection->receive_states_index = 0; 601 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS; 602 break; 603 604 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_DESCRIPTORS_RESULT: 605 if (connection->receive_states_index < (connection->receive_states_instances_num - 1)){ 606 connection->receive_states_index++; 607 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS; 608 break; 609 } 610 connection->receive_states_index = 0; 611 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION; 612 break; 613 614 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED: 615 if (connection->receive_states_index < (connection->receive_states_instances_num - 1)){ 616 connection->receive_states_index++; 617 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION; 618 break; 619 } 620 621 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 622 bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS); 623 break; 624 625 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT: 626 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 627 bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS); 628 break; 629 630 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_START_SCAN: 631 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 632 bass_client_emit_scan_operation_complete(connection, status, BASS_OPCODE_REMOTE_SCAN_STARTED); 633 break; 634 635 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_STOP_SCAN: 636 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 637 bass_client_emit_scan_operation_complete(connection, status, BASS_OPCODE_REMOTE_SCAN_STOPPED); 638 break; 639 640 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE: 641 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 642 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_ADD_SOURCE, BASS_INVALID_SOURCE_INDEX); 643 break; 644 645 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_MODIFY_SOURCE: 646 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 647 bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_MODIFY_SOURCE, connection->control_point_operation_source_id); 648 break; 649 650 case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_REMOVE_SOURCE: 651 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED; 652 bass_client_reset_source( 653 bass_client_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 bass_client_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_client_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_client_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_client_get_connection_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_client_get_connection_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_client_get_connection_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_client_get_connection_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_client_get_connection_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_client_get_connection_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_client_get_connection_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_client_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_client_get_connection_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_client_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_event_callback = NULL; 979 bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid); 980 if (connection == NULL){ 981 return; 982 } 983 // finalize connections 984 bass_client_finalize_connection(connection); 985 } 986 987