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
bass_server_get_next_update_counter(void)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
bass_server_counter_delta(uint8_t counter_a,uint8_t counter_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
bass_server_find_empty_or_last_used_source_index(void)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
bass_server_find_empty_or_last_used_source(void)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
bass_server_find_receive_state_for_value_handle(uint16_t attribute_handle)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
bass_server_find_receive_state_for_client_configuration_handle(uint16_t attribute_handle)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
bass_server_find_source_for_source_id(uint8_t source_id)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
bass_server_find_client_for_con_handle(hci_con_handle_t con_handle)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
bass_server_register_con_handle(hci_con_handle_t con_handle,uint16_t client_configuration)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
bass_server_source_emit_scan_stoped(hci_con_handle_t con_handle)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
bass_server_source_emit_scan_started(hci_con_handle_t con_handle)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
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)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
bass_server_source_emit_source_added(hci_con_handle_t con_handle,bass_server_source_t * source)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
bass_server_source_emit_source_modified(hci_con_handle_t con_handle,bass_server_source_t * source)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
bass_server_source_emit_source_deleted(hci_con_handle_t con_handle,bass_server_source_t * source)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
bass_server_source_emit_broadcast_code(hci_con_handle_t con_handle,uint8_t source_id,const uint8_t * broadcast_code)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
bass_server_copy_source_to_buffer(bass_server_source_t * source,uint16_t buffer_offset,uint8_t * buffer,uint16_t buffer_size)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
bass_server_read_callback(hci_con_handle_t con_handle,uint16_t attribute_handle,uint16_t offset,uint8_t * buffer,uint16_t buffer_size)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
bass_server_source_remote_modify_source_buffer_valid(uint8_t * buffer,uint16_t buffer_size)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
bass_server_add_source_from_buffer(uint8_t * buffer,uint16_t buffer_size,bass_server_source_t * source)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
bass_server_pa_synchronized(bass_server_source_t * source)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
bass_server_bis_synchronized(bass_server_source_t * source)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
bass_server_reset_source(bass_server_source_t * source)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
bass_server_reset_client_long_write_buffer(bass_server_connection_t * client)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
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)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
bass_server_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)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
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)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
broadcast_audio_scan_service_server_register_packet_handler(btstack_packet_handler_t packet_handler)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
bass_service_can_send_now(void * context)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
bass_server_set_callback(uint8_t source_index)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
broadcast_audio_scan_service_server_set_pa_sync_state(uint8_t source_index,le_audio_pa_sync_state_t sync_state)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
broadcast_audio_scan_service_server_add_source(const bass_source_data_t * source_data,uint8_t * source_index)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
broadcast_audio_scan_service_server_deinit(void)684 void broadcast_audio_scan_service_server_deinit(void){
685 bass_server_event_callback = NULL;
686 }
687