xref: /btstack/src/le-audio/gatt-service/broadcast_audio_scan_service_server.c (revision 70cea164e31bdee503cabd4edbd04e729d6971df)
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