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_copy_source_common_data_to_buffer(&source->data, &source_offset, buffer_offset, buffer, buffer_size); 258 259 field_data[0] = (uint8_t)source->data.pa_sync_state; 260 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 261 buffer_offset); 262 source_offset++; 263 264 field_data[0] = (uint8_t)source->big_encryption; 265 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size, 266 buffer_offset); 267 source_offset++; 268 269 if (source->big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){ 270 reverse_128(source->bad_code, &field_data[0]); 271 stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 16, source_offset, buffer, buffer_size, 272 buffer_offset); 273 source_offset += 16; 274 } 275 276 stored_bytes += bass_util_store_source_subgroups_into_buffer(&source->data, true, &source_offset, buffer_offset, 277 buffer, 278 buffer_size); 279 return stored_bytes; 280 } 281 282 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){ 283 UNUSED(con_handle); 284 285 bass_server_source_t * source; 286 source = bass_find_receive_state_for_value_handle(attribute_handle); 287 if (source){ 288 return bass_server_copy_source_to_buffer(source, offset, buffer, buffer_size); 289 } 290 291 source = bass_find_receive_state_for_client_configuration_handle(attribute_handle); 292 if (source){ 293 return att_read_callback_handle_little_endian_16(source->bass_receive_state_client_configuration, offset, buffer, buffer_size); 294 } 295 296 return 0; 297 } 298 299 static bool bass_source_remote_modify_source_buffer_valid(uint8_t *buffer, uint16_t buffer_size){ 300 if (buffer_size < 10){ 301 log_info("Modify Source opcode, buffer too small"); 302 return false; 303 } 304 305 uint8_t pos = 1; // source_id 306 return bass_util_pa_sync_state_and_subgroups_in_valid_range(buffer+pos, buffer_size-pos); 307 } 308 309 static void bass_server_add_source_from_buffer(uint8_t *buffer, uint16_t buffer_size, bass_server_source_t * source){ 310 UNUSED(buffer_size); 311 312 source->update_counter = bass_get_next_update_counter(); 313 source->in_use = true; 314 315 bass_util_get_source_from_buffer(buffer, buffer_size, &source->data, false); 316 } 317 318 static bool bass_pa_synchronized(bass_server_source_t * source){ 319 return source->data.pa_sync_state == LE_AUDIO_PA_SYNC_STATE_SYNCHRONIZED_TO_PA; 320 } 321 322 323 static bool bass_bis_synchronized(bass_server_source_t * source){ 324 uint8_t i; 325 for (i = 0; i < source->data.subgroups_num; i++){ 326 if ((source->data.subgroups[i].bis_sync_state > 0) && (source->data.subgroups[i].bis_sync_state < 0xFFFFFFFF)){ 327 return true; 328 } 329 } 330 return false; 331 } 332 333 334 static void bass_reset_source(bass_server_source_t * source){ 335 source->in_use = false; 336 source->data.address_type = BD_ADDR_TYPE_LE_PUBLIC; 337 memset(source->data.address, 0, sizeof(source->data.address)); 338 source->data.adv_sid = 0; 339 source->data.broadcast_id = 0; 340 source->data.pa_sync = LE_AUDIO_PA_SYNC_DO_NOT_SYNCHRONIZE_TO_PA; 341 source->data.pa_sync_state = LE_AUDIO_PA_SYNC_STATE_NOT_SYNCHRONIZED_TO_PA; 342 source->big_encryption = LE_AUDIO_BIG_ENCRYPTION_NOT_ENCRYPTED; 343 memset(source->bad_code, 0, sizeof(source->bad_code)); 344 source->data.pa_interval = 0; 345 source->data.subgroups_num = 0; 346 memset(source->data.subgroups, 0, sizeof(source->data.subgroups)); 347 } 348 349 static void bass_reset_client_long_write_buffer(bass_remote_client_t * client){ 350 memset(client->long_write_buffer, 0, sizeof(client->long_write_buffer)); 351 client->long_write_value_size = 0; 352 } 353 354 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){ 355 // printf("broadcast_audio_scan_service_write_callback con_handle 0x%02x, attr_handle 0x%02x \n", con_handle, attribute_handle); 356 if (attribute_handle != 0 && attribute_handle != bass_audio_scan_control_point_handle){ 357 358 bass_server_source_t * source = bass_find_receive_state_for_client_configuration_handle(attribute_handle); 359 if (source){ 360 source->bass_receive_state_client_configuration = little_endian_read_16(buffer, 0); 361 bass_register_con_handle(con_handle, source->bass_receive_state_client_configuration); 362 } 363 return 0; 364 } 365 366 367 bass_remote_client_t * client = bass_find_client_for_con_handle(con_handle); 368 if (client == NULL){ 369 return ATT_ERROR_WRITE_REQUEST_REJECTED; 370 } 371 372 uint16_t total_value_len = buffer_size + offset; 373 374 switch (transaction_mode){ 375 case ATT_TRANSACTION_MODE_NONE: 376 if (buffer_size > sizeof(client->long_write_buffer)){ 377 bass_reset_client_long_write_buffer(client); 378 return ATT_ERROR_WRITE_REQUEST_REJECTED; 379 } 380 memcpy(&client->long_write_buffer[0], buffer, buffer_size); 381 client->long_write_value_size = total_value_len; 382 break; 383 384 case ATT_TRANSACTION_MODE_ACTIVE: 385 if (total_value_len > sizeof(client->long_write_buffer)){ 386 bass_reset_client_long_write_buffer(client); 387 return ATT_ERROR_WRITE_REQUEST_REJECTED; 388 } 389 // allow overlapped and/or mixed order chunks 390 client->long_write_attribute_handle = attribute_handle; 391 392 memcpy(&client->long_write_buffer[offset], buffer, buffer_size); 393 if (total_value_len > client->long_write_value_size){ 394 client->long_write_value_size = total_value_len; 395 } 396 return 0; 397 398 case ATT_TRANSACTION_MODE_VALIDATE: 399 return 0; 400 401 case ATT_TRANSACTION_MODE_EXECUTE: 402 attribute_handle = client->long_write_attribute_handle; 403 break; 404 405 default: 406 return 0; 407 } 408 409 if (attribute_handle == bass_audio_scan_control_point_handle){ 410 if (client->long_write_value_size < 2){ 411 return ATT_ERROR_WRITE_REQUEST_REJECTED; 412 } 413 414 bass_opcode_t opcode = (bass_opcode_t)client->long_write_buffer[0]; 415 uint8_t *remote_data = &client->long_write_buffer[1]; 416 uint16_t remote_data_size = client->long_write_value_size - 1; 417 418 bass_server_source_t * source; 419 uint8_t broadcast_code[16]; 420 switch (opcode){ 421 case BASS_OPCODE_REMOTE_SCAN_STOPPED: 422 if (remote_data_size != 1){ 423 return ATT_ERROR_WRITE_REQUEST_REJECTED; 424 } 425 bass_emit_remote_scan_stoped(con_handle); 426 break; 427 428 case BASS_OPCODE_REMOTE_SCAN_STARTED: 429 if (remote_data_size != 1){ 430 return ATT_ERROR_WRITE_REQUEST_REJECTED; 431 } 432 bass_emit_remote_scan_started(con_handle); 433 break; 434 435 case BASS_OPCODE_ADD_SOURCE: 436 if (!bass_util_add_source_buffer_in_valid_range(remote_data, remote_data_size)){ 437 return ATT_ERROR_WRITE_REQUEST_REJECTED; 438 } 439 source = bass_find_empty_or_last_used_source(); 440 btstack_assert(source != NULL); 441 log_info("add source %d", source->source_id); 442 bass_server_add_source_from_buffer(remote_data, remote_data_size, source); 443 bass_emit_source_added(con_handle, source); 444 // server needs to trigger notification 445 break; 446 447 case BASS_OPCODE_MODIFY_SOURCE: 448 if (!bass_source_remote_modify_source_buffer_valid(remote_data, remote_data_size)){ 449 return ATT_ERROR_WRITE_REQUEST_REJECTED; 450 } 451 452 source = bass_find_source_for_source_id(remote_data[0]); 453 if (source == NULL){ 454 return BASS_ERROR_CODE_INVALID_SOURCE_ID; 455 } 456 bass_util_get_pa_info_and_subgroups_from_buffer(remote_data + 1, remote_data_size - 1, &source->data,false); 457 bass_emit_source_modified(con_handle, source); 458 // server needs to trigger notification 459 break; 460 461 case BASS_OPCODE_SET_BROADCAST_CODE: 462 if (remote_data_size != 17){ 463 return ATT_ERROR_WRITE_REQUEST_REJECTED; 464 } 465 466 source = bass_find_source_for_source_id(remote_data[0]); 467 if (source == NULL){ 468 return BASS_ERROR_CODE_INVALID_SOURCE_ID; 469 } 470 reverse_128(&remote_data[1], broadcast_code); 471 bass_emit_broadcast_code(con_handle, source->source_id, broadcast_code); 472 break; 473 474 case BASS_OPCODE_REMOVE_SOURCE: 475 if (remote_data_size != 1){ 476 return ATT_ERROR_WRITE_REQUEST_REJECTED; 477 } 478 source = bass_find_source_for_source_id(remote_data[0]); 479 if (source == NULL){ 480 return BASS_ERROR_CODE_INVALID_SOURCE_ID; 481 } 482 483 if (bass_pa_synchronized(source)){ 484 log_info("remove source %d rejected, PA synchronised", source->source_id); 485 return 0; 486 } 487 488 if (bass_bis_synchronized(source)){ 489 log_info("remove source %d rejected, BIS synchronised", source->source_id); 490 return 0; 491 } 492 493 bass_reset_source(source); 494 broadcast_audio_scan_service_server_set_pa_sync_state(source->source_id, LE_AUDIO_PA_SYNC_STATE_NOT_SYNCHRONIZED_TO_PA); 495 bass_emit_source_deleted(con_handle, source); 496 break; 497 498 default: 499 bass_reset_client_long_write_buffer(client); 500 return BASS_ERROR_CODE_OPCODE_NOT_SUPPORTED; 501 } 502 bass_reset_client_long_write_buffer(client); 503 } 504 return 0; 505 } 506 507 static void broadcast_audio_scan_service_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 508 UNUSED(channel); 509 UNUSED(packet); 510 UNUSED(size); 511 512 if (packet_type != HCI_EVENT_PACKET){ 513 return; 514 } 515 516 hci_con_handle_t con_handle; 517 bass_remote_client_t * client; 518 519 switch (hci_event_packet_get_type(packet)) { 520 case HCI_EVENT_DISCONNECTION_COMPLETE: 521 con_handle = hci_event_disconnection_complete_get_connection_handle(packet); 522 523 client = bass_find_client_for_con_handle(con_handle); 524 if (client == NULL){ 525 break; 526 } 527 528 memset(client, 0, sizeof(bass_remote_client_t)); 529 client->con_handle = HCI_CON_HANDLE_INVALID; 530 break; 531 default: 532 break; 533 } 534 } 535 536 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){ 537 // get service handle range 538 btstack_assert(sources_num != 0); 539 btstack_assert(clients_num != 0); 540 541 uint16_t start_handle = 0; 542 uint16_t end_handle = 0xffff; 543 bool service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE, &start_handle, &end_handle); 544 btstack_assert(service_found); 545 546 UNUSED(service_found); 547 548 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); 549 bass_sources_num = 0; 550 bass_logic_time = 0; 551 bass_sources = sources; 552 553 #ifdef ENABLE_TESTING_SUPPORT 554 printf("BASS 0x%02x - 0x%02x \n", start_handle, end_handle); 555 #endif 556 uint16_t start_chr_handle = start_handle; 557 while ( (start_chr_handle < end_handle) && (bass_sources_num < sources_num )) { 558 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); 559 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); 560 561 if (chr_value_handle == 0){ 562 break; 563 } 564 bass_server_source_t * source = &bass_sources[bass_sources_num]; 565 bass_reset_source(source); 566 567 source->source_id = bass_sources_num; 568 source->update_counter = bass_get_next_update_counter(); 569 source->bass_receive_state_client_configuration = 0; 570 571 source->bass_receive_state_handle = chr_value_handle; 572 source->bass_receive_state_client_configuration_handle = chr_client_configuration_handle; 573 574 #ifdef ENABLE_TESTING_SUPPORT 575 printf(" bass_receive_state_%d 0x%02x \n", bass_sources_num, source->bass_receive_state_handle); 576 printf(" bass_receive_state_%d CCC 0x%02x \n", bass_sources_num, source->bass_receive_state_client_configuration_handle); 577 #endif 578 579 start_chr_handle = chr_client_configuration_handle + 1; 580 bass_sources_num++; 581 } 582 583 bass_clients_num = clients_num; 584 bass_clients = clients; 585 memset(bass_clients, 0, sizeof(bass_remote_client_t) * bass_clients_num); 586 uint8_t i; 587 for (i = 0; i < bass_clients_num; i++){ 588 bass_clients[i].con_handle = HCI_CON_HANDLE_INVALID; 589 } 590 591 log_info("Found BASS service 0x%02x-0x%02x (num sources %d)", start_handle, end_handle, bass_sources_num); 592 593 // register service with ATT Server 594 broadcast_audio_scan_service.start_handle = start_handle; 595 broadcast_audio_scan_service.end_handle = end_handle; 596 broadcast_audio_scan_service.read_callback = &broadcast_audio_scan_service_read_callback; 597 broadcast_audio_scan_service.write_callback = &broadcast_audio_scan_service_write_callback; 598 broadcast_audio_scan_service.packet_handler = broadcast_audio_scan_service_packet_handler; 599 att_server_register_service_handler(&broadcast_audio_scan_service); 600 } 601 602 void broadcast_audio_scan_service_server_register_packet_handler(btstack_packet_handler_t callback){ 603 btstack_assert(callback != NULL); 604 bass_event_callback = callback; 605 } 606 607 static void bass_service_can_send_now(void * context){ 608 bass_remote_client_t * client = (bass_remote_client_t *) context; 609 btstack_assert(client != NULL); 610 611 uint8_t source_index; 612 for (source_index = 0; source_index < bass_sources_num; source_index++){ 613 uint8_t task = (1 << source_index); 614 if ((client->sources_to_notify & task) != 0){ 615 client->sources_to_notify &= ~task; 616 uint8_t buffer[BASS_MAX_NOTIFY_BUFFER_SIZE]; 617 uint16_t bytes_copied = bass_server_copy_source_to_buffer(&bass_sources[source_index], 0, buffer, sizeof(buffer)); 618 att_server_notify(client->con_handle, bass_sources[source_index].bass_receive_state_handle, &buffer[0], bytes_copied); 619 return; 620 } 621 } 622 623 uint8_t i; 624 for (i = 0; i < bass_clients_num; i++){ 625 client = &bass_clients[i]; 626 627 if (client->sources_to_notify != 0){ 628 scheduled_tasks_callback.callback = &bass_service_can_send_now; 629 scheduled_tasks_callback.context = (void*) client; 630 att_server_register_can_send_now_callback(&scheduled_tasks_callback, client->con_handle); 631 return; 632 } 633 } 634 } 635 636 static void bass_set_callback(uint8_t source_index){ 637 // there is only one type of task: notify on source state change 638 // as task we register which source is changed, and the change will be propagated to all clients 639 uint8_t i; 640 uint8_t task = (1 << source_index); 641 642 uint8_t scheduled_tasks = 0; 643 644 for (i = 0; i < bass_clients_num; i++){ 645 bass_remote_client_t * client = &bass_clients[i]; 646 647 if (client->con_handle == HCI_CON_HANDLE_INVALID){ 648 client->sources_to_notify &= ~task; 649 return; 650 } 651 652 scheduled_tasks |= client->sources_to_notify; 653 client->sources_to_notify |= task; 654 655 if (scheduled_tasks == 0){ 656 scheduled_tasks_callback.callback = &bass_service_can_send_now; 657 scheduled_tasks_callback.context = (void*) client; 658 att_server_register_can_send_now_callback(&scheduled_tasks_callback, client->con_handle); 659 } 660 } 661 } 662 663 void broadcast_audio_scan_service_server_set_pa_sync_state(uint8_t source_index, le_audio_pa_sync_state_t sync_state){ 664 btstack_assert(source_index < bass_sources_num); 665 666 bass_server_source_t * source = &bass_sources[source_index]; 667 source->data.pa_sync_state = sync_state; 668 669 if (source->bass_receive_state_client_configuration != 0){ 670 bass_set_callback(source_index); 671 } 672 } 673 674 void broadcast_audio_scan_service_server_add_source(bass_source_data_t source_data, uint8_t * source_index){ 675 *source_index = bass_find_empty_or_last_used_source_index(); 676 if (*source_index == BASS_INVALID_SOURCE_INDEX){ 677 return; 678 } 679 bass_server_source_t * last_used_source = &bass_sources[*source_index]; 680 last_used_source->update_counter = bass_get_next_update_counter(); 681 last_used_source->in_use = true; 682 last_used_source->source_id = *source_index; 683 memcpy(&last_used_source->data, &source_data, sizeof(bass_source_data_t)); 684 } 685 686 void broadcast_audio_scan_service_server_deinit(void){ 687 } 688