xref: /btstack/src/le-audio/gatt-service/broadcast_audio_scan_service_client.c (revision ae3042838ecab39355f8220511b931dbf8f87c8e)
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_client.c"
39 
40 #include "ble/att_db.h"
41 #include "ble/att_server.h"
42 #include "bluetooth_gatt.h"
43 #include "btstack_debug.h"
44 #include "btstack_defines.h"
45 #include "btstack_event.h"
46 #include "btstack_util.h"
47 #include "btstack_memory.h"
48 
49 #include "le-audio/le_audio_util.h"
50 #include "le-audio/gatt-service/broadcast_audio_scan_service_client.h"
51 
52 #ifdef ENABLE_TESTING_SUPPORT
53 #include <stdio.h>
54 #endif
55 
56 static btstack_linked_list_t bass_client_connections;
57 
58 static uint16_t bass_client_cid_counter = 0;
59 static btstack_packet_handler_t bass_client_event_callback;
60 
61 static void bass_client_handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
62 
63 static uint16_t bass_client_get_next_cid(void){
64     bass_client_cid_counter = btstack_next_cid_ignoring_zero(bass_client_cid_counter);
65     return bass_client_cid_counter;
66 }
67 
68 static void bass_client_finalize_connection(bass_client_connection_t * connection){
69     btstack_linked_list_remove(&bass_client_connections, (btstack_linked_item_t*) connection);
70 }
71 
72 static bass_client_connection_t * bass_client_get_connection_for_con_handle(hci_con_handle_t con_handle){
73     btstack_linked_list_iterator_t it;
74     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &bass_client_connections);
75     while (btstack_linked_list_iterator_has_next(&it)){
76         bass_client_connection_t * connection = (bass_client_connection_t *)btstack_linked_list_iterator_next(&it);
77         if (connection->con_handle != con_handle) continue;
78         return connection;
79     }
80     return NULL;
81 }
82 
83 static bass_client_connection_t * bass_client_get_connection_for_cid(uint16_t bass_cid){
84     btstack_linked_list_iterator_t it;
85     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &bass_client_connections);
86     while (btstack_linked_list_iterator_has_next(&it)){
87         bass_client_connection_t * connection = (bass_client_connection_t *)btstack_linked_list_iterator_next(&it);
88         if (connection->cid != bass_cid) continue;
89         return connection;
90     }
91     return NULL;
92 }
93 
94 static bass_client_source_t * bass_client_get_receive_state_for_value_handle(bass_client_connection_t * connection, uint16_t value_handle){
95     uint8_t i;
96     for (i = 0; i < connection->receive_states_instances_num; i++){
97         if (connection->receive_states[i].receive_state_value_handle == value_handle){
98             return &connection->receive_states[i];
99         }
100     }
101     return NULL;
102 }
103 
104 static bass_client_source_t * bass_client_get_source_for_source_id(bass_client_connection_t * connection, uint8_t source_id){
105     uint8_t i;
106     for (i = 0; i < connection->receive_states_instances_num; i++){
107         if (connection->receive_states[i].source_id == source_id){
108             return &connection->receive_states[i];
109         }
110     }
111     return NULL;
112 }
113 
114 static void bass_client_reset_source(bass_client_source_t * source){
115     if (source == NULL){
116         return;
117     }
118     source->source_id = BASS_INVALID_SOURCE_INDEX;
119     source->in_use = false;
120     memset(&source->data, 0, sizeof(bass_source_data_t));
121 }
122 
123 static void bass_client_emit_connection_established(bass_client_connection_t * connection, uint8_t status){
124     btstack_assert(bass_client_event_callback != NULL);
125 
126     uint8_t event[8];
127     uint16_t pos = 0;
128     event[pos++] = HCI_EVENT_LEAUDIO_META;
129     event[pos++] = sizeof(event) - 2;
130     event[pos++] = LEAUDIO_SUBEVENT_BASS_CLIENT_CONNECTED;
131     little_endian_store_16(event, pos, connection->con_handle);
132     pos += 2;
133     little_endian_store_16(event, pos, connection->cid);
134     pos += 2;
135     event[pos++] = status;
136     (*bass_client_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
137 }
138 
139 static void bass_client_emit_scan_operation_complete(bass_client_connection_t * connection, uint8_t status, bass_opcode_t opcode){
140     btstack_assert(bass_client_event_callback != NULL);
141     uint8_t event[7];
142     uint16_t pos = 0;
143     event[pos++] = HCI_EVENT_LEAUDIO_META;
144     event[pos++] = sizeof(event) - 2;
145     event[pos++] = LEAUDIO_SUBEVENT_BASS_CLIENT_SCAN_OPERATION_COMPLETE;
146     little_endian_store_16(event, pos, connection->cid);
147     pos += 2;
148     event[pos++] = status;
149     event[pos++] = (uint8_t)opcode;
150     (*bass_client_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
151 }
152 
153 static void bass_client_emit_source_operation_complete(bass_client_connection_t * connection, uint8_t status, bass_opcode_t opcode, uint8_t source_id){
154     btstack_assert(bass_client_event_callback != NULL);
155     uint8_t event[8];
156     uint16_t pos = 0;
157     event[pos++] = HCI_EVENT_LEAUDIO_META;
158     event[pos++] = sizeof(event) - 2;
159     event[pos++] = LEAUDIO_SUBEVENT_BASS_CLIENT_SOURCE_OPERATION_COMPLETE;
160     little_endian_store_16(event, pos, connection->cid);
161     pos += 2;
162     event[pos++] = status;
163     event[pos++] = (uint8_t)opcode;
164     event[pos++] = source_id;
165     (*bass_client_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
166 }
167 
168 static void bass_client_emit_receive_state(bass_client_connection_t * connection, uint8_t source_id){
169     btstack_assert(bass_client_event_callback != NULL);
170     uint8_t pos = 0;
171     uint8_t event[7];
172     event[pos++] = HCI_EVENT_LEAUDIO_META;
173     event[pos++] = sizeof(event) - 2;
174     event[pos++] = LEAUDIO_SUBEVENT_BASS_CLIENT_NOTIFICATION_COMPLETE;
175     little_endian_store_16(event, pos, connection->cid);
176     pos += 2;
177     event[pos++] = source_id;
178     (*bass_client_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
179 }
180 
181 static bool bass_client_remote_broadcast_receive_state_buffer_valid(uint8_t *buffer, uint16_t buffer_size){
182     // minimal with zero subgroups
183     if (buffer_size < 15){
184         return false;
185     }
186 
187     uint16_t pos = 0;
188 
189     // source_id
190     pos++;
191 
192     // addr type
193     uint8_t adv_type = buffer[pos++];
194     if (adv_type > (uint8_t)BD_ADDR_TYPE_LE_RANDOM){
195         log_info("Unexpected adv_type 0x%02X", adv_type);
196         return false;
197     }
198 
199     // address
200     pos += 6;
201 
202     // advertising_sid Range: 0x00-0x0F
203     uint8_t advertising_sid = buffer[pos++];
204     if (advertising_sid > 0x0F){
205         log_info("Advertising sid out of range 0x%02X", advertising_sid);
206         return false;
207     }
208 
209     // broadcast_id
210     pos += 3;
211 
212     // pa_sync_state
213     uint8_t pa_sync_state = buffer[pos++];
214     if (pa_sync_state >= (uint8_t)LE_AUDIO_PA_SYNC_STATE_RFU){
215         log_info("Unexpected pa_sync_state 0x%02X", pa_sync_state);
216         return false;
217     }
218 
219     // big_encryption
220     le_audio_big_encryption_t big_encryption = (le_audio_big_encryption_t) buffer[pos++];
221     if (big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){
222         // Bad Code
223         pos += 16;
224     }
225 
226     // num subgroups
227     uint8_t num_subgroups = buffer[pos++];
228     if (num_subgroups > BASS_SUBGROUPS_MAX_NUM){
229         log_info("Number of subgroups %u exceedes maximum %u", num_subgroups, BASS_SUBGROUPS_MAX_NUM);
230         return false;
231     }
232 
233     uint8_t i;
234     for (i = 0; i < num_subgroups; i++) {
235         // check if we can read bis_sync_state + meta_data_length
236         // bis_sync_state
237         pos += 4;
238         // meta_data_length
239         if (pos >= buffer_size){
240             return false;
241         }
242         uint8_t metadata_length = buffer[pos++];
243         if ((pos + metadata_length) > buffer_size){
244             return false;
245         }
246         // metadata
247         pos += metadata_length;
248     }
249     return true;
250 }
251 
252 static void bass_client_handle_gatt_server_notification(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
253     UNUSED(packet_type);
254     UNUSED(channel);
255     UNUSED(size);
256 
257     if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION){
258         return;
259     }
260     bass_client_connection_t * connection = bass_client_get_connection_for_con_handle(gatt_event_notification_get_handle(packet));
261     if (connection == NULL){
262         return;
263     }
264 
265     uint16_t value_handle =  gatt_event_notification_get_value_handle(packet);
266     uint16_t value_length = gatt_event_notification_get_value_length(packet);
267     uint8_t * value = (uint8_t *)gatt_event_notification_get_value(packet);
268 
269     if (bass_client_remote_broadcast_receive_state_buffer_valid(value, value_length)){
270         bass_client_source_t * source = bass_client_get_receive_state_for_value_handle(connection, value_handle);
271         if (source == NULL){
272             return;
273         }
274         source->source_id = value[0];
275         bass_util_source_data_parse(&value[1], value_length - 1, &source->data, true);
276 
277         // get big encryption + bad code
278         source->big_encryption = (le_audio_big_encryption_t) value[13];
279         if (source->big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){
280             reverse_128(&value[14], source->bad_code);
281         } else {
282             memset(source->bad_code, 0, 16);
283         }
284 
285         bass_client_emit_receive_state(connection, source->source_id);
286     }
287 }
288 
289 static bool bass_client_register_notification(bass_client_connection_t * connection){
290     bass_client_source_t * receive_state = &connection->receive_states[connection->receive_states_index];
291     if (receive_state == NULL){
292         return false;
293     }
294 
295     gatt_client_characteristic_t characteristic;
296     characteristic.value_handle = receive_state->receive_state_value_handle;
297     characteristic.properties   = receive_state->receive_state_properties;
298     characteristic.end_handle   = receive_state->receive_state_end_handle;
299 
300     uint8_t status = gatt_client_write_client_characteristic_configuration(
301             &bass_client_handle_gatt_client_event,
302                 connection->con_handle,
303                 &characteristic,
304                 GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
305 
306     // notification supported, register for value updates
307     if (status == ERROR_CODE_SUCCESS){
308         gatt_client_listen_for_characteristic_value_updates(
309             &connection->notification_listener,
310             &bass_client_handle_gatt_server_notification,
311             connection->con_handle, &characteristic);
312     }
313     return status;
314 }
315 
316 static uint16_t bass_client_prepare_add_source_buffer(bass_client_connection_t * connection){
317     const bass_source_data_t * receive_state = connection->control_point_operation_data;
318 
319     uint16_t  buffer_offset = connection->buffer_offset;
320     uint8_t * buffer        = connection->buffer;
321     uint16_t  buffer_size   = btstack_min(sizeof(connection->buffer), connection->mtu);
322 
323     btstack_assert(buffer_offset == 0);
324 
325     uint8_t  field_data[6];
326     uint16_t source_offset = 0;
327     uint16_t stored_bytes = 0;
328     memset(buffer, 0, buffer_size);
329 
330     field_data[0] = (uint8_t)BASS_OPCODE_ADD_SOURCE;
331     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
332                                                         buffer_offset);
333     source_offset++;
334 
335     stored_bytes += bass_util_source_data_header_virtual_memcpy(receive_state, &source_offset, buffer_offset, buffer,
336                                                                 buffer_size);
337 
338     field_data[0] = (uint8_t)receive_state->pa_sync;
339     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
340                                                         buffer_offset);
341     source_offset++;
342 
343     little_endian_store_16(field_data, 0, receive_state->pa_interval);
344     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, source_offset, buffer, buffer_size,
345                                                         buffer_offset);
346     source_offset += 2;
347 
348     stored_bytes += bass_util_source_data_subgroups_virtual_memcpy(receive_state, false, &source_offset, buffer_offset,
349                                                                    buffer,
350                                                                    buffer_size);
351 
352     return stored_bytes;
353 }
354 
355 static uint16_t bass_client_prepare_modify_source_buffer(bass_client_connection_t * connection){
356     const bass_source_data_t * receive_state = connection->control_point_operation_data;
357 
358     uint16_t  buffer_offset = connection->buffer_offset;
359     uint8_t * buffer        = connection->buffer;
360     uint16_t  buffer_size   = btstack_min(sizeof(connection->buffer), connection->mtu);
361 
362     btstack_assert(buffer_offset == 0);
363 
364     uint8_t  field_data[6];
365     uint16_t source_offset = 0;
366     uint16_t stored_bytes = 0;
367     memset(buffer, 0, buffer_size);
368 
369     field_data[0] = (uint8_t)BASS_OPCODE_MODIFY_SOURCE;
370     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
371                                                         buffer_offset);
372     source_offset++;
373 
374     field_data[0] = connection->control_point_operation_source_id;
375     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
376                                                         buffer_offset);
377     source_offset++;
378 
379     field_data[0] = (uint8_t)receive_state->pa_sync;
380     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
381                                                         buffer_offset);
382     source_offset++;
383 
384     little_endian_store_16(field_data, 0, receive_state->pa_interval);
385     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 2, source_offset, buffer, buffer_size,
386                                                         buffer_offset);
387     source_offset += 2;
388 
389     stored_bytes += bass_util_source_data_subgroups_virtual_memcpy(receive_state, false, &source_offset, buffer_offset,
390                                                                    buffer,
391                                                                    buffer_size);
392     return stored_bytes;
393 }
394 
395 static uint16_t bass_client_receive_state_len(const bass_source_data_t * source_data){
396     uint16_t source_len = 0;
397     // opcode(1), address_type(1), address(6), adv_sid(1), broadcast_id(3), pa_sync(1), subgroups_num(1)
398     source_len = 1 + 1 + 6 + 1 + 3 + 1 + 1;
399 
400     uint8_t i;
401     for (i = 0; i < source_data->subgroups_num; i++){
402         bass_subgroup_t subgroup = source_data->subgroups[i];
403         // bis_sync(4), metadata_length(1), metadata_length
404         source_len += 4 + 1 + subgroup.metadata_length;
405     }
406     return source_len;
407 }
408 
409 static void bass_client_run_for_connection(bass_client_connection_t * connection){
410     uint8_t status;
411     gatt_client_characteristic_t characteristic;
412     gatt_client_service_t service;
413 
414     uint8_t  value[18];
415     uint16_t stored_bytes;
416 
417     switch (connection->state){
418         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED:
419             break;
420 
421         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_START_SCAN:
422 #ifdef ENABLE_TESTING_SUPPORT
423             printf("    Write START SCAN [0x%04X]:\n",
424                 connection->control_point_value_handle);
425 #endif
426 
427             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_START_SCAN;
428             value[0] = BASS_OPCODE_REMOTE_SCAN_STARTED;
429             // see GATT_EVENT_QUERY_COMPLETE for end of write
430             status = gatt_client_write_value_of_characteristic(
431                     &bass_client_handle_gatt_client_event, connection->con_handle,
432                     connection->control_point_value_handle, 1, &value[0]);
433             UNUSED(status);
434             break;
435 
436         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_STOP_SCAN:
437 #ifdef ENABLE_TESTING_SUPPORT
438             printf("    Write START SCAN [0x%04X]:\n",
439                 connection->control_point_value_handle);
440 #endif
441 
442             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_STOP_SCAN;
443             value[0] = BASS_OPCODE_REMOTE_SCAN_STOPPED;
444             // see GATT_EVENT_QUERY_COMPLETE for end of write
445             status = gatt_client_write_value_of_characteristic(
446                     &bass_client_handle_gatt_client_event, connection->con_handle,
447                     connection->control_point_value_handle, 1, &value[0]);
448             UNUSED(status);
449             break;
450 
451         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_ADD_SOURCE:
452             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE;
453 #ifdef ENABLE_TESTING_SUPPORT
454             printf("    ADD SOURCE [0x%04X]:\n", connection->control_point_value_handle);
455 #endif
456             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE;
457             stored_bytes = bass_client_prepare_add_source_buffer(connection);
458             connection->buffer_offset += stored_bytes;
459 
460             gatt_client_write_long_value_of_characteristic(&bass_client_handle_gatt_client_event, connection->con_handle,
461                                                            connection->control_point_value_handle, stored_bytes, connection->buffer);
462             break;
463 
464         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_MODIFY_SOURCE:
465 #ifdef ENABLE_TESTING_SUPPORT
466             printf("    MODIFY SOURCE [%d]:\n", connection->control_point_operation_source_id);
467 #endif
468             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_MODIFY_SOURCE;
469             stored_bytes = bass_client_prepare_modify_source_buffer(connection);
470             connection->buffer_offset += stored_bytes;
471 
472             gatt_client_write_long_value_of_characteristic(&bass_client_handle_gatt_client_event, connection->con_handle,
473                                                            connection->control_point_value_handle, stored_bytes, connection->buffer);
474 
475             break;
476 
477         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_REMOVE_SOURCE:
478 #ifdef ENABLE_TESTING_SUPPORT
479             printf("    REMOVE SOURCE  [%d]:\n", connection->control_point_operation_source_id);
480 #endif
481             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_REMOVE_SOURCE;
482             value[0] = BASS_OPCODE_REMOVE_SOURCE;
483             value[1] = connection->control_point_operation_source_id;
484             // see GATT_EVENT_QUERY_COMPLETE for end of write
485             status = gatt_client_write_value_of_characteristic(
486                     &bass_client_handle_gatt_client_event, connection->con_handle,
487                     connection->control_point_value_handle, 2, &value[0]);
488             UNUSED(status);
489             break;
490 
491         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_SET_BROADCAST_CODE:
492 #ifdef ENABLE_TESTING_SUPPORT
493             printf("    SET BROADCAST CODE [%d]:\n", connection->control_point_operation_source_id);
494 #endif
495             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_SET_BROADCAST_CODE;
496             value[0] = BASS_OPCODE_SET_BROADCAST_CODE;
497             value[1] = connection->control_point_operation_source_id;
498             reverse_128(connection->broadcast_code, &value[2]);
499 
500             // see GATT_EVENT_QUERY_COMPLETE for end of write
501             status = gatt_client_write_value_of_characteristic(
502                     &bass_client_handle_gatt_client_event, connection->con_handle,
503                     connection->control_point_value_handle, 18, &value[0]);
504             UNUSED(status);
505             break;
506 
507         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE:
508             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT;
509             gatt_client_discover_primary_services_by_uuid16(&bass_client_handle_gatt_client_event, connection->con_handle, ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE);
510             break;
511 
512         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS:
513             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT;
514 
515             service.start_group_handle = connection->start_handle;
516             service.end_group_handle = connection->end_handle;
517             service.uuid16 = ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE;
518 
519             gatt_client_discover_characteristics_for_service(
520                     &bass_client_handle_gatt_client_event,
521                 connection->con_handle,
522                 &service);
523 
524             break;
525 
526         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS:
527 #ifdef ENABLE_TESTING_SUPPORT
528             printf("Read client characteristic descriptors [index %d]:\n", connection->receive_states_index);
529 #endif
530             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_DESCRIPTORS_RESULT;
531             characteristic.value_handle = connection->receive_states[connection->receive_states_index].receive_state_value_handle;
532             characteristic.properties   = connection->receive_states[connection->receive_states_index].receive_state_properties;
533             characteristic.end_handle   = connection->receive_states[connection->receive_states_index].receive_state_end_handle;
534 
535             (void) gatt_client_discover_characteristic_descriptors(&bass_client_handle_gatt_client_event, connection->con_handle, &characteristic);
536             break;
537 
538         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION:
539 #ifdef ENABLE_TESTING_SUPPORT
540             printf("Read client characteristic value [index %d, handle 0x%04X]:\n", connection->receive_states_index, connection->receive_states[connection->receive_states_index].receive_state_ccc_handle);
541 #endif
542             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT;
543 
544             // result in GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT
545             (void) gatt_client_read_characteristic_descriptor_using_descriptor_handle(
546                     &bass_client_handle_gatt_client_event,
547                 connection->con_handle,
548                 connection->receive_states[connection->receive_states_index].receive_state_ccc_handle);
549             break;
550 
551         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION:
552 #ifdef ENABLE_TESTING_SUPPORT
553             printf("Register notification [index %d, handle 0x%04X]:\n", connection->receive_states_index, connection->receive_states[connection->receive_states_index].receive_state_ccc_handle);
554 #endif
555 
556             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED;
557 
558             status = bass_client_register_notification(connection);
559             if (status == ERROR_CODE_SUCCESS) return;
560 
561             if (connection->receive_states[connection->receive_states_index].receive_state_ccc_handle != 0){
562                 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION;
563                 break;
564             }
565 
566             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED;
567             bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS);
568             break;
569         default:
570             break;
571     }
572 }
573 // @return true if client valid / run function should be called
574 static bool bass_client_handle_query_complete(bass_client_connection_t * connection, uint8_t status){
575     switch (connection->state){
576         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
577             if (status != ATT_ERROR_SUCCESS){
578                 bass_client_emit_connection_established(connection, status);
579                 bass_client_finalize_connection(connection);
580                 return false;
581             }
582 
583             if (connection->service_instances_num == 0){
584                 bass_client_emit_connection_established(connection, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE);
585                 bass_client_finalize_connection(connection);
586                 return false;
587             }
588             connection->receive_states_index = 0;
589             connection->receive_states_instances_num = 0;
590             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTICS;
591             break;
592 
593         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_RESULT:
594             if (status != ATT_ERROR_SUCCESS){
595                 bass_client_emit_connection_established(connection, status);
596                 bass_client_finalize_connection(connection);
597                 return false;
598             }
599 
600             connection->receive_states_index = 0;
601             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS;
602             break;
603 
604         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_DESCRIPTORS_RESULT:
605             if (connection->receive_states_index < (connection->receive_states_instances_num - 1)){
606                 connection->receive_states_index++;
607                 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_CHARACTERISTIC_DESCRIPTORS;
608                 break;
609             }
610             connection->receive_states_index = 0;
611             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION;
612             break;
613 
614         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED:
615             if (connection->receive_states_index < (connection->receive_states_instances_num - 1)){
616                 connection->receive_states_index++;
617                 connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION;
618                 break;
619             }
620 
621             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED;
622             bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS);
623             break;
624 
625         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT:
626             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED;
627             bass_client_emit_connection_established(connection, ERROR_CODE_SUCCESS);
628             break;
629 
630         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_START_SCAN:
631             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED;
632             bass_client_emit_scan_operation_complete(connection, status, BASS_OPCODE_REMOTE_SCAN_STARTED);
633             break;
634 
635         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_STOP_SCAN:
636             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED;
637             bass_client_emit_scan_operation_complete(connection, status, BASS_OPCODE_REMOTE_SCAN_STOPPED);
638             break;
639 
640         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_ADD_SOURCE:
641             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED;
642             bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_ADD_SOURCE, BASS_INVALID_SOURCE_INDEX);
643             break;
644 
645         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_MODIFY_SOURCE:
646             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED;
647             bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_MODIFY_SOURCE, connection->control_point_operation_source_id);
648             break;
649 
650         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_REMOVE_SOURCE:
651             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED;
652             bass_client_reset_source(
653                     bass_client_get_source_for_source_id(connection, connection->control_point_operation_source_id));
654             bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_REMOVE_SOURCE, connection->control_point_operation_source_id);
655             break;
656 
657         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_WRITE_CONTROL_POINT_SET_BROADCAST_CODE:
658             connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED;
659             bass_client_emit_source_operation_complete(connection, status, BASS_OPCODE_SET_BROADCAST_CODE, connection->control_point_operation_source_id);
660             break;
661 
662         case BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED:
663             if (status != ATT_ERROR_SUCCESS){
664                 break;
665             }
666 
667             break;
668 
669         default:
670             break;
671 
672     }
673     return true;
674 }
675 
676 static void bass_client_handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
677     UNUSED(packet_type);
678     UNUSED(channel);
679     UNUSED(size);
680 
681     bass_client_connection_t * connection = NULL;
682     gatt_client_service_t service;
683     gatt_client_characteristic_t characteristic;
684     gatt_client_characteristic_descriptor_t characteristic_descriptor;
685 
686     bool call_run = true;
687 
688     switch(hci_event_packet_get_type(packet)){
689         case GATT_EVENT_MTU:
690             connection = bass_client_get_connection_for_con_handle(gatt_event_mtu_get_handle(packet));
691             btstack_assert(connection != NULL);
692             connection->mtu = gatt_event_mtu_get_MTU(packet);
693             break;
694 
695         case GATT_EVENT_SERVICE_QUERY_RESULT:
696             connection = bass_client_get_connection_for_con_handle(gatt_event_service_query_result_get_handle(packet));
697             btstack_assert(connection != NULL);
698 
699             if (connection->service_instances_num < 1){
700                 gatt_event_service_query_result_get_service(packet, &service);
701                 connection->start_handle = service.start_group_handle;
702                 connection->end_handle   = service.end_group_handle;
703 
704 #ifdef ENABLE_TESTING_SUPPORT
705                 printf("BASS Service: start handle 0x%04X, end handle 0x%04X\n", connection->start_handle, connection->end_handle);
706 #endif
707                 connection->service_instances_num++;
708             } else {
709                 log_info("Found more then one BASS Service instance. ");
710             }
711             break;
712 
713         case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
714             connection = bass_client_get_connection_for_con_handle(gatt_event_characteristic_query_result_get_handle(packet));
715             btstack_assert(connection != NULL);
716 
717             gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
718 
719             switch (characteristic.uuid16){
720                 case ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_AUDIO_SCAN_CONTROL_POINT:
721                     connection->control_point_value_handle = characteristic.value_handle;
722                     break;
723                 case ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE:
724                     if (connection->receive_states_instances_num < connection->max_receive_states_num){
725                         connection->receive_states[connection->receive_states_instances_num].receive_state_value_handle = characteristic.value_handle;
726                         connection->receive_states[connection->receive_states_instances_num].receive_state_properties = characteristic.properties;
727                         connection->receive_states[connection->receive_states_index].receive_state_end_handle = characteristic.end_handle;
728                         connection->receive_states_instances_num++;
729                     } else {
730                         log_info("Found more BASS receive_states chrs then it can be stored. ");
731                     }
732                     break;
733                 default:
734                     btstack_assert(false);
735                     return;
736             }
737 
738 #ifdef ENABLE_TESTING_SUPPORT
739             printf("BASS Characteristic:\n    Attribute Handle 0x%04X, Properties 0x%02X, Handle 0x%04X, UUID 0x%04X, %s\n",
740                 characteristic.start_handle,
741                 characteristic.properties,
742                 characteristic.value_handle, characteristic.uuid16,
743                 characteristic.uuid16 == ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE ? "RECEIVE_STATE" : "CONTROL_POINT");
744 #endif
745             break;
746 
747 
748         case GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
749             connection = bass_client_get_connection_for_con_handle(gatt_event_all_characteristic_descriptors_query_result_get_handle(packet));
750             btstack_assert(connection != NULL);
751             gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &characteristic_descriptor);
752 
753             if (characteristic_descriptor.uuid16 == ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION){
754                 connection->receive_states[connection->receive_states_index].receive_state_ccc_handle = characteristic_descriptor.handle;
755 
756 #ifdef ENABLE_TESTING_SUPPORT
757                 printf("    BASS Characteristic Configuration Descriptor:  Handle 0x%04X, UUID 0x%04X\n",
758                     characteristic_descriptor.handle,
759                     characteristic_descriptor.uuid16);
760 #endif
761             }
762             break;
763 
764 
765         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
766             connection = bass_client_get_connection_for_con_handle(gatt_event_characteristic_value_query_result_get_handle(packet));
767             btstack_assert(connection != NULL);
768 
769             if (connection->state == BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT){
770 #ifdef ENABLE_TESTING_SUPPORT
771                 printf("    Received CCC value: ");
772                 printf_hexdump(gatt_event_characteristic_value_query_result_get_value(packet),  gatt_event_characteristic_value_query_result_get_value_length(packet));
773 #endif
774                 break;
775             }
776 
777             if (gatt_event_characteristic_value_query_result_get_value_length(packet) == 0 ){
778                 break;
779             }
780 
781             // TODO
782             // bass_client_emit_receive_state(connection,
783             //     gatt_event_characteristic_value_query_result_get_value_handle(packet),
784             //     ATT_ERROR_SUCCESS,
785             //     gatt_event_notification_get_value(packet),
786             //     gatt_event_notification_get_value_length(packet));
787             break;
788 
789         case GATT_EVENT_QUERY_COMPLETE:
790             connection = bass_client_get_connection_for_con_handle(gatt_event_query_complete_get_handle(packet));
791             btstack_assert(connection != NULL);
792             call_run = bass_client_handle_query_complete(connection, gatt_event_query_complete_get_att_status(packet));
793             break;
794 
795         default:
796             break;
797     }
798 
799     if (call_run && (connection != NULL)){
800         bass_client_run_for_connection(connection);
801     }
802 }
803 
804 void broadcast_audio_scan_service_client_init(btstack_packet_handler_t packet_handler){
805     btstack_assert(packet_handler != NULL);
806     bass_client_event_callback = packet_handler;
807 }
808 
809 uint8_t broadcast_audio_scan_service_client_connect(bass_client_connection_t * connection,
810     bass_client_source_t * receive_states, uint8_t receive_states_num,
811     hci_con_handle_t con_handle, uint16_t * bass_cid){
812 
813     btstack_assert(receive_states != NULL);
814     btstack_assert(receive_states_num > 0);
815 
816     if (bass_client_get_connection_for_con_handle(con_handle) != NULL){
817         return ERROR_CODE_COMMAND_DISALLOWED;
818     }
819 
820     uint16_t cid = bass_client_get_next_cid();
821     if (bass_cid != NULL) {
822         *bass_cid = cid;
823     }
824 
825     connection->cid = cid;
826     connection->con_handle = con_handle;
827     connection->mtu = ATT_DEFAULT_MTU;
828 
829     connection->max_receive_states_num = receive_states_num;
830     connection->receive_states = receive_states;
831 
832     uint8_t i;
833     for (i = 0; i < connection->max_receive_states_num; i++){
834         connection->receive_states[i].in_use = false;
835         connection->receive_states[i].source_id = BASS_INVALID_SOURCE_INDEX;
836     }
837 
838     connection->service_instances_num = 0;
839     connection->receive_states_instances_num = 0;
840     connection->receive_states_index = 0;
841 
842     connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
843     btstack_linked_list_add(&bass_client_connections, (btstack_linked_item_t *) connection);
844 
845     bass_client_run_for_connection(connection);
846     return ERROR_CODE_SUCCESS;
847 }
848 
849 uint8_t broadcast_audio_scan_service_client_scanning_started(uint16_t bass_cid){
850     bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid);
851     if (connection == NULL){
852         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
853     }
854     if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){
855         return ERROR_CODE_COMMAND_DISALLOWED;
856     }
857     connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_START_SCAN;
858     bass_client_run_for_connection(connection);
859      return ERROR_CODE_SUCCESS;
860 }
861 
862 uint8_t broadcast_audio_scan_service_client_scanning_stopped(uint16_t bass_cid){
863     bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid);
864     if (connection == NULL){
865         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
866     }
867     if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){
868         return ERROR_CODE_COMMAND_DISALLOWED;
869     }
870     connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_STOP_SCAN;
871     bass_client_run_for_connection(connection);
872     return ERROR_CODE_SUCCESS;
873 }
874 
875 uint8_t broadcast_audio_scan_service_client_add_source(uint16_t bass_cid, const bass_source_data_t * add_source_data){
876     bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid);
877     if (connection == NULL){
878         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
879     }
880     if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){
881         return ERROR_CODE_COMMAND_DISALLOWED;
882     }
883 
884     connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_ADD_SOURCE;
885     connection->control_point_operation_data = add_source_data;
886     connection->buffer_offset = 0;
887     connection->data_size = bass_client_receive_state_len(add_source_data);
888 
889     bass_client_run_for_connection(connection);
890     return ERROR_CODE_SUCCESS;
891 }
892 
893 uint8_t broadcast_audio_scan_service_client_modify_source(uint16_t bass_cid, uint8_t source_id, const bass_source_data_t * modify_source_data){
894     bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid);
895     if (connection == NULL){
896         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
897     }
898     if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){
899         return ERROR_CODE_COMMAND_DISALLOWED;
900     }
901 
902     connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_MODIFY_SOURCE;
903     connection->control_point_operation_data = modify_source_data;
904     connection->control_point_operation_source_id = source_id;
905     connection->buffer_offset = 0;
906     connection->data_size = bass_client_receive_state_len(modify_source_data);
907 
908     bass_client_run_for_connection(connection);
909     return ERROR_CODE_SUCCESS;
910 }
911 
912 uint8_t broadcast_audio_scan_service_client_remove_source(uint16_t bass_cid, uint8_t source_id){
913     bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid);
914     if (connection == NULL){
915         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
916     }
917     if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){
918         return ERROR_CODE_COMMAND_DISALLOWED;
919     }
920 
921     connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_REMOVE_SOURCE;
922     connection->control_point_operation_source_id = source_id;
923 
924     bass_client_run_for_connection(connection);
925     return ERROR_CODE_SUCCESS;
926 }
927 
928 uint8_t broadcast_audio_scan_service_client_set_broadcast_code(uint16_t bass_cid, uint8_t source_id, const uint8_t * broadcast_code){
929     bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid);
930     if (connection == NULL){
931         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
932     }
933     if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){
934         return ERROR_CODE_COMMAND_DISALLOWED;
935     }
936 
937     connection->state = BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_W2_WRITE_CONTROL_POINT_SET_BROADCAST_CODE;
938     connection->control_point_operation_source_id = source_id;
939     connection->broadcast_code = broadcast_code;
940 
941     bass_client_run_for_connection(connection);
942     return ERROR_CODE_SUCCESS;
943 }
944 
945 const bass_source_data_t * broadcast_audio_scan_service_client_get_source_data(uint16_t bass_cid, uint8_t source_id){
946     bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid);
947     if (connection == NULL){
948         return NULL;
949     }
950     if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){
951         return NULL;
952     }
953     return (const bass_source_data_t *) &bass_client_get_source_for_source_id(connection, source_id)->data;
954 }
955 
956 uint8_t broadcast_audio_scan_service_client_get_encryption_state(uint16_t bass_cid, uint8_t source_id,
957                                                                  le_audio_big_encryption_t * out_big_encryption, uint8_t * out_bad_code){
958     btstack_assert(out_big_encryption != NULL);
959     btstack_assert(out_bad_code != NULL);
960 
961     bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid);
962     if (connection == NULL){
963         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
964     }
965     if (connection->state != BROADCAST_AUDIO_SCAN_SERVICE_CLIENT_STATE_CONNECTED){
966         return ERROR_CODE_COMMAND_DISALLOWED;
967     }
968     bass_client_source_t * source = bass_client_get_source_for_source_id(connection, source_id);
969     if (source == NULL){
970         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
971     }
972     *out_big_encryption = source->big_encryption;
973     memcpy(out_bad_code, source->bad_code, 16);
974     return ERROR_CODE_SUCCESS;
975 }
976 
977 void broadcast_audio_scan_service_client_deinit(uint16_t bass_cid){
978     bass_client_event_callback = NULL;
979     bass_client_connection_t * connection = bass_client_get_connection_for_cid(bass_cid);
980     if (connection == NULL){
981         return;
982     }
983     // finalize connections
984     bass_client_finalize_connection(connection);
985 }
986 
987