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_server.c" 39 40 #include <stdio.h> 41 42 #include "ble/att_db.h" 43 #include "ble/att_server.h" 44 #include "bluetooth_gatt.h" 45 #include "btstack_debug.h" 46 #include "btstack_defines.h" 47 #include "btstack_event.h" 48 #include "btstack_util.h" 49 50 #include "le-audio/gatt-service/broadcast_audio_scan_service_server.h" 51 #include "le-audio/le_audio_util.h" 52 53 #ifdef ENABLE_TESTING_SUPPORT 54 #include <stdio.h> 55 #endif 56 57 #define BASS_MAX_NOTIFY_BUFFER_SIZE 200 58 #define BASS_INVALID_SOURCE_INDEX 0xFF 59 60 static att_service_handler_t broadcast_audio_scan_service; 61 static btstack_packet_handler_t bass_event_callback; 62 63 // characteristic: AUDIO_SCAN_CONTROL_POINT 64 static uint16_t bass_audio_scan_control_point_handle; 65 66 static uint8_t bass_logic_time = 0; 67 68 static bass_server_source_t * bass_sources; 69 static uint8_t bass_sources_num = 0; 70 static bass_remote_client_t * bass_clients; 71 static uint8_t bass_clients_num = 0; 72 static btstack_context_callback_registration_t scheduled_tasks_callback; 73 74 static uint8_t bass_get_next_update_counter(void){ 75 uint8_t next_update_counter; 76 if (bass_logic_time == 0xff) { 77 next_update_counter = 0; 78 } else { 79 next_update_counter = bass_logic_time + 1; 80 } 81 bass_logic_time = next_update_counter; 82 return next_update_counter; 83 } 84 85 // returns positive number if counter a > b 86 static int8_t bass_counter_delta(uint8_t counter_a, uint8_t counter_b){ 87 return (int8_t)(counter_a - counter_b); 88 } 89 90 static uint8_t bass_find_empty_or_last_used_source_index(void){ 91 bass_server_source_t * last_used_source = NULL; 92 uint8_t last_used_source_index = BASS_INVALID_SOURCE_INDEX; 93 94 uint8_t i; 95 for (i = 0; i < bass_sources_num; i++){ 96 if (!bass_sources[i].in_use){ 97 return i; 98 } 99 if (last_used_source == NULL){ 100 last_used_source = &bass_sources[i]; 101 last_used_source_index = i; 102 continue; 103 } 104 if (bass_counter_delta(bass_sources[i].update_counter, last_used_source->update_counter) < 0 ){ 105 last_used_source = &bass_sources[i]; 106 last_used_source_index = i; 107 } 108 } 109 return last_used_source_index; 110 } 111 112 static bass_server_source_t * bass_find_empty_or_last_used_source(void){ 113 uint8_t last_used_source_index = bass_find_empty_or_last_used_source_index(); 114 if (last_used_source_index == BASS_INVALID_SOURCE_INDEX){ 115 return NULL; 116 } 117 return &bass_sources[last_used_source_index]; 118 } 119 120 static bass_server_source_t * bass_find_receive_state_for_value_handle(uint16_t attribute_handle){ 121 uint16_t i; 122 for (i = 0; i < bass_sources_num; i++){ 123 if (attribute_handle == bass_sources[i].bass_receive_state_handle){ 124 return &bass_sources[i]; 125 } 126 } 127 return NULL; 128 } 129 130 static bass_server_source_t * bass_find_receive_state_for_client_configuration_handle(uint16_t attribute_handle){ 131 if (attribute_handle == 0){ 132 return NULL; 133 } 134 uint8_t i; 135 for (i = 0; i < bass_sources_num; i++){ 136 if (bass_sources[i].bass_receive_state_client_configuration_handle == attribute_handle){ 137 return &bass_sources[i]; 138 } 139 } 140 return NULL; 141 } 142 143 static bass_server_source_t * bass_find_source_for_source_id(uint8_t source_id){ 144 if (source_id < bass_sources_num){ 145 return &bass_sources[source_id]; 146 } 147 return NULL; 148 } 149 150 static bass_remote_client_t * bass_find_client_for_con_handle(hci_con_handle_t con_handle){ 151 uint16_t i; 152 for (i = 0; i < bass_clients_num; i++){ 153 if (bass_clients[i].con_handle == con_handle) { 154 return &bass_clients[i]; 155 } 156 } 157 return NULL; 158 } 159 160 static void bass_register_con_handle(hci_con_handle_t con_handle, uint16_t client_configuration){ 161 bass_remote_client_t * client = bass_find_client_for_con_handle(con_handle); 162 if (client == NULL){ 163 client = bass_find_client_for_con_handle(HCI_CON_HANDLE_INVALID); 164 if (client == NULL){ 165 return; 166 } 167 168 } 169 client->con_handle = (client_configuration == 0) ? HCI_CON_HANDLE_INVALID : con_handle; 170 } 171 172 static void bass_emit_remote_scan_stoped(hci_con_handle_t con_handle){ 173 btstack_assert(bass_event_callback != NULL); 174 175 uint8_t event[5]; 176 uint8_t pos = 0; 177 event[pos++] = HCI_EVENT_GATTSERVICE_META; 178 event[pos++] = sizeof(event) - 2; 179 event[pos++] = GATTSERVICE_SUBEVENT_BASS_REMOTE_SCAN_STOPPED; 180 little_endian_store_16(event, pos, con_handle); 181 pos += 2; 182 (*bass_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 183 } 184 185 static void bass_emit_remote_scan_started(hci_con_handle_t con_handle){ 186 btstack_assert(bass_event_callback != NULL); 187 188 uint8_t event[5]; 189 uint8_t pos = 0; 190 event[pos++] = HCI_EVENT_GATTSERVICE_META; 191 event[pos++] = sizeof(event) - 2; 192 event[pos++] = GATTSERVICE_SUBEVENT_BASS_REMOTE_SCAN_STARTED; 193 little_endian_store_16(event, pos, con_handle); 194 pos += 2; 195 (*bass_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 196 } 197 198 199 static void bass_emit_source_state_changed(uint8_t subevent_id, hci_con_handle_t con_handle, uint8_t source_id, le_audio_pa_sync_t pa_sync){ 200 btstack_assert(bass_event_callback != NULL); 201 202 uint8_t event[7]; 203 uint8_t pos = 0; 204 event[pos++] = HCI_EVENT_GATTSERVICE_META; 205 event[pos++] = sizeof(event) - 2; 206 event[pos++] = subevent_id; 207 little_endian_store_16(event, pos, con_handle); 208 pos += 2; 209 event[pos++] = source_id; 210 event[pos++] = (uint8_t)pa_sync; 211 (*bass_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 212 } 213 214 static void bass_emit_source_added(hci_con_handle_t con_handle, bass_server_source_t * source){ 215 bass_emit_source_state_changed(GATTSERVICE_SUBEVENT_BASS_SOURCE_ADDED, con_handle, source->source_id, source->data.pa_sync); 216 } 217 218 static void bass_emit_source_modified(hci_con_handle_t con_handle, bass_server_source_t * source){ 219 bass_emit_source_state_changed(GATTSERVICE_SUBEVENT_BASS_SOURCE_MODIFIED, con_handle, source->source_id, source->data.pa_sync); 220 } 221 222 static void bass_emit_source_deleted(hci_con_handle_t con_handle, bass_server_source_t * source){ 223 bass_emit_source_state_changed(GATTSERVICE_SUBEVENT_BASS_SOURCE_DELETED, con_handle, source->source_id, LE_AUDIO_PA_SYNC_DO_NOT_SYNCHRONIZE_TO_PA); 224 } 225 226 static void bass_emit_broadcast_code(hci_con_handle_t con_handle, uint8_t source_id, const uint8_t * broadcast_code){ 227 btstack_assert(bass_event_callback != NULL); 228 229 uint8_t event[22]; 230 uint8_t pos = 0; 231 event[pos++] = HCI_EVENT_GATTSERVICE_META; 232 event[pos++] = sizeof(event) - 2; 233 event[pos++] = GATTSERVICE_SUBEVENT_BASS_BROADCAST_CODE; 234 little_endian_store_16(event, pos, con_handle); 235 pos += 2; 236 event[pos++] = source_id; 237 reverse_128(broadcast_code, &event[pos]); 238 pos += 16; 239 (*bass_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 240 } 241 242 // offset gives position into fully serialized bass record 243 static uint16_t bass_server_copy_source_to_buffer(bass_server_source_t * source, uint16_t buffer_offset, uint8_t * buffer, uint16_t buffer_size){ 244 uint8_t field_data[16]; 245 uint16_t source_offset = 0; 246 uint16_t stored_bytes = 0; 247 memset(buffer, 0, buffer_size); 248 249 if (!source->in_use){ 250 return 0; 251 } 252 field_data[0] = source->source_id; 253 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 254 buffer_offset); 255 source_offset++; 256 257 stored_bytes += bass_util_source_data_header_virtual_memcpy(&source->data, &source_offset, buffer_offset, buffer, 258 buffer_size); 259 260 field_data[0] = (uint8_t)source->data.pa_sync_state; 261 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 262 buffer_offset); 263 source_offset++; 264 265 field_data[0] = (uint8_t)source->big_encryption; 266 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 267 buffer_offset); 268 source_offset++; 269 270 if (source->big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){ 271 reverse_128(source->bad_code, &field_data[0]); 272 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 16, source_offset, buffer, buffer_size, 273 buffer_offset); 274 source_offset += 16; 275 } 276 277 stored_bytes += bass_util_source_data_subgroups_virtual_memcpy(&source->data, true, &source_offset, buffer_offset, 278 buffer, 279 buffer_size); 280 return stored_bytes; 281 } 282 283 static uint16_t broadcast_audio_scan_service_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 284 UNUSED(con_handle); 285 286 bass_server_source_t * source; 287 source = bass_find_receive_state_for_value_handle(attribute_handle); 288 if (source){ 289 return bass_server_copy_source_to_buffer(source, offset, buffer, buffer_size); 290 } 291 292 source = bass_find_receive_state_for_client_configuration_handle(attribute_handle); 293 if (source){ 294 return att_read_callback_handle_little_endian_16(source->bass_receive_state_client_configuration, offset, buffer, buffer_size); 295 } 296 297 return 0; 298 } 299 300 static bool bass_source_remote_modify_source_buffer_valid(uint8_t *buffer, uint16_t buffer_size){ 301 if (buffer_size < 10){ 302 log_info("Modify Source opcode, buffer too small"); 303 return false; 304 } 305 306 uint8_t pos = 1; // source_id 307 return bass_util_pa_sync_state_and_subgroups_in_valid_range(buffer+pos, buffer_size-pos); 308 } 309 310 static void bass_server_add_source_from_buffer(uint8_t *buffer, uint16_t buffer_size, bass_server_source_t * source){ 311 UNUSED(buffer_size); 312 313 source->update_counter = bass_get_next_update_counter(); 314 source->in_use = true; 315 316 bass_util_source_data_parse(buffer, buffer_size, &source->data, false); 317 } 318 319 static bool bass_pa_synchronized(bass_server_source_t * source){ 320 return source->data.pa_sync_state == LE_AUDIO_PA_SYNC_STATE_SYNCHRONIZED_TO_PA; 321 } 322 323 324 static bool bass_bis_synchronized(bass_server_source_t * source){ 325 uint8_t i; 326 for (i = 0; i < source->data.subgroups_num; i++){ 327 if ((source->data.subgroups[i].bis_sync_state > 0) && (source->data.subgroups[i].bis_sync_state < 0xFFFFFFFF)){ 328 return true; 329 } 330 } 331 return false; 332 } 333 334 335 static void bass_reset_source(bass_server_source_t * source){ 336 source->in_use = false; 337 source->data.address_type = BD_ADDR_TYPE_LE_PUBLIC; 338 memset(source->data.address, 0, sizeof(source->data.address)); 339 source->data.adv_sid = 0; 340 source->data.broadcast_id = 0; 341 source->data.pa_sync = LE_AUDIO_PA_SYNC_DO_NOT_SYNCHRONIZE_TO_PA; 342 source->data.pa_sync_state = LE_AUDIO_PA_SYNC_STATE_NOT_SYNCHRONIZED_TO_PA; 343 source->big_encryption = LE_AUDIO_BIG_ENCRYPTION_NOT_ENCRYPTED; 344 memset(source->bad_code, 0, sizeof(source->bad_code)); 345 source->data.pa_interval = 0; 346 source->data.subgroups_num = 0; 347 memset(source->data.subgroups, 0, sizeof(source->data.subgroups)); 348 } 349 350 static void bass_reset_client_long_write_buffer(bass_remote_client_t * client){ 351 memset(client->long_write_buffer, 0, sizeof(client->long_write_buffer)); 352 client->long_write_value_size = 0; 353 } 354 355 static int broadcast_audio_scan_service_write_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ 356 // printf("broadcast_audio_scan_service_write_callback con_handle 0x%02x, attr_handle 0x%02x \n", con_handle, attribute_handle); 357 if (attribute_handle != 0 && attribute_handle != bass_audio_scan_control_point_handle){ 358 359 bass_server_source_t * source = bass_find_receive_state_for_client_configuration_handle(attribute_handle); 360 if (source){ 361 source->bass_receive_state_client_configuration = little_endian_read_16(buffer, 0); 362 bass_register_con_handle(con_handle, source->bass_receive_state_client_configuration); 363 } 364 return 0; 365 } 366 367 368 bass_remote_client_t * client = bass_find_client_for_con_handle(con_handle); 369 if (client == NULL){ 370 return ATT_ERROR_WRITE_REQUEST_REJECTED; 371 } 372 373 uint16_t total_value_len = buffer_size + offset; 374 375 switch (transaction_mode){ 376 case ATT_TRANSACTION_MODE_NONE: 377 if (buffer_size > sizeof(client->long_write_buffer)){ 378 bass_reset_client_long_write_buffer(client); 379 return ATT_ERROR_WRITE_REQUEST_REJECTED; 380 } 381 memcpy(&client->long_write_buffer[0], buffer, buffer_size); 382 client->long_write_value_size = total_value_len; 383 break; 384 385 case ATT_TRANSACTION_MODE_ACTIVE: 386 if (total_value_len > sizeof(client->long_write_buffer)){ 387 bass_reset_client_long_write_buffer(client); 388 return ATT_ERROR_WRITE_REQUEST_REJECTED; 389 } 390 // allow overlapped and/or mixed order chunks 391 client->long_write_attribute_handle = attribute_handle; 392 393 memcpy(&client->long_write_buffer[offset], buffer, buffer_size); 394 if (total_value_len > client->long_write_value_size){ 395 client->long_write_value_size = total_value_len; 396 } 397 return 0; 398 399 case ATT_TRANSACTION_MODE_VALIDATE: 400 return 0; 401 402 case ATT_TRANSACTION_MODE_EXECUTE: 403 attribute_handle = client->long_write_attribute_handle; 404 break; 405 406 default: 407 return 0; 408 } 409 410 if (attribute_handle == bass_audio_scan_control_point_handle){ 411 if (client->long_write_value_size < 2){ 412 return ATT_ERROR_WRITE_REQUEST_REJECTED; 413 } 414 415 bass_opcode_t opcode = (bass_opcode_t)client->long_write_buffer[0]; 416 uint8_t *remote_data = &client->long_write_buffer[1]; 417 uint16_t remote_data_size = client->long_write_value_size - 1; 418 419 bass_server_source_t * source; 420 uint8_t broadcast_code[16]; 421 switch (opcode){ 422 case BASS_OPCODE_REMOTE_SCAN_STOPPED: 423 if (remote_data_size != 1){ 424 return ATT_ERROR_WRITE_REQUEST_REJECTED; 425 } 426 bass_emit_remote_scan_stoped(con_handle); 427 break; 428 429 case BASS_OPCODE_REMOTE_SCAN_STARTED: 430 if (remote_data_size != 1){ 431 return ATT_ERROR_WRITE_REQUEST_REJECTED; 432 } 433 bass_emit_remote_scan_started(con_handle); 434 break; 435 436 case BASS_OPCODE_ADD_SOURCE: 437 if (!bass_util_source_buffer_in_valid_range(remote_data, remote_data_size)){ 438 return ATT_ERROR_WRITE_REQUEST_REJECTED; 439 } 440 source = bass_find_empty_or_last_used_source(); 441 btstack_assert(source != NULL); 442 log_info("add source %d", source->source_id); 443 bass_server_add_source_from_buffer(remote_data, remote_data_size, source); 444 bass_emit_source_added(con_handle, source); 445 // server needs to trigger notification 446 break; 447 448 case BASS_OPCODE_MODIFY_SOURCE: 449 if (!bass_source_remote_modify_source_buffer_valid(remote_data, remote_data_size)){ 450 return ATT_ERROR_WRITE_REQUEST_REJECTED; 451 } 452 453 source = bass_find_source_for_source_id(remote_data[0]); 454 if (source == NULL){ 455 return BASS_ERROR_CODE_INVALID_SOURCE_ID; 456 } 457 bass_util_pa_info_and_subgroups_parse(remote_data + 1, remote_data_size - 1, &source->data, false); 458 bass_emit_source_modified(con_handle, source); 459 // server needs to trigger notification 460 break; 461 462 case BASS_OPCODE_SET_BROADCAST_CODE: 463 if (remote_data_size != 17){ 464 return ATT_ERROR_WRITE_REQUEST_REJECTED; 465 } 466 467 source = bass_find_source_for_source_id(remote_data[0]); 468 if (source == NULL){ 469 return BASS_ERROR_CODE_INVALID_SOURCE_ID; 470 } 471 reverse_128(&remote_data[1], broadcast_code); 472 bass_emit_broadcast_code(con_handle, source->source_id, broadcast_code); 473 break; 474 475 case BASS_OPCODE_REMOVE_SOURCE: 476 if (remote_data_size != 1){ 477 return ATT_ERROR_WRITE_REQUEST_REJECTED; 478 } 479 source = bass_find_source_for_source_id(remote_data[0]); 480 if (source == NULL){ 481 return BASS_ERROR_CODE_INVALID_SOURCE_ID; 482 } 483 484 if (bass_pa_synchronized(source)){ 485 log_info("remove source %d rejected, PA synchronised", source->source_id); 486 return 0; 487 } 488 489 if (bass_bis_synchronized(source)){ 490 log_info("remove source %d rejected, BIS synchronised", source->source_id); 491 return 0; 492 } 493 494 bass_reset_source(source); 495 broadcast_audio_scan_service_server_set_pa_sync_state(source->source_id, LE_AUDIO_PA_SYNC_STATE_NOT_SYNCHRONIZED_TO_PA); 496 bass_emit_source_deleted(con_handle, source); 497 break; 498 499 default: 500 bass_reset_client_long_write_buffer(client); 501 return BASS_ERROR_CODE_OPCODE_NOT_SUPPORTED; 502 } 503 bass_reset_client_long_write_buffer(client); 504 } 505 return 0; 506 } 507 508 static void broadcast_audio_scan_service_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 509 UNUSED(channel); 510 UNUSED(packet); 511 UNUSED(size); 512 513 if (packet_type != HCI_EVENT_PACKET){ 514 return; 515 } 516 517 hci_con_handle_t con_handle; 518 bass_remote_client_t * client; 519 520 switch (hci_event_packet_get_type(packet)) { 521 case HCI_EVENT_DISCONNECTION_COMPLETE: 522 con_handle = hci_event_disconnection_complete_get_connection_handle(packet); 523 524 client = bass_find_client_for_con_handle(con_handle); 525 if (client == NULL){ 526 break; 527 } 528 529 memset(client, 0, sizeof(bass_remote_client_t)); 530 client->con_handle = HCI_CON_HANDLE_INVALID; 531 break; 532 default: 533 break; 534 } 535 } 536 537 void broadcast_audio_scan_service_server_init(const uint8_t sources_num, bass_server_source_t * sources, const uint8_t clients_num, bass_remote_client_t * clients){ 538 // get service handle range 539 btstack_assert(sources_num != 0); 540 btstack_assert(clients_num != 0); 541 542 uint16_t start_handle = 0; 543 uint16_t end_handle = 0xffff; 544 bool service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE, &start_handle, &end_handle); 545 btstack_assert(service_found); 546 547 UNUSED(service_found); 548 549 bass_audio_scan_control_point_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_AUDIO_SCAN_CONTROL_POINT); 550 bass_sources_num = 0; 551 bass_logic_time = 0; 552 bass_sources = sources; 553 554 #ifdef ENABLE_TESTING_SUPPORT 555 printf("BASS 0x%02x - 0x%02x \n", start_handle, end_handle); 556 #endif 557 uint16_t start_chr_handle = start_handle; 558 while ( (start_chr_handle < end_handle) && (bass_sources_num < sources_num )) { 559 uint16_t chr_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_chr_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE); 560 uint16_t chr_client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_chr_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE); 561 562 if (chr_value_handle == 0){ 563 break; 564 } 565 bass_server_source_t * source = &bass_sources[bass_sources_num]; 566 bass_reset_source(source); 567 568 source->source_id = bass_sources_num; 569 source->update_counter = bass_get_next_update_counter(); 570 source->bass_receive_state_client_configuration = 0; 571 572 source->bass_receive_state_handle = chr_value_handle; 573 source->bass_receive_state_client_configuration_handle = chr_client_configuration_handle; 574 575 #ifdef ENABLE_TESTING_SUPPORT 576 printf(" bass_receive_state_%d 0x%02x \n", bass_sources_num, source->bass_receive_state_handle); 577 printf(" bass_receive_state_%d CCC 0x%02x \n", bass_sources_num, source->bass_receive_state_client_configuration_handle); 578 #endif 579 580 start_chr_handle = chr_client_configuration_handle + 1; 581 bass_sources_num++; 582 } 583 584 bass_clients_num = clients_num; 585 bass_clients = clients; 586 memset(bass_clients, 0, sizeof(bass_remote_client_t) * bass_clients_num); 587 uint8_t i; 588 for (i = 0; i < bass_clients_num; i++){ 589 bass_clients[i].con_handle = HCI_CON_HANDLE_INVALID; 590 } 591 592 log_info("Found BASS service 0x%02x-0x%02x (num sources %d)", start_handle, end_handle, bass_sources_num); 593 594 // register service with ATT Server 595 broadcast_audio_scan_service.start_handle = start_handle; 596 broadcast_audio_scan_service.end_handle = end_handle; 597 broadcast_audio_scan_service.read_callback = &broadcast_audio_scan_service_read_callback; 598 broadcast_audio_scan_service.write_callback = &broadcast_audio_scan_service_write_callback; 599 broadcast_audio_scan_service.packet_handler = broadcast_audio_scan_service_packet_handler; 600 att_server_register_service_handler(&broadcast_audio_scan_service); 601 } 602 603 void broadcast_audio_scan_service_server_register_packet_handler(btstack_packet_handler_t callback){ 604 btstack_assert(callback != NULL); 605 bass_event_callback = callback; 606 } 607 608 static void bass_service_can_send_now(void * context){ 609 bass_remote_client_t * client = (bass_remote_client_t *) context; 610 btstack_assert(client != NULL); 611 612 uint8_t source_index; 613 for (source_index = 0; source_index < bass_sources_num; source_index++){ 614 uint8_t task = (1 << source_index); 615 if ((client->sources_to_notify & task) != 0){ 616 client->sources_to_notify &= ~task; 617 uint8_t buffer[BASS_MAX_NOTIFY_BUFFER_SIZE]; 618 uint16_t bytes_copied = bass_server_copy_source_to_buffer(&bass_sources[source_index], 0, buffer, sizeof(buffer)); 619 att_server_notify(client->con_handle, bass_sources[source_index].bass_receive_state_handle, &buffer[0], bytes_copied); 620 return; 621 } 622 } 623 624 uint8_t i; 625 for (i = 0; i < bass_clients_num; i++){ 626 client = &bass_clients[i]; 627 628 if (client->sources_to_notify != 0){ 629 scheduled_tasks_callback.callback = &bass_service_can_send_now; 630 scheduled_tasks_callback.context = (void*) client; 631 att_server_register_can_send_now_callback(&scheduled_tasks_callback, client->con_handle); 632 return; 633 } 634 } 635 } 636 637 static void bass_set_callback(uint8_t source_index){ 638 // there is only one type of task: notify on source state change 639 // as task we register which source is changed, and the change will be propagated to all clients 640 uint8_t i; 641 uint8_t task = (1 << source_index); 642 643 uint8_t scheduled_tasks = 0; 644 645 for (i = 0; i < bass_clients_num; i++){ 646 bass_remote_client_t * client = &bass_clients[i]; 647 648 if (client->con_handle == HCI_CON_HANDLE_INVALID){ 649 client->sources_to_notify &= ~task; 650 return; 651 } 652 653 scheduled_tasks |= client->sources_to_notify; 654 client->sources_to_notify |= task; 655 656 if (scheduled_tasks == 0){ 657 scheduled_tasks_callback.callback = &bass_service_can_send_now; 658 scheduled_tasks_callback.context = (void*) client; 659 att_server_register_can_send_now_callback(&scheduled_tasks_callback, client->con_handle); 660 } 661 } 662 } 663 664 void broadcast_audio_scan_service_server_set_pa_sync_state(uint8_t source_index, le_audio_pa_sync_state_t sync_state){ 665 btstack_assert(source_index < bass_sources_num); 666 667 bass_server_source_t * source = &bass_sources[source_index]; 668 source->data.pa_sync_state = sync_state; 669 670 if (source->bass_receive_state_client_configuration != 0){ 671 bass_set_callback(source_index); 672 } 673 } 674 675 void broadcast_audio_scan_service_server_add_source(bass_source_data_t source_data, uint8_t * source_index){ 676 *source_index = bass_find_empty_or_last_used_source_index(); 677 if (*source_index == BASS_INVALID_SOURCE_INDEX){ 678 return; 679 } 680 bass_server_source_t * last_used_source = &bass_sources[*source_index]; 681 last_used_source->update_counter = bass_get_next_update_counter(); 682 last_used_source->in_use = true; 683 last_used_source->source_id = *source_index; 684 memcpy(&last_used_source->data, &source_data, sizeof(bass_source_data_t)); 685 } 686 687 void broadcast_audio_scan_service_server_deinit(void){ 688 } 689