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_server_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_server_connection_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_server_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_server_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_server_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_server_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_server_find_empty_or_last_used_source(void){ 113 uint8_t last_used_source_index = bass_server_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_server_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_server_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_server_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_server_connection_t * bass_server_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_server_register_con_handle(hci_con_handle_t con_handle, uint16_t client_configuration){ 161 bass_server_connection_t * client = bass_server_find_client_for_con_handle(con_handle); 162 if (client == NULL){ 163 client = bass_server_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_server_source_emit_scan_stoped(hci_con_handle_t con_handle){ 173 btstack_assert(bass_server_event_callback != NULL); 174 175 uint8_t event[5]; 176 uint8_t pos = 0; 177 event[pos++] = HCI_EVENT_LEAUDIO_META; 178 event[pos++] = sizeof(event) - 2; 179 event[pos++] = LEAUDIO_SUBEVENT_BASS_SERVER_SCAN_STOPPED; 180 little_endian_store_16(event, pos, con_handle); 181 pos += 2; 182 (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 183 } 184 185 static void bass_server_source_emit_scan_started(hci_con_handle_t con_handle){ 186 btstack_assert(bass_server_event_callback != NULL); 187 188 uint8_t event[5]; 189 uint8_t pos = 0; 190 event[pos++] = HCI_EVENT_LEAUDIO_META; 191 event[pos++] = sizeof(event) - 2; 192 event[pos++] = LEAUDIO_SUBEVENT_BASS_SERVER_SCAN_STARTED; 193 little_endian_store_16(event, pos, con_handle); 194 pos += 2; 195 (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 196 } 197 198 199 static void bass_server_source_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_server_event_callback != NULL); 201 202 uint8_t event[7]; 203 uint8_t pos = 0; 204 event[pos++] = HCI_EVENT_LEAUDIO_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_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 212 } 213 214 static void bass_server_source_emit_source_added(hci_con_handle_t con_handle, bass_server_source_t * source){ 215 bass_server_source_emit_source_state_changed(LEAUDIO_SUBEVENT_BASS_SERVER_SOURCE_ADDED, con_handle, source->source_id, source->data.pa_sync); 216 } 217 218 static void bass_server_source_emit_source_modified(hci_con_handle_t con_handle, bass_server_source_t * source){ 219 bass_server_source_emit_source_state_changed(LEAUDIO_SUBEVENT_BASS_SERVER_SOURCE_MODIFIED, con_handle, source->source_id, source->data.pa_sync); 220 } 221 222 static void bass_server_source_emit_source_deleted(hci_con_handle_t con_handle, bass_server_source_t * source){ 223 bass_server_source_emit_source_state_changed(LEAUDIO_SUBEVENT_BASS_SERVER_SOURCE_DELETED, con_handle, source->source_id, LE_AUDIO_PA_SYNC_DO_NOT_SYNCHRONIZE_TO_PA); 224 } 225 226 static void bass_server_source_emit_broadcast_code(hci_con_handle_t con_handle, uint8_t source_id, const uint8_t * broadcast_code){ 227 btstack_assert(bass_server_event_callback != NULL); 228 229 uint8_t event[22]; 230 uint8_t pos = 0; 231 event[pos++] = HCI_EVENT_LEAUDIO_META; 232 event[pos++] = sizeof(event) - 2; 233 event[pos++] = LEAUDIO_SUBEVENT_BASS_SERVER_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_server_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 bass_server_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 = bass_server_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_server_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_server_source_remote_modify_source_buffer_valid(uint8_t *buffer, uint16_t buffer_size){ 300 if (buffer_size < 5){ 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_server_get_next_update_counter(); 313 source->in_use = true; 314 315 bass_util_source_data_parse(buffer, buffer_size, &source->data, false); 316 } 317 318 static bool bass_server_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_server_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_server_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_server_reset_client_long_write_buffer(bass_server_connection_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 bass_server_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("bass_server_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 bass_server_source_t * source = bass_server_find_receive_state_for_client_configuration_handle(attribute_handle); 358 if (source){ 359 source->bass_receive_state_client_configuration = little_endian_read_16(buffer, 0); 360 bass_server_register_con_handle(con_handle, source->bass_receive_state_client_configuration); 361 } 362 return 0; 363 } 364 365 bass_server_connection_t * connection = bass_server_find_client_for_con_handle(con_handle); 366 if (connection == NULL){ 367 return ATT_ERROR_WRITE_REQUEST_REJECTED; 368 } 369 370 uint16_t total_value_len = buffer_size + offset; 371 372 switch (transaction_mode){ 373 case ATT_TRANSACTION_MODE_NONE: 374 if (buffer_size > sizeof(connection->long_write_buffer)){ 375 bass_server_reset_client_long_write_buffer(connection); 376 return ATT_ERROR_WRITE_REQUEST_REJECTED; 377 } 378 memcpy(&connection->long_write_buffer[0], buffer, buffer_size); 379 connection->long_write_value_size = total_value_len; 380 break; 381 382 case ATT_TRANSACTION_MODE_ACTIVE: 383 if (total_value_len > sizeof(connection->long_write_buffer)){ 384 bass_server_reset_client_long_write_buffer(connection); 385 return ATT_ERROR_WRITE_REQUEST_REJECTED; 386 } 387 // allow overlapped and/or mixed order chunks 388 connection->long_write_attribute_handle = attribute_handle; 389 390 memcpy(&connection->long_write_buffer[offset], buffer, buffer_size); 391 if (total_value_len > connection->long_write_value_size){ 392 connection->long_write_value_size = total_value_len; 393 } 394 return 0; 395 396 case ATT_TRANSACTION_MODE_VALIDATE: 397 return 0; 398 399 case ATT_TRANSACTION_MODE_EXECUTE: 400 attribute_handle = connection->long_write_attribute_handle; 401 break; 402 403 default: 404 return 0; 405 } 406 407 if (attribute_handle == bass_audio_scan_control_point_handle){ 408 if (connection->long_write_value_size < 2){ 409 return ATT_ERROR_WRITE_REQUEST_REJECTED; 410 } 411 412 bass_opcode_t opcode = (bass_opcode_t)connection->long_write_buffer[0]; 413 uint8_t *remote_data = &connection->long_write_buffer[1]; 414 uint16_t remote_data_size = connection->long_write_value_size - 1; 415 416 bass_server_source_t * source; 417 uint8_t broadcast_code[16]; 418 switch (opcode){ 419 case BASS_OPCODE_REMOTE_SCAN_STOPPED: 420 if (remote_data_size != 1){ 421 return ATT_ERROR_WRITE_REQUEST_REJECTED; 422 } 423 bass_server_source_emit_scan_stoped(con_handle); 424 break; 425 426 case BASS_OPCODE_REMOTE_SCAN_STARTED: 427 if (remote_data_size != 1){ 428 return ATT_ERROR_WRITE_REQUEST_REJECTED; 429 } 430 bass_server_source_emit_scan_started(con_handle); 431 break; 432 433 case BASS_OPCODE_ADD_SOURCE: 434 if (!bass_util_source_buffer_in_valid_range(remote_data, remote_data_size)){ 435 return ATT_ERROR_WRITE_REQUEST_REJECTED; 436 } 437 source = bass_server_find_empty_or_last_used_source(); 438 btstack_assert(source != NULL); 439 log_info("add source %d", source->source_id); 440 bass_server_add_source_from_buffer(remote_data, remote_data_size, source); 441 bass_server_source_emit_source_added(con_handle, source); 442 // server needs to trigger notification 443 break; 444 445 case BASS_OPCODE_MODIFY_SOURCE: 446 if (!bass_server_source_remote_modify_source_buffer_valid(remote_data, remote_data_size)){ 447 return ATT_ERROR_WRITE_REQUEST_REJECTED; 448 } 449 450 source = bass_server_find_source_for_source_id(remote_data[0]); 451 if (source == NULL){ 452 return BASS_ERROR_CODE_INVALID_SOURCE_ID; 453 } 454 bass_util_pa_info_and_subgroups_parse(remote_data + 1, remote_data_size - 1, &source->data, false); 455 bass_server_source_emit_source_modified(con_handle, source); 456 // server needs to trigger notification 457 break; 458 459 case BASS_OPCODE_SET_BROADCAST_CODE: 460 if (remote_data_size != 17){ 461 return ATT_ERROR_WRITE_REQUEST_REJECTED; 462 } 463 464 source = bass_server_find_source_for_source_id(remote_data[0]); 465 if (source == NULL){ 466 return BASS_ERROR_CODE_INVALID_SOURCE_ID; 467 } 468 reverse_128(&remote_data[1], broadcast_code); 469 bass_server_source_emit_broadcast_code(con_handle, source->source_id, broadcast_code); 470 break; 471 472 case BASS_OPCODE_REMOVE_SOURCE: 473 if (remote_data_size != 1){ 474 return ATT_ERROR_WRITE_REQUEST_REJECTED; 475 } 476 source = bass_server_find_source_for_source_id(remote_data[0]); 477 if (source == NULL){ 478 return BASS_ERROR_CODE_INVALID_SOURCE_ID; 479 } 480 481 if (bass_server_pa_synchronized(source)){ 482 log_info("remove source %d rejected, PA synchronised", source->source_id); 483 return 0; 484 } 485 486 if (bass_server_bis_synchronized(source)){ 487 log_info("remove source %d rejected, BIS synchronised", source->source_id); 488 return 0; 489 } 490 491 bass_server_reset_source(source); 492 broadcast_audio_scan_service_server_set_pa_sync_state(source->source_id, LE_AUDIO_PA_SYNC_STATE_NOT_SYNCHRONIZED_TO_PA); 493 bass_server_source_emit_source_deleted(con_handle, source); 494 break; 495 496 default: 497 bass_server_reset_client_long_write_buffer(connection); 498 return BASS_ERROR_CODE_OPCODE_NOT_SUPPORTED; 499 } 500 bass_server_reset_client_long_write_buffer(connection); 501 } 502 return 0; 503 } 504 505 static void bass_server_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 506 UNUSED(channel); 507 UNUSED(packet); 508 UNUSED(size); 509 510 if (packet_type != HCI_EVENT_PACKET){ 511 return; 512 } 513 514 hci_con_handle_t con_handle; 515 bass_server_connection_t * connection; 516 517 switch (hci_event_packet_get_type(packet)) { 518 case HCI_EVENT_DISCONNECTION_COMPLETE: 519 con_handle = hci_event_disconnection_complete_get_connection_handle(packet); 520 521 connection = bass_server_find_client_for_con_handle(con_handle); 522 if (connection == NULL){ 523 break; 524 } 525 526 memset(connection, 0, sizeof(bass_server_connection_t)); 527 connection->con_handle = HCI_CON_HANDLE_INVALID; 528 break; 529 default: 530 break; 531 } 532 } 533 534 void broadcast_audio_scan_service_server_init(const uint8_t sources_num, bass_server_source_t * sources, const uint8_t clients_num, bass_server_connection_t * clients){ 535 // get service handle range 536 btstack_assert(sources_num != 0); 537 btstack_assert(clients_num != 0); 538 539 uint16_t start_handle = 0; 540 uint16_t end_handle = 0xffff; 541 bool service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE, &start_handle, &end_handle); 542 btstack_assert(service_found); 543 544 UNUSED(service_found); 545 546 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); 547 bass_sources_num = 0; 548 bass_logic_time = 0; 549 bass_sources = sources; 550 551 #ifdef ENABLE_TESTING_SUPPORT 552 printf("BASS 0x%02x - 0x%02x \n", start_handle, end_handle); 553 #endif 554 uint16_t start_chr_handle = start_handle; 555 while ( (start_chr_handle < end_handle) && (bass_sources_num < sources_num )) { 556 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); 557 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); 558 559 if (chr_value_handle == 0){ 560 break; 561 } 562 bass_server_source_t * source = &bass_sources[bass_sources_num]; 563 bass_server_reset_source(source); 564 565 source->source_id = bass_sources_num; 566 source->update_counter = bass_server_get_next_update_counter(); 567 source->bass_receive_state_client_configuration = 0; 568 569 source->bass_receive_state_handle = chr_value_handle; 570 source->bass_receive_state_client_configuration_handle = chr_client_configuration_handle; 571 572 #ifdef ENABLE_TESTING_SUPPORT 573 printf(" bass_receive_state_%d 0x%02x \n", bass_sources_num, source->bass_receive_state_handle); 574 printf(" bass_receive_state_%d CCC 0x%02x \n", bass_sources_num, source->bass_receive_state_client_configuration_handle); 575 #endif 576 577 start_chr_handle = chr_client_configuration_handle + 1; 578 bass_sources_num++; 579 } 580 581 bass_clients_num = clients_num; 582 bass_clients = clients; 583 memset(bass_clients, 0, sizeof(bass_server_connection_t) * bass_clients_num); 584 uint8_t i; 585 for (i = 0; i < bass_clients_num; i++){ 586 bass_clients[i].con_handle = HCI_CON_HANDLE_INVALID; 587 } 588 589 log_info("Found BASS service 0x%02x-0x%02x (num sources %d)", start_handle, end_handle, bass_sources_num); 590 591 // register service with ATT Server 592 broadcast_audio_scan_service.start_handle = start_handle; 593 broadcast_audio_scan_service.end_handle = end_handle; 594 broadcast_audio_scan_service.read_callback = &bass_server_read_callback; 595 broadcast_audio_scan_service.write_callback = &bass_server_write_callback; 596 broadcast_audio_scan_service.packet_handler = bass_server_packet_handler; 597 att_server_register_service_handler(&broadcast_audio_scan_service); 598 } 599 600 void broadcast_audio_scan_service_server_register_packet_handler(btstack_packet_handler_t packet_handler){ 601 btstack_assert(packet_handler != NULL); 602 bass_server_event_callback = packet_handler; 603 } 604 605 static void bass_service_can_send_now(void * context){ 606 bass_server_connection_t * client = (bass_server_connection_t *) context; 607 btstack_assert(client != NULL); 608 609 uint8_t source_index; 610 for (source_index = 0; source_index < bass_sources_num; source_index++){ 611 uint8_t task = (1 << source_index); 612 if ((client->sources_to_notify & task) != 0){ 613 client->sources_to_notify &= ~task; 614 uint8_t buffer[BASS_MAX_NOTIFY_BUFFER_SIZE]; 615 uint16_t bytes_copied = bass_server_copy_source_to_buffer(&bass_sources[source_index], 0, buffer, sizeof(buffer)); 616 att_server_notify(client->con_handle, bass_sources[source_index].bass_receive_state_handle, &buffer[0], bytes_copied); 617 return; 618 } 619 } 620 621 uint8_t i; 622 for (i = 0; i < bass_clients_num; i++){ 623 client = &bass_clients[i]; 624 625 if (client->sources_to_notify != 0){ 626 scheduled_tasks_callback.callback = &bass_service_can_send_now; 627 scheduled_tasks_callback.context = (void*) client; 628 att_server_register_can_send_now_callback(&scheduled_tasks_callback, client->con_handle); 629 return; 630 } 631 } 632 } 633 634 static void bass_server_set_callback(uint8_t source_index){ 635 // there is only one type of task: notify on source state change 636 // as task we register which source is changed, and the change will be propagated to all clients 637 uint8_t i; 638 uint8_t task = (1 << source_index); 639 640 uint8_t scheduled_tasks = 0; 641 642 for (i = 0; i < bass_clients_num; i++){ 643 bass_server_connection_t * connection = &bass_clients[i]; 644 645 if (connection->con_handle == HCI_CON_HANDLE_INVALID){ 646 connection->sources_to_notify &= ~task; 647 return; 648 } 649 650 scheduled_tasks |= connection->sources_to_notify; 651 connection->sources_to_notify |= task; 652 653 if (scheduled_tasks == 0){ 654 scheduled_tasks_callback.callback = &bass_service_can_send_now; 655 scheduled_tasks_callback.context = (void*) connection; 656 att_server_register_can_send_now_callback(&scheduled_tasks_callback, connection->con_handle); 657 } 658 } 659 } 660 661 void broadcast_audio_scan_service_server_set_pa_sync_state(uint8_t source_index, le_audio_pa_sync_state_t sync_state){ 662 btstack_assert(source_index < bass_sources_num); 663 664 bass_server_source_t * source = &bass_sources[source_index]; 665 source->data.pa_sync_state = sync_state; 666 667 if (source->bass_receive_state_client_configuration != 0){ 668 bass_server_set_callback(source_index); 669 } 670 } 671 672 void broadcast_audio_scan_service_server_add_source(const bass_source_data_t *source_data, uint8_t * source_index){ 673 *source_index = bass_server_find_empty_or_last_used_source_index(); 674 if (*source_index == BASS_INVALID_SOURCE_INDEX){ 675 return; 676 } 677 bass_server_source_t * last_used_source = &bass_sources[*source_index]; 678 last_used_source->update_counter = bass_server_get_next_update_counter(); 679 last_used_source->in_use = true; 680 last_used_source->source_id = *source_index; 681 memcpy(&last_used_source->data, source_data, sizeof(bass_source_data_t)); 682 } 683 684 void broadcast_audio_scan_service_server_deinit(void){ 685 bass_server_event_callback = NULL; 686 } 687