15deb0bb6SMatthias Ringwald /*
25deb0bb6SMatthias Ringwald * Copyright (C) 2022 BlueKitchen GmbH
35deb0bb6SMatthias Ringwald *
45deb0bb6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without
55deb0bb6SMatthias Ringwald * modification, are permitted provided that the following conditions
65deb0bb6SMatthias Ringwald * are met:
75deb0bb6SMatthias Ringwald *
85deb0bb6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
95deb0bb6SMatthias Ringwald * notice, this list of conditions and the following disclaimer.
105deb0bb6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
115deb0bb6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
125deb0bb6SMatthias Ringwald * documentation and/or other materials provided with the distribution.
135deb0bb6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
145deb0bb6SMatthias Ringwald * contributors may be used to endorse or promote products derived
155deb0bb6SMatthias Ringwald * from this software without specific prior written permission.
165deb0bb6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
175deb0bb6SMatthias Ringwald * personal benefit and not for any commercial purpose or for
185deb0bb6SMatthias Ringwald * monetary gain.
195deb0bb6SMatthias Ringwald *
205deb0bb6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
215deb0bb6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
225deb0bb6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
235deb0bb6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
245deb0bb6SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
255deb0bb6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
265deb0bb6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
275deb0bb6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
285deb0bb6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
295deb0bb6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
305deb0bb6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
315deb0bb6SMatthias Ringwald * SUCH DAMAGE.
325deb0bb6SMatthias Ringwald *
335deb0bb6SMatthias Ringwald * Please inquire about commercial licensing options at
345deb0bb6SMatthias Ringwald * [email protected]
355deb0bb6SMatthias Ringwald *
365deb0bb6SMatthias Ringwald */
375deb0bb6SMatthias Ringwald
385deb0bb6SMatthias Ringwald #define BTSTACK_FILE__ "broadcast_audio_scan_service_server.c"
395deb0bb6SMatthias Ringwald
405deb0bb6SMatthias Ringwald #include <stdio.h>
415deb0bb6SMatthias Ringwald
425deb0bb6SMatthias Ringwald #include "ble/att_db.h"
435deb0bb6SMatthias Ringwald #include "ble/att_server.h"
445deb0bb6SMatthias Ringwald #include "bluetooth_gatt.h"
455deb0bb6SMatthias Ringwald #include "btstack_debug.h"
465deb0bb6SMatthias Ringwald #include "btstack_defines.h"
475deb0bb6SMatthias Ringwald #include "btstack_event.h"
485deb0bb6SMatthias Ringwald #include "btstack_util.h"
495deb0bb6SMatthias Ringwald
505deb0bb6SMatthias Ringwald #include "le-audio/gatt-service/broadcast_audio_scan_service_server.h"
515deb0bb6SMatthias Ringwald #include "le-audio/le_audio_util.h"
525deb0bb6SMatthias Ringwald
535deb0bb6SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
545deb0bb6SMatthias Ringwald #include <stdio.h>
555deb0bb6SMatthias Ringwald #endif
565deb0bb6SMatthias Ringwald
575deb0bb6SMatthias Ringwald #define BASS_MAX_NOTIFY_BUFFER_SIZE 200
585deb0bb6SMatthias Ringwald #define BASS_INVALID_SOURCE_INDEX 0xFF
595deb0bb6SMatthias Ringwald
605deb0bb6SMatthias Ringwald static att_service_handler_t broadcast_audio_scan_service;
61c4f227dfSMilanka Ringwald static btstack_packet_handler_t bass_server_event_callback;
625deb0bb6SMatthias Ringwald
635deb0bb6SMatthias Ringwald // characteristic: AUDIO_SCAN_CONTROL_POINT
645deb0bb6SMatthias Ringwald static uint16_t bass_audio_scan_control_point_handle;
655deb0bb6SMatthias Ringwald
665deb0bb6SMatthias Ringwald static uint8_t bass_logic_time = 0;
675deb0bb6SMatthias Ringwald
685deb0bb6SMatthias Ringwald static bass_server_source_t * bass_sources;
695deb0bb6SMatthias Ringwald static uint8_t bass_sources_num = 0;
707f95ef04SMilanka Ringwald static bass_server_connection_t * bass_clients;
715deb0bb6SMatthias Ringwald static uint8_t bass_clients_num = 0;
725deb0bb6SMatthias Ringwald static btstack_context_callback_registration_t scheduled_tasks_callback;
735deb0bb6SMatthias Ringwald
bass_server_get_next_update_counter(void)74c4f227dfSMilanka Ringwald static uint8_t bass_server_get_next_update_counter(void){
755deb0bb6SMatthias Ringwald uint8_t next_update_counter;
765deb0bb6SMatthias Ringwald if (bass_logic_time == 0xff) {
775deb0bb6SMatthias Ringwald next_update_counter = 0;
785deb0bb6SMatthias Ringwald } else {
795deb0bb6SMatthias Ringwald next_update_counter = bass_logic_time + 1;
805deb0bb6SMatthias Ringwald }
815deb0bb6SMatthias Ringwald bass_logic_time = next_update_counter;
825deb0bb6SMatthias Ringwald return next_update_counter;
835deb0bb6SMatthias Ringwald }
845deb0bb6SMatthias Ringwald
855deb0bb6SMatthias Ringwald // returns positive number if counter a > b
bass_server_counter_delta(uint8_t counter_a,uint8_t counter_b)86c4f227dfSMilanka Ringwald static int8_t bass_server_counter_delta(uint8_t counter_a, uint8_t counter_b){
875deb0bb6SMatthias Ringwald return (int8_t)(counter_a - counter_b);
885deb0bb6SMatthias Ringwald }
895deb0bb6SMatthias Ringwald
bass_server_find_empty_or_last_used_source_index(void)90c4f227dfSMilanka Ringwald static uint8_t bass_server_find_empty_or_last_used_source_index(void){
915deb0bb6SMatthias Ringwald bass_server_source_t * last_used_source = NULL;
925deb0bb6SMatthias Ringwald uint8_t last_used_source_index = BASS_INVALID_SOURCE_INDEX;
935deb0bb6SMatthias Ringwald
945deb0bb6SMatthias Ringwald uint8_t i;
955deb0bb6SMatthias Ringwald for (i = 0; i < bass_sources_num; i++){
965deb0bb6SMatthias Ringwald if (!bass_sources[i].in_use){
975deb0bb6SMatthias Ringwald return i;
985deb0bb6SMatthias Ringwald }
995deb0bb6SMatthias Ringwald if (last_used_source == NULL){
1005deb0bb6SMatthias Ringwald last_used_source = &bass_sources[i];
1015deb0bb6SMatthias Ringwald last_used_source_index = i;
1025deb0bb6SMatthias Ringwald continue;
1035deb0bb6SMatthias Ringwald }
104c4f227dfSMilanka Ringwald if (bass_server_counter_delta(bass_sources[i].update_counter, last_used_source->update_counter) < 0 ){
1055deb0bb6SMatthias Ringwald last_used_source = &bass_sources[i];
1065deb0bb6SMatthias Ringwald last_used_source_index = i;
1075deb0bb6SMatthias Ringwald }
1085deb0bb6SMatthias Ringwald }
1095deb0bb6SMatthias Ringwald return last_used_source_index;
1105deb0bb6SMatthias Ringwald }
1115deb0bb6SMatthias Ringwald
bass_server_find_empty_or_last_used_source(void)112c4f227dfSMilanka Ringwald static bass_server_source_t * bass_server_find_empty_or_last_used_source(void){
113c4f227dfSMilanka Ringwald uint8_t last_used_source_index = bass_server_find_empty_or_last_used_source_index();
1145deb0bb6SMatthias Ringwald if (last_used_source_index == BASS_INVALID_SOURCE_INDEX){
1155deb0bb6SMatthias Ringwald return NULL;
1165deb0bb6SMatthias Ringwald }
1175deb0bb6SMatthias Ringwald return &bass_sources[last_used_source_index];
1185deb0bb6SMatthias Ringwald }
1195deb0bb6SMatthias Ringwald
bass_server_find_receive_state_for_value_handle(uint16_t attribute_handle)120c4f227dfSMilanka Ringwald static bass_server_source_t * bass_server_find_receive_state_for_value_handle(uint16_t attribute_handle){
1215deb0bb6SMatthias Ringwald uint16_t i;
1225deb0bb6SMatthias Ringwald for (i = 0; i < bass_sources_num; i++){
1235deb0bb6SMatthias Ringwald if (attribute_handle == bass_sources[i].bass_receive_state_handle){
1245deb0bb6SMatthias Ringwald return &bass_sources[i];
1255deb0bb6SMatthias Ringwald }
1265deb0bb6SMatthias Ringwald }
1275deb0bb6SMatthias Ringwald return NULL;
1285deb0bb6SMatthias Ringwald }
1295deb0bb6SMatthias Ringwald
bass_server_find_receive_state_for_client_configuration_handle(uint16_t attribute_handle)130c4f227dfSMilanka Ringwald static bass_server_source_t * bass_server_find_receive_state_for_client_configuration_handle(uint16_t attribute_handle){
1315deb0bb6SMatthias Ringwald if (attribute_handle == 0){
1325deb0bb6SMatthias Ringwald return NULL;
1335deb0bb6SMatthias Ringwald }
1345deb0bb6SMatthias Ringwald uint8_t i;
1355deb0bb6SMatthias Ringwald for (i = 0; i < bass_sources_num; i++){
1365deb0bb6SMatthias Ringwald if (bass_sources[i].bass_receive_state_client_configuration_handle == attribute_handle){
1375deb0bb6SMatthias Ringwald return &bass_sources[i];
1385deb0bb6SMatthias Ringwald }
1395deb0bb6SMatthias Ringwald }
1405deb0bb6SMatthias Ringwald return NULL;
1415deb0bb6SMatthias Ringwald }
1425deb0bb6SMatthias Ringwald
bass_server_find_source_for_source_id(uint8_t source_id)143c4f227dfSMilanka Ringwald static bass_server_source_t * bass_server_find_source_for_source_id(uint8_t source_id){
1445deb0bb6SMatthias Ringwald if (source_id < bass_sources_num){
1455deb0bb6SMatthias Ringwald return &bass_sources[source_id];
1465deb0bb6SMatthias Ringwald }
1475deb0bb6SMatthias Ringwald return NULL;
1485deb0bb6SMatthias Ringwald }
1495deb0bb6SMatthias Ringwald
bass_server_find_client_for_con_handle(hci_con_handle_t con_handle)1507f95ef04SMilanka Ringwald static bass_server_connection_t * bass_server_find_client_for_con_handle(hci_con_handle_t con_handle){
1515deb0bb6SMatthias Ringwald uint16_t i;
1525deb0bb6SMatthias Ringwald for (i = 0; i < bass_clients_num; i++){
1535deb0bb6SMatthias Ringwald if (bass_clients[i].con_handle == con_handle) {
1545deb0bb6SMatthias Ringwald return &bass_clients[i];
1555deb0bb6SMatthias Ringwald }
1565deb0bb6SMatthias Ringwald }
1575deb0bb6SMatthias Ringwald return NULL;
1585deb0bb6SMatthias Ringwald }
1595deb0bb6SMatthias Ringwald
bass_server_register_con_handle(hci_con_handle_t con_handle,uint16_t client_configuration)160c4f227dfSMilanka Ringwald static void bass_server_register_con_handle(hci_con_handle_t con_handle, uint16_t client_configuration){
1617f95ef04SMilanka Ringwald bass_server_connection_t * client = bass_server_find_client_for_con_handle(con_handle);
1625deb0bb6SMatthias Ringwald if (client == NULL){
163c4f227dfSMilanka Ringwald client = bass_server_find_client_for_con_handle(HCI_CON_HANDLE_INVALID);
1645deb0bb6SMatthias Ringwald if (client == NULL){
1655deb0bb6SMatthias Ringwald return;
1665deb0bb6SMatthias Ringwald }
1675deb0bb6SMatthias Ringwald
1685deb0bb6SMatthias Ringwald }
1695deb0bb6SMatthias Ringwald client->con_handle = (client_configuration == 0) ? HCI_CON_HANDLE_INVALID : con_handle;
1705deb0bb6SMatthias Ringwald }
1715deb0bb6SMatthias Ringwald
bass_server_source_emit_scan_stoped(hci_con_handle_t con_handle)172c4f227dfSMilanka Ringwald static void bass_server_source_emit_scan_stoped(hci_con_handle_t con_handle){
173c4f227dfSMilanka Ringwald btstack_assert(bass_server_event_callback != NULL);
1745deb0bb6SMatthias Ringwald
1755deb0bb6SMatthias Ringwald uint8_t event[5];
1765deb0bb6SMatthias Ringwald uint8_t pos = 0;
177*ae304283SMilanka Ringwald event[pos++] = HCI_EVENT_LEAUDIO_META;
1785deb0bb6SMatthias Ringwald event[pos++] = sizeof(event) - 2;
179*ae304283SMilanka Ringwald event[pos++] = LEAUDIO_SUBEVENT_BASS_SERVER_SCAN_STOPPED;
1805deb0bb6SMatthias Ringwald little_endian_store_16(event, pos, con_handle);
1815deb0bb6SMatthias Ringwald pos += 2;
182c4f227dfSMilanka Ringwald (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
1835deb0bb6SMatthias Ringwald }
1845deb0bb6SMatthias Ringwald
bass_server_source_emit_scan_started(hci_con_handle_t con_handle)185c4f227dfSMilanka Ringwald static void bass_server_source_emit_scan_started(hci_con_handle_t con_handle){
186c4f227dfSMilanka Ringwald btstack_assert(bass_server_event_callback != NULL);
1875deb0bb6SMatthias Ringwald
1885deb0bb6SMatthias Ringwald uint8_t event[5];
1895deb0bb6SMatthias Ringwald uint8_t pos = 0;
190*ae304283SMilanka Ringwald event[pos++] = HCI_EVENT_LEAUDIO_META;
1915deb0bb6SMatthias Ringwald event[pos++] = sizeof(event) - 2;
192*ae304283SMilanka Ringwald event[pos++] = LEAUDIO_SUBEVENT_BASS_SERVER_SCAN_STARTED;
1935deb0bb6SMatthias Ringwald little_endian_store_16(event, pos, con_handle);
1945deb0bb6SMatthias Ringwald pos += 2;
195c4f227dfSMilanka Ringwald (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
1965deb0bb6SMatthias Ringwald }
1975deb0bb6SMatthias Ringwald
1985deb0bb6SMatthias Ringwald
bass_server_source_emit_source_state_changed(uint8_t subevent_id,hci_con_handle_t con_handle,uint8_t source_id,le_audio_pa_sync_t pa_sync)199c4f227dfSMilanka Ringwald static void bass_server_source_emit_source_state_changed(uint8_t subevent_id, hci_con_handle_t con_handle, uint8_t source_id, le_audio_pa_sync_t pa_sync){
200c4f227dfSMilanka Ringwald btstack_assert(bass_server_event_callback != NULL);
2015deb0bb6SMatthias Ringwald
2025deb0bb6SMatthias Ringwald uint8_t event[7];
2035deb0bb6SMatthias Ringwald uint8_t pos = 0;
204*ae304283SMilanka Ringwald event[pos++] = HCI_EVENT_LEAUDIO_META;
2055deb0bb6SMatthias Ringwald event[pos++] = sizeof(event) - 2;
2065deb0bb6SMatthias Ringwald event[pos++] = subevent_id;
2075deb0bb6SMatthias Ringwald little_endian_store_16(event, pos, con_handle);
2085deb0bb6SMatthias Ringwald pos += 2;
2095deb0bb6SMatthias Ringwald event[pos++] = source_id;
2105deb0bb6SMatthias Ringwald event[pos++] = (uint8_t)pa_sync;
211c4f227dfSMilanka Ringwald (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
2125deb0bb6SMatthias Ringwald }
2135deb0bb6SMatthias Ringwald
bass_server_source_emit_source_added(hci_con_handle_t con_handle,bass_server_source_t * source)214c4f227dfSMilanka Ringwald static void bass_server_source_emit_source_added(hci_con_handle_t con_handle, bass_server_source_t * source){
215*ae304283SMilanka Ringwald bass_server_source_emit_source_state_changed(LEAUDIO_SUBEVENT_BASS_SERVER_SOURCE_ADDED, con_handle, source->source_id, source->data.pa_sync);
2165deb0bb6SMatthias Ringwald }
2175deb0bb6SMatthias Ringwald
bass_server_source_emit_source_modified(hci_con_handle_t con_handle,bass_server_source_t * source)218c4f227dfSMilanka Ringwald static void bass_server_source_emit_source_modified(hci_con_handle_t con_handle, bass_server_source_t * source){
219*ae304283SMilanka Ringwald bass_server_source_emit_source_state_changed(LEAUDIO_SUBEVENT_BASS_SERVER_SOURCE_MODIFIED, con_handle, source->source_id, source->data.pa_sync);
2205deb0bb6SMatthias Ringwald }
2215deb0bb6SMatthias Ringwald
bass_server_source_emit_source_deleted(hci_con_handle_t con_handle,bass_server_source_t * source)222c4f227dfSMilanka Ringwald static void bass_server_source_emit_source_deleted(hci_con_handle_t con_handle, bass_server_source_t * source){
223*ae304283SMilanka Ringwald bass_server_source_emit_source_state_changed(LEAUDIO_SUBEVENT_BASS_SERVER_SOURCE_DELETED, con_handle, source->source_id, LE_AUDIO_PA_SYNC_DO_NOT_SYNCHRONIZE_TO_PA);
2245deb0bb6SMatthias Ringwald }
2255deb0bb6SMatthias Ringwald
bass_server_source_emit_broadcast_code(hci_con_handle_t con_handle,uint8_t source_id,const uint8_t * broadcast_code)226c4f227dfSMilanka Ringwald static void bass_server_source_emit_broadcast_code(hci_con_handle_t con_handle, uint8_t source_id, const uint8_t * broadcast_code){
227c4f227dfSMilanka Ringwald btstack_assert(bass_server_event_callback != NULL);
2285deb0bb6SMatthias Ringwald
2295deb0bb6SMatthias Ringwald uint8_t event[22];
2305deb0bb6SMatthias Ringwald uint8_t pos = 0;
231*ae304283SMilanka Ringwald event[pos++] = HCI_EVENT_LEAUDIO_META;
2325deb0bb6SMatthias Ringwald event[pos++] = sizeof(event) - 2;
233*ae304283SMilanka Ringwald event[pos++] = LEAUDIO_SUBEVENT_BASS_SERVER_BROADCAST_CODE;
2345deb0bb6SMatthias Ringwald little_endian_store_16(event, pos, con_handle);
2355deb0bb6SMatthias Ringwald pos += 2;
2365deb0bb6SMatthias Ringwald event[pos++] = source_id;
2375deb0bb6SMatthias Ringwald reverse_128(broadcast_code, &event[pos]);
2385deb0bb6SMatthias Ringwald pos += 16;
239c4f227dfSMilanka Ringwald (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
2405deb0bb6SMatthias Ringwald }
2415deb0bb6SMatthias Ringwald
2425deb0bb6SMatthias Ringwald // offset gives position into fully serialized bass record
bass_server_copy_source_to_buffer(bass_server_source_t * source,uint16_t buffer_offset,uint8_t * buffer,uint16_t buffer_size)2435deb0bb6SMatthias Ringwald static uint16_t bass_server_copy_source_to_buffer(bass_server_source_t * source, uint16_t buffer_offset, uint8_t * buffer, uint16_t buffer_size){
2445deb0bb6SMatthias Ringwald uint8_t field_data[16];
2455deb0bb6SMatthias Ringwald uint16_t source_offset = 0;
2465deb0bb6SMatthias Ringwald uint16_t stored_bytes = 0;
2475deb0bb6SMatthias Ringwald memset(buffer, 0, buffer_size);
2485deb0bb6SMatthias Ringwald
2495deb0bb6SMatthias Ringwald if (!source->in_use){
2505deb0bb6SMatthias Ringwald return 0;
2515deb0bb6SMatthias Ringwald }
2525deb0bb6SMatthias Ringwald field_data[0] = source->source_id;
25354461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
25454461c80SMatthias Ringwald buffer_offset);
2555deb0bb6SMatthias Ringwald source_offset++;
2565deb0bb6SMatthias Ringwald
2576e96f7c7SMatthias Ringwald stored_bytes += bass_util_source_data_header_virtual_memcpy(&source->data, &source_offset, buffer_offset, buffer,
2586e96f7c7SMatthias Ringwald buffer_size);
2595deb0bb6SMatthias Ringwald
2605deb0bb6SMatthias Ringwald field_data[0] = (uint8_t)source->data.pa_sync_state;
26154461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
26254461c80SMatthias Ringwald buffer_offset);
2635deb0bb6SMatthias Ringwald source_offset++;
2645deb0bb6SMatthias Ringwald
2655deb0bb6SMatthias Ringwald field_data[0] = (uint8_t)source->big_encryption;
26654461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
26754461c80SMatthias Ringwald buffer_offset);
2685deb0bb6SMatthias Ringwald source_offset++;
2695deb0bb6SMatthias Ringwald
2705deb0bb6SMatthias Ringwald if (source->big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){
2715deb0bb6SMatthias Ringwald reverse_128(source->bad_code, &field_data[0]);
27254461c80SMatthias Ringwald stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 16, source_offset, buffer, buffer_size,
27354461c80SMatthias Ringwald buffer_offset);
2745deb0bb6SMatthias Ringwald source_offset += 16;
2755deb0bb6SMatthias Ringwald }
2765deb0bb6SMatthias Ringwald
2776e96f7c7SMatthias Ringwald stored_bytes += bass_util_source_data_subgroups_virtual_memcpy(&source->data, true, &source_offset, buffer_offset,
2785deb0bb6SMatthias Ringwald buffer,
2795deb0bb6SMatthias Ringwald buffer_size);
2805deb0bb6SMatthias Ringwald return stored_bytes;
2815deb0bb6SMatthias Ringwald }
2825deb0bb6SMatthias Ringwald
bass_server_read_callback(hci_con_handle_t con_handle,uint16_t attribute_handle,uint16_t offset,uint8_t * buffer,uint16_t buffer_size)283c4f227dfSMilanka Ringwald static uint16_t bass_server_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
2845deb0bb6SMatthias Ringwald UNUSED(con_handle);
2855deb0bb6SMatthias Ringwald
2867f95ef04SMilanka Ringwald bass_server_source_t * source = bass_server_find_receive_state_for_value_handle(attribute_handle);
2875deb0bb6SMatthias Ringwald if (source){
2885deb0bb6SMatthias Ringwald return bass_server_copy_source_to_buffer(source, offset, buffer, buffer_size);
2895deb0bb6SMatthias Ringwald }
2905deb0bb6SMatthias Ringwald
291c4f227dfSMilanka Ringwald source = bass_server_find_receive_state_for_client_configuration_handle(attribute_handle);
2925deb0bb6SMatthias Ringwald if (source){
2935deb0bb6SMatthias Ringwald return att_read_callback_handle_little_endian_16(source->bass_receive_state_client_configuration, offset, buffer, buffer_size);
2945deb0bb6SMatthias Ringwald }
2955deb0bb6SMatthias Ringwald
2965deb0bb6SMatthias Ringwald return 0;
2975deb0bb6SMatthias Ringwald }
2985deb0bb6SMatthias Ringwald
bass_server_source_remote_modify_source_buffer_valid(uint8_t * buffer,uint16_t buffer_size)299c4f227dfSMilanka Ringwald static bool bass_server_source_remote_modify_source_buffer_valid(uint8_t *buffer, uint16_t buffer_size){
3002d612fc8SMatthias Ringwald if (buffer_size < 5){
3015deb0bb6SMatthias Ringwald log_info("Modify Source opcode, buffer too small");
3025deb0bb6SMatthias Ringwald return false;
3035deb0bb6SMatthias Ringwald }
3045deb0bb6SMatthias Ringwald
3055deb0bb6SMatthias Ringwald uint8_t pos = 1; // source_id
3065deb0bb6SMatthias Ringwald return bass_util_pa_sync_state_and_subgroups_in_valid_range(buffer+pos, buffer_size-pos);
3075deb0bb6SMatthias Ringwald }
3085deb0bb6SMatthias Ringwald
bass_server_add_source_from_buffer(uint8_t * buffer,uint16_t buffer_size,bass_server_source_t * source)3095deb0bb6SMatthias Ringwald static void bass_server_add_source_from_buffer(uint8_t *buffer, uint16_t buffer_size, bass_server_source_t * source){
3105deb0bb6SMatthias Ringwald UNUSED(buffer_size);
3115deb0bb6SMatthias Ringwald
312c4f227dfSMilanka Ringwald source->update_counter = bass_server_get_next_update_counter();
3135deb0bb6SMatthias Ringwald source->in_use = true;
3145deb0bb6SMatthias Ringwald
3156e96f7c7SMatthias Ringwald bass_util_source_data_parse(buffer, buffer_size, &source->data, false);
3165deb0bb6SMatthias Ringwald }
3175deb0bb6SMatthias Ringwald
bass_server_pa_synchronized(bass_server_source_t * source)318c4f227dfSMilanka Ringwald static bool bass_server_pa_synchronized(bass_server_source_t * source){
3195deb0bb6SMatthias Ringwald return source->data.pa_sync_state == LE_AUDIO_PA_SYNC_STATE_SYNCHRONIZED_TO_PA;
3205deb0bb6SMatthias Ringwald }
3215deb0bb6SMatthias Ringwald
3225deb0bb6SMatthias Ringwald
bass_server_bis_synchronized(bass_server_source_t * source)323c4f227dfSMilanka Ringwald static bool bass_server_bis_synchronized(bass_server_source_t * source){
3245deb0bb6SMatthias Ringwald uint8_t i;
3255deb0bb6SMatthias Ringwald for (i = 0; i < source->data.subgroups_num; i++){
3265deb0bb6SMatthias Ringwald if ((source->data.subgroups[i].bis_sync_state > 0) && (source->data.subgroups[i].bis_sync_state < 0xFFFFFFFF)){
3275deb0bb6SMatthias Ringwald return true;
3285deb0bb6SMatthias Ringwald }
3295deb0bb6SMatthias Ringwald }
3305deb0bb6SMatthias Ringwald return false;
3315deb0bb6SMatthias Ringwald }
3325deb0bb6SMatthias Ringwald
3335deb0bb6SMatthias Ringwald
bass_server_reset_source(bass_server_source_t * source)334c4f227dfSMilanka Ringwald static void bass_server_reset_source(bass_server_source_t * source){
3355deb0bb6SMatthias Ringwald source->in_use = false;
3365deb0bb6SMatthias Ringwald source->data.address_type = BD_ADDR_TYPE_LE_PUBLIC;
3375deb0bb6SMatthias Ringwald memset(source->data.address, 0, sizeof(source->data.address));
3385deb0bb6SMatthias Ringwald source->data.adv_sid = 0;
3395deb0bb6SMatthias Ringwald source->data.broadcast_id = 0;
3405deb0bb6SMatthias Ringwald source->data.pa_sync = LE_AUDIO_PA_SYNC_DO_NOT_SYNCHRONIZE_TO_PA;
3415deb0bb6SMatthias Ringwald source->data.pa_sync_state = LE_AUDIO_PA_SYNC_STATE_NOT_SYNCHRONIZED_TO_PA;
3425deb0bb6SMatthias Ringwald source->big_encryption = LE_AUDIO_BIG_ENCRYPTION_NOT_ENCRYPTED;
3435deb0bb6SMatthias Ringwald memset(source->bad_code, 0, sizeof(source->bad_code));
3445deb0bb6SMatthias Ringwald source->data.pa_interval = 0;
3455deb0bb6SMatthias Ringwald source->data.subgroups_num = 0;
3465deb0bb6SMatthias Ringwald memset(source->data.subgroups, 0, sizeof(source->data.subgroups));
3475deb0bb6SMatthias Ringwald }
3485deb0bb6SMatthias Ringwald
bass_server_reset_client_long_write_buffer(bass_server_connection_t * client)3497f95ef04SMilanka Ringwald static void bass_server_reset_client_long_write_buffer(bass_server_connection_t * client){
3505deb0bb6SMatthias Ringwald memset(client->long_write_buffer, 0, sizeof(client->long_write_buffer));
3515deb0bb6SMatthias Ringwald client->long_write_value_size = 0;
3525deb0bb6SMatthias Ringwald }
3535deb0bb6SMatthias Ringwald
bass_server_write_callback(hci_con_handle_t con_handle,uint16_t attribute_handle,uint16_t transaction_mode,uint16_t offset,uint8_t * buffer,uint16_t buffer_size)354c4f227dfSMilanka Ringwald static int bass_server_write_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){
355c4f227dfSMilanka Ringwald // printf("bass_server_write_callback con_handle 0x%02x, attr_handle 0x%02x \n", con_handle, attribute_handle);
3565deb0bb6SMatthias Ringwald if (attribute_handle != 0 && attribute_handle != bass_audio_scan_control_point_handle){
357c4f227dfSMilanka Ringwald bass_server_source_t * source = bass_server_find_receive_state_for_client_configuration_handle(attribute_handle);
3585deb0bb6SMatthias Ringwald if (source){
3595deb0bb6SMatthias Ringwald source->bass_receive_state_client_configuration = little_endian_read_16(buffer, 0);
360c4f227dfSMilanka Ringwald bass_server_register_con_handle(con_handle, source->bass_receive_state_client_configuration);
3615deb0bb6SMatthias Ringwald }
3625deb0bb6SMatthias Ringwald return 0;
3635deb0bb6SMatthias Ringwald }
3645deb0bb6SMatthias Ringwald
3657f95ef04SMilanka Ringwald bass_server_connection_t * connection = bass_server_find_client_for_con_handle(con_handle);
3667f95ef04SMilanka Ringwald if (connection == NULL){
3675deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
3685deb0bb6SMatthias Ringwald }
3695deb0bb6SMatthias Ringwald
3705deb0bb6SMatthias Ringwald uint16_t total_value_len = buffer_size + offset;
3715deb0bb6SMatthias Ringwald
3725deb0bb6SMatthias Ringwald switch (transaction_mode){
3735deb0bb6SMatthias Ringwald case ATT_TRANSACTION_MODE_NONE:
3747f95ef04SMilanka Ringwald if (buffer_size > sizeof(connection->long_write_buffer)){
3757f95ef04SMilanka Ringwald bass_server_reset_client_long_write_buffer(connection);
3765deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
3775deb0bb6SMatthias Ringwald }
3787f95ef04SMilanka Ringwald memcpy(&connection->long_write_buffer[0], buffer, buffer_size);
3797f95ef04SMilanka Ringwald connection->long_write_value_size = total_value_len;
3805deb0bb6SMatthias Ringwald break;
3815deb0bb6SMatthias Ringwald
3825deb0bb6SMatthias Ringwald case ATT_TRANSACTION_MODE_ACTIVE:
3837f95ef04SMilanka Ringwald if (total_value_len > sizeof(connection->long_write_buffer)){
3847f95ef04SMilanka Ringwald bass_server_reset_client_long_write_buffer(connection);
3855deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
3865deb0bb6SMatthias Ringwald }
3875deb0bb6SMatthias Ringwald // allow overlapped and/or mixed order chunks
3887f95ef04SMilanka Ringwald connection->long_write_attribute_handle = attribute_handle;
3895deb0bb6SMatthias Ringwald
3907f95ef04SMilanka Ringwald memcpy(&connection->long_write_buffer[offset], buffer, buffer_size);
3917f95ef04SMilanka Ringwald if (total_value_len > connection->long_write_value_size){
3927f95ef04SMilanka Ringwald connection->long_write_value_size = total_value_len;
3935deb0bb6SMatthias Ringwald }
3945deb0bb6SMatthias Ringwald return 0;
3955deb0bb6SMatthias Ringwald
3965deb0bb6SMatthias Ringwald case ATT_TRANSACTION_MODE_VALIDATE:
3975deb0bb6SMatthias Ringwald return 0;
3985deb0bb6SMatthias Ringwald
3995deb0bb6SMatthias Ringwald case ATT_TRANSACTION_MODE_EXECUTE:
4007f95ef04SMilanka Ringwald attribute_handle = connection->long_write_attribute_handle;
4015deb0bb6SMatthias Ringwald break;
4025deb0bb6SMatthias Ringwald
4035deb0bb6SMatthias Ringwald default:
4045deb0bb6SMatthias Ringwald return 0;
4055deb0bb6SMatthias Ringwald }
4065deb0bb6SMatthias Ringwald
4075deb0bb6SMatthias Ringwald if (attribute_handle == bass_audio_scan_control_point_handle){
4087f95ef04SMilanka Ringwald if (connection->long_write_value_size < 2){
4095deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
4105deb0bb6SMatthias Ringwald }
4115deb0bb6SMatthias Ringwald
4127f95ef04SMilanka Ringwald bass_opcode_t opcode = (bass_opcode_t)connection->long_write_buffer[0];
4137f95ef04SMilanka Ringwald uint8_t *remote_data = &connection->long_write_buffer[1];
4147f95ef04SMilanka Ringwald uint16_t remote_data_size = connection->long_write_value_size - 1;
4155deb0bb6SMatthias Ringwald
4165deb0bb6SMatthias Ringwald bass_server_source_t * source;
4175deb0bb6SMatthias Ringwald uint8_t broadcast_code[16];
4185deb0bb6SMatthias Ringwald switch (opcode){
4195deb0bb6SMatthias Ringwald case BASS_OPCODE_REMOTE_SCAN_STOPPED:
4205deb0bb6SMatthias Ringwald if (remote_data_size != 1){
4215deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
4225deb0bb6SMatthias Ringwald }
423c4f227dfSMilanka Ringwald bass_server_source_emit_scan_stoped(con_handle);
4245deb0bb6SMatthias Ringwald break;
4255deb0bb6SMatthias Ringwald
4265deb0bb6SMatthias Ringwald case BASS_OPCODE_REMOTE_SCAN_STARTED:
4275deb0bb6SMatthias Ringwald if (remote_data_size != 1){
4285deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
4295deb0bb6SMatthias Ringwald }
430c4f227dfSMilanka Ringwald bass_server_source_emit_scan_started(con_handle);
4315deb0bb6SMatthias Ringwald break;
4325deb0bb6SMatthias Ringwald
4335deb0bb6SMatthias Ringwald case BASS_OPCODE_ADD_SOURCE:
4346e96f7c7SMatthias Ringwald if (!bass_util_source_buffer_in_valid_range(remote_data, remote_data_size)){
4355deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
4365deb0bb6SMatthias Ringwald }
437c4f227dfSMilanka Ringwald source = bass_server_find_empty_or_last_used_source();
4385deb0bb6SMatthias Ringwald btstack_assert(source != NULL);
4395deb0bb6SMatthias Ringwald log_info("add source %d", source->source_id);
4405deb0bb6SMatthias Ringwald bass_server_add_source_from_buffer(remote_data, remote_data_size, source);
441c4f227dfSMilanka Ringwald bass_server_source_emit_source_added(con_handle, source);
4425deb0bb6SMatthias Ringwald // server needs to trigger notification
4435deb0bb6SMatthias Ringwald break;
4445deb0bb6SMatthias Ringwald
4455deb0bb6SMatthias Ringwald case BASS_OPCODE_MODIFY_SOURCE:
446c4f227dfSMilanka Ringwald if (!bass_server_source_remote_modify_source_buffer_valid(remote_data, remote_data_size)){
4475deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
4485deb0bb6SMatthias Ringwald }
4495deb0bb6SMatthias Ringwald
450c4f227dfSMilanka Ringwald source = bass_server_find_source_for_source_id(remote_data[0]);
4515deb0bb6SMatthias Ringwald if (source == NULL){
4525deb0bb6SMatthias Ringwald return BASS_ERROR_CODE_INVALID_SOURCE_ID;
4535deb0bb6SMatthias Ringwald }
4546e96f7c7SMatthias Ringwald bass_util_pa_info_and_subgroups_parse(remote_data + 1, remote_data_size - 1, &source->data, false);
455c4f227dfSMilanka Ringwald bass_server_source_emit_source_modified(con_handle, source);
4565deb0bb6SMatthias Ringwald // server needs to trigger notification
4575deb0bb6SMatthias Ringwald break;
4585deb0bb6SMatthias Ringwald
4595deb0bb6SMatthias Ringwald case BASS_OPCODE_SET_BROADCAST_CODE:
4605deb0bb6SMatthias Ringwald if (remote_data_size != 17){
4615deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
4625deb0bb6SMatthias Ringwald }
4635deb0bb6SMatthias Ringwald
464c4f227dfSMilanka Ringwald source = bass_server_find_source_for_source_id(remote_data[0]);
4655deb0bb6SMatthias Ringwald if (source == NULL){
4665deb0bb6SMatthias Ringwald return BASS_ERROR_CODE_INVALID_SOURCE_ID;
4675deb0bb6SMatthias Ringwald }
4685deb0bb6SMatthias Ringwald reverse_128(&remote_data[1], broadcast_code);
469c4f227dfSMilanka Ringwald bass_server_source_emit_broadcast_code(con_handle, source->source_id, broadcast_code);
4705deb0bb6SMatthias Ringwald break;
4715deb0bb6SMatthias Ringwald
4725deb0bb6SMatthias Ringwald case BASS_OPCODE_REMOVE_SOURCE:
4735deb0bb6SMatthias Ringwald if (remote_data_size != 1){
4745deb0bb6SMatthias Ringwald return ATT_ERROR_WRITE_REQUEST_REJECTED;
4755deb0bb6SMatthias Ringwald }
476c4f227dfSMilanka Ringwald source = bass_server_find_source_for_source_id(remote_data[0]);
4775deb0bb6SMatthias Ringwald if (source == NULL){
4785deb0bb6SMatthias Ringwald return BASS_ERROR_CODE_INVALID_SOURCE_ID;
4795deb0bb6SMatthias Ringwald }
4805deb0bb6SMatthias Ringwald
481c4f227dfSMilanka Ringwald if (bass_server_pa_synchronized(source)){
4825deb0bb6SMatthias Ringwald log_info("remove source %d rejected, PA synchronised", source->source_id);
4835deb0bb6SMatthias Ringwald return 0;
4845deb0bb6SMatthias Ringwald }
4855deb0bb6SMatthias Ringwald
486c4f227dfSMilanka Ringwald if (bass_server_bis_synchronized(source)){
4875deb0bb6SMatthias Ringwald log_info("remove source %d rejected, BIS synchronised", source->source_id);
4885deb0bb6SMatthias Ringwald return 0;
4895deb0bb6SMatthias Ringwald }
4905deb0bb6SMatthias Ringwald
491c4f227dfSMilanka Ringwald bass_server_reset_source(source);
4925deb0bb6SMatthias Ringwald broadcast_audio_scan_service_server_set_pa_sync_state(source->source_id, LE_AUDIO_PA_SYNC_STATE_NOT_SYNCHRONIZED_TO_PA);
493c4f227dfSMilanka Ringwald bass_server_source_emit_source_deleted(con_handle, source);
4945deb0bb6SMatthias Ringwald break;
4955deb0bb6SMatthias Ringwald
4965deb0bb6SMatthias Ringwald default:
4977f95ef04SMilanka Ringwald bass_server_reset_client_long_write_buffer(connection);
4985deb0bb6SMatthias Ringwald return BASS_ERROR_CODE_OPCODE_NOT_SUPPORTED;
4995deb0bb6SMatthias Ringwald }
5007f95ef04SMilanka Ringwald bass_server_reset_client_long_write_buffer(connection);
5015deb0bb6SMatthias Ringwald }
5025deb0bb6SMatthias Ringwald return 0;
5035deb0bb6SMatthias Ringwald }
5045deb0bb6SMatthias Ringwald
bass_server_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)505c4f227dfSMilanka Ringwald static void bass_server_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
5065deb0bb6SMatthias Ringwald UNUSED(channel);
5075deb0bb6SMatthias Ringwald UNUSED(packet);
5085deb0bb6SMatthias Ringwald UNUSED(size);
5095deb0bb6SMatthias Ringwald
5105deb0bb6SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET){
5115deb0bb6SMatthias Ringwald return;
5125deb0bb6SMatthias Ringwald }
5135deb0bb6SMatthias Ringwald
5145deb0bb6SMatthias Ringwald hci_con_handle_t con_handle;
5157f95ef04SMilanka Ringwald bass_server_connection_t * connection;
5165deb0bb6SMatthias Ringwald
5175deb0bb6SMatthias Ringwald switch (hci_event_packet_get_type(packet)) {
5185deb0bb6SMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE:
5195deb0bb6SMatthias Ringwald con_handle = hci_event_disconnection_complete_get_connection_handle(packet);
5205deb0bb6SMatthias Ringwald
5217f95ef04SMilanka Ringwald connection = bass_server_find_client_for_con_handle(con_handle);
5227f95ef04SMilanka Ringwald if (connection == NULL){
5235deb0bb6SMatthias Ringwald break;
5245deb0bb6SMatthias Ringwald }
5255deb0bb6SMatthias Ringwald
5267f95ef04SMilanka Ringwald memset(connection, 0, sizeof(bass_server_connection_t));
5277f95ef04SMilanka Ringwald connection->con_handle = HCI_CON_HANDLE_INVALID;
5285deb0bb6SMatthias Ringwald break;
5295deb0bb6SMatthias Ringwald default:
5305deb0bb6SMatthias Ringwald break;
5315deb0bb6SMatthias Ringwald }
5325deb0bb6SMatthias Ringwald }
5335deb0bb6SMatthias Ringwald
broadcast_audio_scan_service_server_init(const uint8_t sources_num,bass_server_source_t * sources,const uint8_t clients_num,bass_server_connection_t * clients)5347f95ef04SMilanka Ringwald void broadcast_audio_scan_service_server_init(const uint8_t sources_num, bass_server_source_t * sources, const uint8_t clients_num, bass_server_connection_t * clients){
5355deb0bb6SMatthias Ringwald // get service handle range
5365deb0bb6SMatthias Ringwald btstack_assert(sources_num != 0);
5375deb0bb6SMatthias Ringwald btstack_assert(clients_num != 0);
5385deb0bb6SMatthias Ringwald
5395deb0bb6SMatthias Ringwald uint16_t start_handle = 0;
5405deb0bb6SMatthias Ringwald uint16_t end_handle = 0xffff;
5415deb0bb6SMatthias Ringwald bool service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE, &start_handle, &end_handle);
5425deb0bb6SMatthias Ringwald btstack_assert(service_found);
5435deb0bb6SMatthias Ringwald
5445deb0bb6SMatthias Ringwald UNUSED(service_found);
5455deb0bb6SMatthias Ringwald
5465deb0bb6SMatthias Ringwald bass_audio_scan_control_point_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_AUDIO_SCAN_CONTROL_POINT);
5475deb0bb6SMatthias Ringwald bass_sources_num = 0;
5485deb0bb6SMatthias Ringwald bass_logic_time = 0;
5495deb0bb6SMatthias Ringwald bass_sources = sources;
5505deb0bb6SMatthias Ringwald
5515deb0bb6SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
5525deb0bb6SMatthias Ringwald printf("BASS 0x%02x - 0x%02x \n", start_handle, end_handle);
5535deb0bb6SMatthias Ringwald #endif
5545deb0bb6SMatthias Ringwald uint16_t start_chr_handle = start_handle;
5555deb0bb6SMatthias Ringwald while ( (start_chr_handle < end_handle) && (bass_sources_num < sources_num )) {
5565deb0bb6SMatthias Ringwald uint16_t chr_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_chr_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE);
5575deb0bb6SMatthias Ringwald uint16_t chr_client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_chr_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE);
5585deb0bb6SMatthias Ringwald
5595deb0bb6SMatthias Ringwald if (chr_value_handle == 0){
5605deb0bb6SMatthias Ringwald break;
5615deb0bb6SMatthias Ringwald }
5625deb0bb6SMatthias Ringwald bass_server_source_t * source = &bass_sources[bass_sources_num];
563c4f227dfSMilanka Ringwald bass_server_reset_source(source);
5645deb0bb6SMatthias Ringwald
5655deb0bb6SMatthias Ringwald source->source_id = bass_sources_num;
566c4f227dfSMilanka Ringwald source->update_counter = bass_server_get_next_update_counter();
5675deb0bb6SMatthias Ringwald source->bass_receive_state_client_configuration = 0;
5685deb0bb6SMatthias Ringwald
5695deb0bb6SMatthias Ringwald source->bass_receive_state_handle = chr_value_handle;
5705deb0bb6SMatthias Ringwald source->bass_receive_state_client_configuration_handle = chr_client_configuration_handle;
5715deb0bb6SMatthias Ringwald
5725deb0bb6SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
5735deb0bb6SMatthias Ringwald printf(" bass_receive_state_%d 0x%02x \n", bass_sources_num, source->bass_receive_state_handle);
5745deb0bb6SMatthias Ringwald printf(" bass_receive_state_%d CCC 0x%02x \n", bass_sources_num, source->bass_receive_state_client_configuration_handle);
5755deb0bb6SMatthias Ringwald #endif
5765deb0bb6SMatthias Ringwald
5775deb0bb6SMatthias Ringwald start_chr_handle = chr_client_configuration_handle + 1;
5785deb0bb6SMatthias Ringwald bass_sources_num++;
5795deb0bb6SMatthias Ringwald }
5805deb0bb6SMatthias Ringwald
5815deb0bb6SMatthias Ringwald bass_clients_num = clients_num;
5825deb0bb6SMatthias Ringwald bass_clients = clients;
5837f95ef04SMilanka Ringwald memset(bass_clients, 0, sizeof(bass_server_connection_t) * bass_clients_num);
5845deb0bb6SMatthias Ringwald uint8_t i;
5855deb0bb6SMatthias Ringwald for (i = 0; i < bass_clients_num; i++){
5865deb0bb6SMatthias Ringwald bass_clients[i].con_handle = HCI_CON_HANDLE_INVALID;
5875deb0bb6SMatthias Ringwald }
5885deb0bb6SMatthias Ringwald
5895deb0bb6SMatthias Ringwald log_info("Found BASS service 0x%02x-0x%02x (num sources %d)", start_handle, end_handle, bass_sources_num);
5905deb0bb6SMatthias Ringwald
5915deb0bb6SMatthias Ringwald // register service with ATT Server
5925deb0bb6SMatthias Ringwald broadcast_audio_scan_service.start_handle = start_handle;
5935deb0bb6SMatthias Ringwald broadcast_audio_scan_service.end_handle = end_handle;
594c4f227dfSMilanka Ringwald broadcast_audio_scan_service.read_callback = &bass_server_read_callback;
595c4f227dfSMilanka Ringwald broadcast_audio_scan_service.write_callback = &bass_server_write_callback;
596c4f227dfSMilanka Ringwald broadcast_audio_scan_service.packet_handler = bass_server_packet_handler;
5975deb0bb6SMatthias Ringwald att_server_register_service_handler(&broadcast_audio_scan_service);
5985deb0bb6SMatthias Ringwald }
5995deb0bb6SMatthias Ringwald
broadcast_audio_scan_service_server_register_packet_handler(btstack_packet_handler_t packet_handler)600b973a76fSMilanka Ringwald void broadcast_audio_scan_service_server_register_packet_handler(btstack_packet_handler_t packet_handler){
601b973a76fSMilanka Ringwald btstack_assert(packet_handler != NULL);
602c4f227dfSMilanka Ringwald bass_server_event_callback = packet_handler;
6035deb0bb6SMatthias Ringwald }
6045deb0bb6SMatthias Ringwald
bass_service_can_send_now(void * context)6055deb0bb6SMatthias Ringwald static void bass_service_can_send_now(void * context){
6067f95ef04SMilanka Ringwald bass_server_connection_t * client = (bass_server_connection_t *) context;
6075deb0bb6SMatthias Ringwald btstack_assert(client != NULL);
6085deb0bb6SMatthias Ringwald
6095deb0bb6SMatthias Ringwald uint8_t source_index;
6105deb0bb6SMatthias Ringwald for (source_index = 0; source_index < bass_sources_num; source_index++){
6115deb0bb6SMatthias Ringwald uint8_t task = (1 << source_index);
6125deb0bb6SMatthias Ringwald if ((client->sources_to_notify & task) != 0){
6135deb0bb6SMatthias Ringwald client->sources_to_notify &= ~task;
6145deb0bb6SMatthias Ringwald uint8_t buffer[BASS_MAX_NOTIFY_BUFFER_SIZE];
6155deb0bb6SMatthias Ringwald uint16_t bytes_copied = bass_server_copy_source_to_buffer(&bass_sources[source_index], 0, buffer, sizeof(buffer));
6165deb0bb6SMatthias Ringwald att_server_notify(client->con_handle, bass_sources[source_index].bass_receive_state_handle, &buffer[0], bytes_copied);
6175deb0bb6SMatthias Ringwald return;
6185deb0bb6SMatthias Ringwald }
6195deb0bb6SMatthias Ringwald }
6205deb0bb6SMatthias Ringwald
6215deb0bb6SMatthias Ringwald uint8_t i;
6225deb0bb6SMatthias Ringwald for (i = 0; i < bass_clients_num; i++){
6235deb0bb6SMatthias Ringwald client = &bass_clients[i];
6245deb0bb6SMatthias Ringwald
6255deb0bb6SMatthias Ringwald if (client->sources_to_notify != 0){
6265deb0bb6SMatthias Ringwald scheduled_tasks_callback.callback = &bass_service_can_send_now;
6275deb0bb6SMatthias Ringwald scheduled_tasks_callback.context = (void*) client;
6285deb0bb6SMatthias Ringwald att_server_register_can_send_now_callback(&scheduled_tasks_callback, client->con_handle);
6295deb0bb6SMatthias Ringwald return;
6305deb0bb6SMatthias Ringwald }
6315deb0bb6SMatthias Ringwald }
6325deb0bb6SMatthias Ringwald }
6335deb0bb6SMatthias Ringwald
bass_server_set_callback(uint8_t source_index)634c4f227dfSMilanka Ringwald static void bass_server_set_callback(uint8_t source_index){
6355deb0bb6SMatthias Ringwald // there is only one type of task: notify on source state change
6365deb0bb6SMatthias Ringwald // as task we register which source is changed, and the change will be propagated to all clients
6375deb0bb6SMatthias Ringwald uint8_t i;
6385deb0bb6SMatthias Ringwald uint8_t task = (1 << source_index);
6395deb0bb6SMatthias Ringwald
6405deb0bb6SMatthias Ringwald uint8_t scheduled_tasks = 0;
6415deb0bb6SMatthias Ringwald
6425deb0bb6SMatthias Ringwald for (i = 0; i < bass_clients_num; i++){
6437f95ef04SMilanka Ringwald bass_server_connection_t * connection = &bass_clients[i];
6445deb0bb6SMatthias Ringwald
6457f95ef04SMilanka Ringwald if (connection->con_handle == HCI_CON_HANDLE_INVALID){
6467f95ef04SMilanka Ringwald connection->sources_to_notify &= ~task;
6475deb0bb6SMatthias Ringwald return;
6485deb0bb6SMatthias Ringwald }
6495deb0bb6SMatthias Ringwald
6507f95ef04SMilanka Ringwald scheduled_tasks |= connection->sources_to_notify;
6517f95ef04SMilanka Ringwald connection->sources_to_notify |= task;
6525deb0bb6SMatthias Ringwald
6535deb0bb6SMatthias Ringwald if (scheduled_tasks == 0){
6545deb0bb6SMatthias Ringwald scheduled_tasks_callback.callback = &bass_service_can_send_now;
6557f95ef04SMilanka Ringwald scheduled_tasks_callback.context = (void*) connection;
6567f95ef04SMilanka Ringwald att_server_register_can_send_now_callback(&scheduled_tasks_callback, connection->con_handle);
6575deb0bb6SMatthias Ringwald }
6585deb0bb6SMatthias Ringwald }
6595deb0bb6SMatthias Ringwald }
6605deb0bb6SMatthias Ringwald
broadcast_audio_scan_service_server_set_pa_sync_state(uint8_t source_index,le_audio_pa_sync_state_t sync_state)6615deb0bb6SMatthias Ringwald void broadcast_audio_scan_service_server_set_pa_sync_state(uint8_t source_index, le_audio_pa_sync_state_t sync_state){
6625deb0bb6SMatthias Ringwald btstack_assert(source_index < bass_sources_num);
6635deb0bb6SMatthias Ringwald
6645deb0bb6SMatthias Ringwald bass_server_source_t * source = &bass_sources[source_index];
6655deb0bb6SMatthias Ringwald source->data.pa_sync_state = sync_state;
6665deb0bb6SMatthias Ringwald
6675deb0bb6SMatthias Ringwald if (source->bass_receive_state_client_configuration != 0){
668c4f227dfSMilanka Ringwald bass_server_set_callback(source_index);
6695deb0bb6SMatthias Ringwald }
6705deb0bb6SMatthias Ringwald }
6715deb0bb6SMatthias Ringwald
broadcast_audio_scan_service_server_add_source(const bass_source_data_t * source_data,uint8_t * source_index)6728d085b97SMatthias Ringwald void broadcast_audio_scan_service_server_add_source(const bass_source_data_t *source_data, uint8_t * source_index){
673c4f227dfSMilanka Ringwald *source_index = bass_server_find_empty_or_last_used_source_index();
6745deb0bb6SMatthias Ringwald if (*source_index == BASS_INVALID_SOURCE_INDEX){
6755deb0bb6SMatthias Ringwald return;
6765deb0bb6SMatthias Ringwald }
6775deb0bb6SMatthias Ringwald bass_server_source_t * last_used_source = &bass_sources[*source_index];
678c4f227dfSMilanka Ringwald last_used_source->update_counter = bass_server_get_next_update_counter();
6795deb0bb6SMatthias Ringwald last_used_source->in_use = true;
6805deb0bb6SMatthias Ringwald last_used_source->source_id = *source_index;
6818d085b97SMatthias Ringwald memcpy(&last_used_source->data, source_data, sizeof(bass_source_data_t));
6825deb0bb6SMatthias Ringwald }
6835deb0bb6SMatthias Ringwald
broadcast_audio_scan_service_server_deinit(void)6845deb0bb6SMatthias Ringwald void broadcast_audio_scan_service_server_deinit(void){
6857f95ef04SMilanka Ringwald bass_server_event_callback = NULL;
6865deb0bb6SMatthias Ringwald }
687