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