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