1*10277393SMatthias Ringwald /* 2*10277393SMatthias Ringwald * Copyright (C) 2022 BlueKitchen GmbH 3*10277393SMatthias Ringwald * 4*10277393SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*10277393SMatthias Ringwald * modification, are permitted provided that the following conditions 6*10277393SMatthias Ringwald * are met: 7*10277393SMatthias Ringwald * 8*10277393SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*10277393SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*10277393SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*10277393SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*10277393SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*10277393SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*10277393SMatthias Ringwald * contributors may be used to endorse or promote products derived 15*10277393SMatthias Ringwald * from this software without specific prior written permission. 16*10277393SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*10277393SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*10277393SMatthias Ringwald * monetary gain. 19*10277393SMatthias Ringwald * 20*10277393SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*10277393SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*10277393SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*10277393SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*10277393SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*10277393SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*10277393SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*10277393SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*10277393SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*10277393SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*10277393SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*10277393SMatthias Ringwald * SUCH DAMAGE. 32*10277393SMatthias Ringwald * 33*10277393SMatthias Ringwald * Please inquire about commercial licensing options at 34*10277393SMatthias Ringwald * [email protected] 35*10277393SMatthias Ringwald * 36*10277393SMatthias Ringwald */ 37*10277393SMatthias Ringwald 38*10277393SMatthias Ringwald #define BTSTACK_FILE__ "le_audio_broadcast_sink.c" 39*10277393SMatthias Ringwald 40*10277393SMatthias Ringwald /* 41*10277393SMatthias Ringwald * LE Audio Broadcast Sink 42*10277393SMatthias Ringwald */ 43*10277393SMatthias Ringwald 44*10277393SMatthias Ringwald 45*10277393SMatthias Ringwald #include "btstack_config.h" 46*10277393SMatthias Ringwald 47*10277393SMatthias Ringwald #include <stdint.h> 48*10277393SMatthias Ringwald #include <stdio.h> 49*10277393SMatthias Ringwald #include <stdlib.h> 50*10277393SMatthias Ringwald #include <string.h> 51*10277393SMatthias Ringwald #include <unistd.h> 52*10277393SMatthias Ringwald #include <inttypes.h> 53*10277393SMatthias Ringwald #include <fcntl.h> // open 54*10277393SMatthias Ringwald #include <errno.h> 55*10277393SMatthias Ringwald 56*10277393SMatthias Ringwald #include "ad_parser.h" 57*10277393SMatthias Ringwald #include "bluetooth_data_types.h" 58*10277393SMatthias Ringwald #include "bluetooth_gatt.h" 59*10277393SMatthias Ringwald #include "btstack_debug.h" 60*10277393SMatthias Ringwald #include "btstack_audio.h" 61*10277393SMatthias Ringwald #include "btstack_event.h" 62*10277393SMatthias Ringwald #include "btstack_run_loop.h" 63*10277393SMatthias Ringwald #include "btstack_ring_buffer.h" 64*10277393SMatthias Ringwald #include "btstack_stdin.h" 65*10277393SMatthias Ringwald #include "btstack_util.h" 66*10277393SMatthias Ringwald #include "gap.h" 67*10277393SMatthias Ringwald #include "hci.h" 68*10277393SMatthias Ringwald #include "hci_cmd.h" 69*10277393SMatthias Ringwald #include "lc3.h" 70*10277393SMatthias Ringwald #include "lc3_ehima.h" 71*10277393SMatthias Ringwald #include "wav_util.h" 72*10277393SMatthias Ringwald 73*10277393SMatthias Ringwald // max config 74*10277393SMatthias Ringwald #define MAX_NUM_BIS 2 75*10277393SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480 76*10277393SMatthias Ringwald 77*10277393SMatthias Ringwald #define DUMP_LEN_LC3_FRAMES 1000 78*10277393SMatthias Ringwald 79*10277393SMatthias Ringwald // playback 80*10277393SMatthias Ringwald #define MAX_NUM_LC3_FRAMES 5 81*10277393SMatthias Ringwald #define MAX_BYTES_PER_SAMPLE 4 82*10277393SMatthias Ringwald #define PLAYBACK_BUFFER_SIZE (MAX_NUM_LC3_FRAMES * MAX_SAMPLES_PER_FRAME * MAX_BYTES_PER_SAMPLE) 83*10277393SMatthias Ringwald 84*10277393SMatthias Ringwald // analysis 85*10277393SMatthias Ringwald #define PACKET_PREFIX_LEN 10 86*10277393SMatthias Ringwald 87*10277393SMatthias Ringwald #define ANSI_COLOR_RED "\x1b[31m" 88*10277393SMatthias Ringwald #define ANSI_COLOR_GREEN "\x1b[32m" 89*10277393SMatthias Ringwald #define ANSI_COLOR_YELLOW "\x1b[33m" 90*10277393SMatthias Ringwald #define ANSI_COLOR_BLUE "\x1b[34m" 91*10277393SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m" 92*10277393SMatthias Ringwald #define ANSI_COLOR_CYAN "\x1b[36m" 93*10277393SMatthias Ringwald #define ANSI_COLOR_RESET "\x1b[0m" 94*10277393SMatthias Ringwald 95*10277393SMatthias Ringwald static void show_usage(void); 96*10277393SMatthias Ringwald 97*10277393SMatthias Ringwald static const char * filename_lc3 = "le_audio_broadcast_sink.lc3"; 98*10277393SMatthias Ringwald static const char * filename_wav = "le_audio_broadcast_sink.wav"; 99*10277393SMatthias Ringwald 100*10277393SMatthias Ringwald static enum { 101*10277393SMatthias Ringwald APP_W4_WORKING, 102*10277393SMatthias Ringwald APP_W4_BROADCAST_ADV, 103*10277393SMatthias Ringwald APP_W4_PA_AND_BIG_INFO, 104*10277393SMatthias Ringwald APP_CREATE_BIG_SYNC, 105*10277393SMatthias Ringwald APP_W4_BIG_SYNC_ESTABLISHED, 106*10277393SMatthias Ringwald APP_SET_ISO_PATHS, 107*10277393SMatthias Ringwald APP_STREAMING, 108*10277393SMatthias Ringwald APP_TERMINATE_BIG, 109*10277393SMatthias Ringwald APP_IDLE 110*10277393SMatthias Ringwald } app_state = APP_W4_WORKING; 111*10277393SMatthias Ringwald 112*10277393SMatthias Ringwald // 113*10277393SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 114*10277393SMatthias Ringwald 115*10277393SMatthias Ringwald static bool have_base; 116*10277393SMatthias Ringwald static bool have_big_info; 117*10277393SMatthias Ringwald 118*10277393SMatthias Ringwald uint32_t last_samples_report_ms; 119*10277393SMatthias Ringwald uint32_t samples_received; 120*10277393SMatthias Ringwald uint32_t samples_dropped; 121*10277393SMatthias Ringwald uint16_t frames_per_second[MAX_NUM_BIS]; 122*10277393SMatthias Ringwald 123*10277393SMatthias Ringwald // remote info 124*10277393SMatthias Ringwald static char remote_name[20]; 125*10277393SMatthias Ringwald static bd_addr_t remote; 126*10277393SMatthias Ringwald static bd_addr_type_t remote_type; 127*10277393SMatthias Ringwald static uint8_t remote_sid; 128*10277393SMatthias Ringwald static bool count_mode; 129*10277393SMatthias Ringwald static bool pts_mode; 130*10277393SMatthias Ringwald 131*10277393SMatthias Ringwald // broadcast info 132*10277393SMatthias Ringwald static const uint8_t big_handle = 1; 133*10277393SMatthias Ringwald static hci_con_handle_t sync_handle; 134*10277393SMatthias Ringwald static hci_con_handle_t bis_con_handles[MAX_NUM_BIS]; 135*10277393SMatthias Ringwald static unsigned int next_bis_index; 136*10277393SMatthias Ringwald 137*10277393SMatthias Ringwald // analysis 138*10277393SMatthias Ringwald static uint16_t last_packet_sequence[MAX_NUM_BIS]; 139*10277393SMatthias Ringwald static uint32_t last_packet_time_ms[MAX_NUM_BIS]; 140*10277393SMatthias Ringwald static uint8_t last_packet_prefix[MAX_NUM_BIS * PACKET_PREFIX_LEN]; 141*10277393SMatthias Ringwald 142*10277393SMatthias Ringwald // lc3 writer 143*10277393SMatthias Ringwald static int dump_file; 144*10277393SMatthias Ringwald static uint32_t lc3_frames; 145*10277393SMatthias Ringwald 146*10277393SMatthias Ringwald // lc3 codec config 147*10277393SMatthias Ringwald static uint32_t sampling_frequency_hz; 148*10277393SMatthias Ringwald static lc3_frame_duration_t frame_duration; 149*10277393SMatthias Ringwald static uint16_t number_samples_per_frame; 150*10277393SMatthias Ringwald static uint16_t octets_per_frame; 151*10277393SMatthias Ringwald static uint8_t num_bis; 152*10277393SMatthias Ringwald 153*10277393SMatthias Ringwald // lc3 decoder 154*10277393SMatthias Ringwald static const lc3_decoder_t * lc3_decoder; 155*10277393SMatthias Ringwald static lc3_decoder_ehima_t decoder_contexts[MAX_NUM_BIS]; 156*10277393SMatthias Ringwald static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME]; 157*10277393SMatthias Ringwald 158*10277393SMatthias Ringwald // playback 159*10277393SMatthias Ringwald static uint8_t playback_buffer_storage[PLAYBACK_BUFFER_SIZE]; 160*10277393SMatthias Ringwald static btstack_ring_buffer_t playback_buffer; 161*10277393SMatthias Ringwald 162*10277393SMatthias Ringwald static void le_audio_broadcast_sink_playback(int16_t * buffer, uint16_t num_samples){ 163*10277393SMatthias Ringwald // called from lower-layer but guaranteed to be on main thread 164*10277393SMatthias Ringwald uint32_t bytes_needed = num_samples * num_bis * 2; 165*10277393SMatthias Ringwald 166*10277393SMatthias Ringwald static bool underrun = true; 167*10277393SMatthias Ringwald 168*10277393SMatthias Ringwald log_info("Playback: need %u, have %u", num_samples, btstack_ring_buffer_bytes_available(&playback_buffer) / ( num_bis * 2)); 169*10277393SMatthias Ringwald 170*10277393SMatthias Ringwald if (bytes_needed > btstack_ring_buffer_bytes_available(&playback_buffer)){ 171*10277393SMatthias Ringwald memset(buffer, 0, bytes_needed); 172*10277393SMatthias Ringwald if (underrun == false){ 173*10277393SMatthias Ringwald log_info("Playback underrun"); 174*10277393SMatthias Ringwald underrun = true; 175*10277393SMatthias Ringwald } 176*10277393SMatthias Ringwald return; 177*10277393SMatthias Ringwald } 178*10277393SMatthias Ringwald 179*10277393SMatthias Ringwald if (underrun){ 180*10277393SMatthias Ringwald underrun = false; 181*10277393SMatthias Ringwald log_info("Playback started"); 182*10277393SMatthias Ringwald } 183*10277393SMatthias Ringwald uint32_t bytes_read; 184*10277393SMatthias Ringwald btstack_ring_buffer_read(&playback_buffer, (uint8_t *) buffer, bytes_needed, &bytes_read); 185*10277393SMatthias Ringwald btstack_assert(bytes_read == bytes_needed); 186*10277393SMatthias Ringwald } 187*10277393SMatthias Ringwald 188*10277393SMatthias Ringwald static void open_lc3_file(void) { 189*10277393SMatthias Ringwald // open lc3 file 190*10277393SMatthias Ringwald int oflags = O_WRONLY | O_CREAT | O_TRUNC; 191*10277393SMatthias Ringwald dump_file = open(filename_lc3, oflags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 192*10277393SMatthias Ringwald if (dump_file < 0) { 193*10277393SMatthias Ringwald printf("failed to open file %s, errno = %d\n", filename_lc3, errno); 194*10277393SMatthias Ringwald return; 195*10277393SMatthias Ringwald } 196*10277393SMatthias Ringwald 197*10277393SMatthias Ringwald printf("LC3 binary file: %s\n", filename_lc3); 198*10277393SMatthias Ringwald 199*10277393SMatthias Ringwald // calc bps 200*10277393SMatthias Ringwald uint16_t frame_duration_100us = (frame_duration == LC3_FRAME_DURATION_7500US) ? 75 : 100; 201*10277393SMatthias Ringwald uint32_t bits_per_second = (uint32_t) octets_per_frame * num_bis * 8 * 10000 / frame_duration_100us; 202*10277393SMatthias Ringwald 203*10277393SMatthias Ringwald // write header for floating point implementation 204*10277393SMatthias Ringwald uint8_t header[18]; 205*10277393SMatthias Ringwald little_endian_store_16(header, 0, 0xcc1c); 206*10277393SMatthias Ringwald little_endian_store_16(header, 2, sizeof(header)); 207*10277393SMatthias Ringwald little_endian_store_16(header, 4, sampling_frequency_hz / 100); 208*10277393SMatthias Ringwald little_endian_store_16(header, 6, bits_per_second / 100); 209*10277393SMatthias Ringwald little_endian_store_16(header, 8, num_bis); 210*10277393SMatthias Ringwald little_endian_store_16(header, 10, frame_duration_100us * 10); 211*10277393SMatthias Ringwald little_endian_store_16(header, 12, 0); 212*10277393SMatthias Ringwald little_endian_store_32(header, 14, DUMP_LEN_LC3_FRAMES * number_samples_per_frame); 213*10277393SMatthias Ringwald write(dump_file, header, sizeof(header)); 214*10277393SMatthias Ringwald } 215*10277393SMatthias Ringwald 216*10277393SMatthias Ringwald static void setup_lc3_decoder(void){ 217*10277393SMatthias Ringwald uint8_t channel; 218*10277393SMatthias Ringwald for (channel = 0 ; channel < num_bis ; channel++){ 219*10277393SMatthias Ringwald lc3_decoder_ehima_t * decoder_context = &decoder_contexts[channel]; 220*10277393SMatthias Ringwald lc3_decoder = lc3_decoder_ehima_init_instance(decoder_context); 221*10277393SMatthias Ringwald lc3_decoder->configure(decoder_context, sampling_frequency_hz, frame_duration); 222*10277393SMatthias Ringwald } 223*10277393SMatthias Ringwald number_samples_per_frame = lc3_decoder->get_number_samples_per_frame(&decoder_contexts[0]); 224*10277393SMatthias Ringwald btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME); 225*10277393SMatthias Ringwald } 226*10277393SMatthias Ringwald 227*10277393SMatthias Ringwald static void close_files(void){ 228*10277393SMatthias Ringwald printf("Close files\n"); 229*10277393SMatthias Ringwald close(dump_file); 230*10277393SMatthias Ringwald wav_writer_close(); 231*10277393SMatthias Ringwald } 232*10277393SMatthias Ringwald 233*10277393SMatthias Ringwald static void handle_periodic_advertisement(const uint8_t * packet, uint16_t size){ 234*10277393SMatthias Ringwald // periodic advertisement contains the BASE 235*10277393SMatthias Ringwald // TODO: BASE might be split across multiple advertisements 236*10277393SMatthias Ringwald const uint8_t * adv_data = hci_subevent_le_periodic_advertising_report_get_data(packet); 237*10277393SMatthias Ringwald uint16_t adv_size = hci_subevent_le_periodic_advertising_report_get_data_length(packet); 238*10277393SMatthias Ringwald 239*10277393SMatthias Ringwald ad_context_t context; 240*10277393SMatthias Ringwald for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)) { 241*10277393SMatthias Ringwald uint8_t data_type = ad_iterator_get_data_type(&context); 242*10277393SMatthias Ringwald uint8_t data_size = ad_iterator_get_data_len(&context); 243*10277393SMatthias Ringwald const uint8_t * data = ad_iterator_get_data(&context); 244*10277393SMatthias Ringwald uint16_t uuid; 245*10277393SMatthias Ringwald switch (data_type){ 246*10277393SMatthias Ringwald case BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID: 247*10277393SMatthias Ringwald uuid = little_endian_read_16(data, 0); 248*10277393SMatthias Ringwald if (uuid == ORG_BLUETOOTH_SERVICE_BASIC_AUDIO_ANNOUNCEMENT_SERVICE){ 249*10277393SMatthias Ringwald have_base = true; 250*10277393SMatthias Ringwald // Level 1: Group Level 251*10277393SMatthias Ringwald const uint8_t * base_data = &data[2]; 252*10277393SMatthias Ringwald uint16_t base_len = data_size - 2; 253*10277393SMatthias Ringwald printf("BASE:\n"); 254*10277393SMatthias Ringwald uint32_t presentation_delay = little_endian_read_24(base_data, 0); 255*10277393SMatthias Ringwald printf("- presentation delay: %"PRIu32" us\n", presentation_delay); 256*10277393SMatthias Ringwald uint8_t num_subgroups = base_data[3]; 257*10277393SMatthias Ringwald printf("- num subgroups: %u\n", num_subgroups); 258*10277393SMatthias Ringwald uint8_t i; 259*10277393SMatthias Ringwald uint16_t offset = 4; 260*10277393SMatthias Ringwald for (i=0;i<num_subgroups;i++){ 261*10277393SMatthias Ringwald // Level 2: Subgroup Level 262*10277393SMatthias Ringwald num_bis = base_data[offset++]; 263*10277393SMatthias Ringwald printf(" - num bis[%u]: %u\n", i, num_bis); 264*10277393SMatthias Ringwald // codec_id: coding format = 0x06, vendor and coded id = 0 265*10277393SMatthias Ringwald offset += 5; 266*10277393SMatthias Ringwald uint8_t codec_specific_configuration_length = base_data[offset++]; 267*10277393SMatthias Ringwald const uint8_t * codec_specific_configuration = &base_data[offset]; 268*10277393SMatthias Ringwald printf(" - codec specific config[%u]: ", i); 269*10277393SMatthias Ringwald printf_hexdump(codec_specific_configuration, codec_specific_configuration_length); 270*10277393SMatthias Ringwald // parse config to get sampling frequency and frame duration 271*10277393SMatthias Ringwald uint8_t codec_offset = 0; 272*10277393SMatthias Ringwald while ((codec_offset + 1) < codec_specific_configuration_length){ 273*10277393SMatthias Ringwald uint8_t ltv_len = codec_specific_configuration[codec_offset++]; 274*10277393SMatthias Ringwald uint8_t ltv_type = codec_specific_configuration[codec_offset]; 275*10277393SMatthias Ringwald const uint32_t sampling_frequency_map[] = { 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 384000 }; 276*10277393SMatthias Ringwald uint8_t sampling_frequency_index; 277*10277393SMatthias Ringwald uint8_t frame_duration_index; 278*10277393SMatthias Ringwald switch (ltv_type){ 279*10277393SMatthias Ringwald case 0x01: // sampling frequency 280*10277393SMatthias Ringwald sampling_frequency_index = codec_specific_configuration[codec_offset+1]; 281*10277393SMatthias Ringwald // TODO: check range 282*10277393SMatthias Ringwald sampling_frequency_hz = sampling_frequency_map[sampling_frequency_index - 1]; 283*10277393SMatthias Ringwald printf(" - sampling frequency[%u]: %"PRIu32"\n", i, sampling_frequency_hz); 284*10277393SMatthias Ringwald break; 285*10277393SMatthias Ringwald case 0x02: // 0 = 7.5, 1 = 10 ms 286*10277393SMatthias Ringwald frame_duration_index = codec_specific_configuration[codec_offset+1]; 287*10277393SMatthias Ringwald frame_duration = (frame_duration_index == 0) ? LC3_FRAME_DURATION_7500US : LC3_FRAME_DURATION_10000US; 288*10277393SMatthias Ringwald printf(" - frame duration[%u]: %s ms\n", i, (frame_duration == LC3_FRAME_DURATION_7500US) ? "7.5" : "10"); 289*10277393SMatthias Ringwald break; 290*10277393SMatthias Ringwald case 0x04: // octets per coding frame 291*10277393SMatthias Ringwald octets_per_frame = little_endian_read_16(codec_specific_configuration, codec_offset+1); 292*10277393SMatthias Ringwald printf(" - octets per codec frame[%u]: %u\n", i, octets_per_frame); 293*10277393SMatthias Ringwald break; 294*10277393SMatthias Ringwald default: 295*10277393SMatthias Ringwald break; 296*10277393SMatthias Ringwald } 297*10277393SMatthias Ringwald codec_offset += ltv_len; 298*10277393SMatthias Ringwald } 299*10277393SMatthias Ringwald // 300*10277393SMatthias Ringwald offset += codec_specific_configuration_length; 301*10277393SMatthias Ringwald uint8_t metadata_length = base_data[offset++]; 302*10277393SMatthias Ringwald const uint8_t * meta_data = &base_data[offset]; 303*10277393SMatthias Ringwald offset += metadata_length; 304*10277393SMatthias Ringwald printf(" - meta data[%u]: ", i); 305*10277393SMatthias Ringwald printf_hexdump(meta_data, metadata_length); 306*10277393SMatthias Ringwald uint8_t k; 307*10277393SMatthias Ringwald for (k=0;k<num_bis;k++){ 308*10277393SMatthias Ringwald // Level 3: BIS Level 309*10277393SMatthias Ringwald uint8_t bis_index = base_data[offset++]; 310*10277393SMatthias Ringwald printf(" - bis index[%u][%u]: %u\n", i, k, bis_index); 311*10277393SMatthias Ringwald uint8_t codec_specific_configuration_length2 = base_data[offset++]; 312*10277393SMatthias Ringwald const uint8_t * codec_specific_configuration2 = &base_data[offset]; 313*10277393SMatthias Ringwald printf(" - codec specific config[%u][%u]: ", i, k); 314*10277393SMatthias Ringwald printf_hexdump(codec_specific_configuration2, codec_specific_configuration_length2); 315*10277393SMatthias Ringwald offset += codec_specific_configuration_length2; 316*10277393SMatthias Ringwald } 317*10277393SMatthias Ringwald } 318*10277393SMatthias Ringwald } 319*10277393SMatthias Ringwald break; 320*10277393SMatthias Ringwald default: 321*10277393SMatthias Ringwald break; 322*10277393SMatthias Ringwald } 323*10277393SMatthias Ringwald } 324*10277393SMatthias Ringwald } 325*10277393SMatthias Ringwald 326*10277393SMatthias Ringwald static void handle_big_info(const uint8_t * packet, uint16_t size){ 327*10277393SMatthias Ringwald printf("BIG Info advertising report\n"); 328*10277393SMatthias Ringwald sync_handle = hci_subevent_le_biginfo_advertising_report_get_sync_handle(packet); 329*10277393SMatthias Ringwald have_big_info = true; 330*10277393SMatthias Ringwald } 331*10277393SMatthias Ringwald 332*10277393SMatthias Ringwald static void enter_create_big_sync(void){ 333*10277393SMatthias Ringwald // stop scanning 334*10277393SMatthias Ringwald gap_stop_scan(); 335*10277393SMatthias Ringwald 336*10277393SMatthias Ringwald // init decoder 337*10277393SMatthias Ringwald setup_lc3_decoder(); 338*10277393SMatthias Ringwald 339*10277393SMatthias Ringwald printf("Configure: %u channels, sampling rate %u, samples per frame %u\n", num_bis, sampling_frequency_hz, number_samples_per_frame); 340*10277393SMatthias Ringwald 341*10277393SMatthias Ringwald // create lc3 file 342*10277393SMatthias Ringwald open_lc3_file(); 343*10277393SMatthias Ringwald 344*10277393SMatthias Ringwald // create wav file 345*10277393SMatthias Ringwald printf("WAV file: %s\n", filename_wav); 346*10277393SMatthias Ringwald wav_writer_open(filename_wav, num_bis, sampling_frequency_hz); 347*10277393SMatthias Ringwald 348*10277393SMatthias Ringwald // init playback buffer 349*10277393SMatthias Ringwald btstack_ring_buffer_init(&playback_buffer, playback_buffer_storage, PLAYBACK_BUFFER_SIZE); 350*10277393SMatthias Ringwald 351*10277393SMatthias Ringwald // start playback 352*10277393SMatthias Ringwald // PTS 8.2 sends stereo at half speed for stereo, for now playback at half speed 353*10277393SMatthias Ringwald const btstack_audio_sink_t * sink = btstack_audio_sink_get_instance(); 354*10277393SMatthias Ringwald if (sink != NULL){ 355*10277393SMatthias Ringwald uint32_t playback_speed; 356*10277393SMatthias Ringwald if ((num_bis > 1) && pts_mode){ 357*10277393SMatthias Ringwald playback_speed = sampling_frequency_hz / num_bis; 358*10277393SMatthias Ringwald printf("PTS workaround: playback at %u hz\n", playback_speed); 359*10277393SMatthias Ringwald } else { 360*10277393SMatthias Ringwald playback_speed = sampling_frequency_hz; 361*10277393SMatthias Ringwald }; 362*10277393SMatthias Ringwald sink->init(num_bis, sampling_frequency_hz, le_audio_broadcast_sink_playback); 363*10277393SMatthias Ringwald sink->start_stream(); 364*10277393SMatthias Ringwald } 365*10277393SMatthias Ringwald 366*10277393SMatthias Ringwald app_state = APP_CREATE_BIG_SYNC; 367*10277393SMatthias Ringwald } 368*10277393SMatthias Ringwald 369*10277393SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 370*10277393SMatthias Ringwald UNUSED(channel); 371*10277393SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 372*10277393SMatthias Ringwald unsigned int i; 373*10277393SMatthias Ringwald switch (packet[0]) { 374*10277393SMatthias Ringwald case BTSTACK_EVENT_STATE: 375*10277393SMatthias Ringwald switch(btstack_event_state_get_state(packet)) { 376*10277393SMatthias Ringwald case HCI_STATE_WORKING: 377*10277393SMatthias Ringwald if (app_state != APP_W4_WORKING) break; 378*10277393SMatthias Ringwald app_state = APP_W4_BROADCAST_ADV; 379*10277393SMatthias Ringwald gap_set_scan_params(1, 0x30, 0x30, 0); 380*10277393SMatthias Ringwald gap_start_scan(); 381*10277393SMatthias Ringwald printf("Start scan..\n"); 382*10277393SMatthias Ringwald break; 383*10277393SMatthias Ringwald case HCI_STATE_OFF: 384*10277393SMatthias Ringwald printf("Goodbye\n"); 385*10277393SMatthias Ringwald exit(0); 386*10277393SMatthias Ringwald break; 387*10277393SMatthias Ringwald default: 388*10277393SMatthias Ringwald break; 389*10277393SMatthias Ringwald } 390*10277393SMatthias Ringwald break; 391*10277393SMatthias Ringwald case GAP_EVENT_EXTENDED_ADVERTISING_REPORT: 392*10277393SMatthias Ringwald { 393*10277393SMatthias Ringwald if (app_state != APP_W4_BROADCAST_ADV) break; 394*10277393SMatthias Ringwald 395*10277393SMatthias Ringwald gap_event_extended_advertising_report_get_address(packet, remote); 396*10277393SMatthias Ringwald uint8_t adv_size = gap_event_extended_advertising_report_get_data_length(packet); 397*10277393SMatthias Ringwald const uint8_t * adv_data = gap_event_extended_advertising_report_get_data(packet); 398*10277393SMatthias Ringwald 399*10277393SMatthias Ringwald ad_context_t context; 400*10277393SMatthias Ringwald bool found = false; 401*10277393SMatthias Ringwald remote_name[0] = '\0'; 402*10277393SMatthias Ringwald uint16_t uuid; 403*10277393SMatthias Ringwald for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)) { 404*10277393SMatthias Ringwald uint8_t data_type = ad_iterator_get_data_type(&context); 405*10277393SMatthias Ringwald uint8_t size = ad_iterator_get_data_len(&context); 406*10277393SMatthias Ringwald const uint8_t *data = ad_iterator_get_data(&context); 407*10277393SMatthias Ringwald switch (data_type){ 408*10277393SMatthias Ringwald case BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID: 409*10277393SMatthias Ringwald uuid = little_endian_read_16(data, 0); 410*10277393SMatthias Ringwald if (uuid == ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE){ 411*10277393SMatthias Ringwald found = true; 412*10277393SMatthias Ringwald } 413*10277393SMatthias Ringwald break; 414*10277393SMatthias Ringwald case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME: 415*10277393SMatthias Ringwald case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME: 416*10277393SMatthias Ringwald size = btstack_min(sizeof(remote_name) - 1, size); 417*10277393SMatthias Ringwald memcpy(remote_name, data, size); 418*10277393SMatthias Ringwald remote_name[size] = 0; 419*10277393SMatthias Ringwald break; 420*10277393SMatthias Ringwald default: 421*10277393SMatthias Ringwald break; 422*10277393SMatthias Ringwald } 423*10277393SMatthias Ringwald } 424*10277393SMatthias Ringwald if (!found) break; 425*10277393SMatthias Ringwald remote_type = gap_event_extended_advertising_report_get_address_type(packet); 426*10277393SMatthias Ringwald remote_sid = gap_event_extended_advertising_report_get_advertising_sid(packet); 427*10277393SMatthias Ringwald pts_mode = strncmp("PTS-", remote_name, 4) == 0; 428*10277393SMatthias Ringwald count_mode = strncmp("COUNT", remote_name, 5) == 0; 429*10277393SMatthias Ringwald printf("Remote Broadcast sink found, addr %s, name: '%s' (pts-mode: %u, count: %u)\n", bd_addr_to_str(remote), remote_name, pts_mode, count_mode); 430*10277393SMatthias Ringwald // ignore other advertisements 431*10277393SMatthias Ringwald gap_whitelist_add(remote_type, remote); 432*10277393SMatthias Ringwald gap_set_scan_params(1, 0x30, 0x30, 1); 433*10277393SMatthias Ringwald // sync to PA 434*10277393SMatthias Ringwald gap_periodic_advertiser_list_clear(); 435*10277393SMatthias Ringwald gap_periodic_advertiser_list_add(remote_type, remote, remote_sid); 436*10277393SMatthias Ringwald app_state = APP_W4_PA_AND_BIG_INFO; 437*10277393SMatthias Ringwald printf("Start Periodic Advertising Sync\n"); 438*10277393SMatthias Ringwald gap_periodic_advertising_create_sync(0x01, remote_sid, remote_type, remote, 0, 1000, 0); 439*10277393SMatthias Ringwald break; 440*10277393SMatthias Ringwald } 441*10277393SMatthias Ringwald 442*10277393SMatthias Ringwald case HCI_EVENT_LE_META: 443*10277393SMatthias Ringwald switch(hci_event_le_meta_get_subevent_code(packet)) { 444*10277393SMatthias Ringwald case HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHMENT: 445*10277393SMatthias Ringwald printf("Periodic advertising sync established\n"); 446*10277393SMatthias Ringwald break; 447*10277393SMatthias Ringwald case HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_REPORT: 448*10277393SMatthias Ringwald if (have_base) break; 449*10277393SMatthias Ringwald handle_periodic_advertisement(packet, size); 450*10277393SMatthias Ringwald if (have_big_info){ 451*10277393SMatthias Ringwald enter_create_big_sync(); 452*10277393SMatthias Ringwald } 453*10277393SMatthias Ringwald break; 454*10277393SMatthias Ringwald case HCI_SUBEVENT_LE_BIGINFO_ADVERTISING_REPORT: 455*10277393SMatthias Ringwald if (have_big_info) break; 456*10277393SMatthias Ringwald handle_big_info(packet, size); 457*10277393SMatthias Ringwald if (have_base){ 458*10277393SMatthias Ringwald enter_create_big_sync(); 459*10277393SMatthias Ringwald } 460*10277393SMatthias Ringwald break; 461*10277393SMatthias Ringwald case HCI_SUBEVENT_LE_BIG_SYNC_ESTABLISHED: 462*10277393SMatthias Ringwald printf("BIG Sync Established\n"); 463*10277393SMatthias Ringwald if (app_state == APP_W4_BIG_SYNC_ESTABLISHED){ 464*10277393SMatthias Ringwald gap_stop_scan(); 465*10277393SMatthias Ringwald gap_periodic_advertising_terminate_sync(sync_handle); 466*10277393SMatthias Ringwald // update num_bis 467*10277393SMatthias Ringwald num_bis = packet[16]; 468*10277393SMatthias Ringwald for (i=0;i<num_bis;i++){ 469*10277393SMatthias Ringwald bis_con_handles[i] = little_endian_read_16(packet, 17 + 2*i); 470*10277393SMatthias Ringwald } 471*10277393SMatthias Ringwald next_bis_index = 0; 472*10277393SMatthias Ringwald app_state = APP_SET_ISO_PATHS; 473*10277393SMatthias Ringwald } 474*10277393SMatthias Ringwald break; 475*10277393SMatthias Ringwald default: 476*10277393SMatthias Ringwald break; 477*10277393SMatthias Ringwald } 478*10277393SMatthias Ringwald default: 479*10277393SMatthias Ringwald break; 480*10277393SMatthias Ringwald } 481*10277393SMatthias Ringwald 482*10277393SMatthias Ringwald if (!hci_can_send_command_packet_now()) return; 483*10277393SMatthias Ringwald 484*10277393SMatthias Ringwald const uint8_t broadcast_code[16] = { 0 }; 485*10277393SMatthias Ringwald uint8_t bis_array[MAX_NUM_BIS]; 486*10277393SMatthias Ringwald switch(app_state){ 487*10277393SMatthias Ringwald case APP_CREATE_BIG_SYNC: 488*10277393SMatthias Ringwald app_state = APP_W4_BIG_SYNC_ESTABLISHED; 489*10277393SMatthias Ringwald printf("BIG Create Sync for BIS: "); 490*10277393SMatthias Ringwald for (i=0;i<num_bis;i++){ 491*10277393SMatthias Ringwald bis_array[i] = i + 1; 492*10277393SMatthias Ringwald printf("%u ", bis_array[i]); 493*10277393SMatthias Ringwald } 494*10277393SMatthias Ringwald printf("\n"); 495*10277393SMatthias Ringwald hci_send_cmd(&hci_le_big_create_sync, big_handle, sync_handle, 0, broadcast_code, 0, 100, num_bis, bis_array); 496*10277393SMatthias Ringwald break; 497*10277393SMatthias Ringwald case APP_SET_ISO_PATHS: 498*10277393SMatthias Ringwald hci_send_cmd(&hci_le_setup_iso_data_path, bis_con_handles[next_bis_index++], 1, 0, 0, 0, 0, 0, 0, NULL); 499*10277393SMatthias Ringwald if (next_bis_index == num_bis){ 500*10277393SMatthias Ringwald app_state = APP_STREAMING; 501*10277393SMatthias Ringwald last_samples_report_ms = btstack_run_loop_get_time_ms(); 502*10277393SMatthias Ringwald } 503*10277393SMatthias Ringwald break; 504*10277393SMatthias Ringwald case APP_TERMINATE_BIG: 505*10277393SMatthias Ringwald hci_send_cmd(&hci_le_big_terminate_sync, big_handle); 506*10277393SMatthias Ringwald app_state = APP_IDLE; 507*10277393SMatthias Ringwald printf("Shutdown...\n"); 508*10277393SMatthias Ringwald hci_power_control(HCI_POWER_OFF); 509*10277393SMatthias Ringwald break; 510*10277393SMatthias Ringwald default: 511*10277393SMatthias Ringwald break; 512*10277393SMatthias Ringwald } 513*10277393SMatthias Ringwald } 514*10277393SMatthias Ringwald 515*10277393SMatthias Ringwald static void iso_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 516*10277393SMatthias Ringwald 517*10277393SMatthias Ringwald uint16_t header = little_endian_read_16(packet, 0); 518*10277393SMatthias Ringwald hci_con_handle_t con_handle = header & 0x0fff; 519*10277393SMatthias Ringwald uint8_t pb_flag = (header >> 12) & 3; 520*10277393SMatthias Ringwald uint8_t ts_flag = (header >> 14) & 1; 521*10277393SMatthias Ringwald uint16_t iso_load_len = little_endian_read_16(packet, 2); 522*10277393SMatthias Ringwald 523*10277393SMatthias Ringwald uint16_t offset = 4; 524*10277393SMatthias Ringwald uint32_t time_stamp = 0; 525*10277393SMatthias Ringwald if (ts_flag){ 526*10277393SMatthias Ringwald uint32_t time_stamp = little_endian_read_32(packet, offset); 527*10277393SMatthias Ringwald offset += 4; 528*10277393SMatthias Ringwald } 529*10277393SMatthias Ringwald 530*10277393SMatthias Ringwald uint16_t packet_sequence_number = little_endian_read_16(packet, offset); 531*10277393SMatthias Ringwald offset += 2; 532*10277393SMatthias Ringwald 533*10277393SMatthias Ringwald uint16_t header_2 = little_endian_read_16(packet, offset); 534*10277393SMatthias Ringwald uint16_t iso_sdu_length = header_2 & 0x3fff; 535*10277393SMatthias Ringwald uint8_t packet_status_flag = (uint8_t) (header_2 >> 14); 536*10277393SMatthias Ringwald offset += 2; 537*10277393SMatthias Ringwald 538*10277393SMatthias Ringwald if (iso_sdu_length == 0) return; 539*10277393SMatthias Ringwald 540*10277393SMatthias Ringwald // infer channel from con handle - only works for up to 2 channels 541*10277393SMatthias Ringwald uint8_t bis_channel = (con_handle == bis_con_handles[0]) ? 0 : 1; 542*10277393SMatthias Ringwald 543*10277393SMatthias Ringwald if (count_mode){ 544*10277393SMatthias Ringwald // check for missing packet 545*10277393SMatthias Ringwald uint16_t last_seq_no = last_packet_sequence[bis_channel]; 546*10277393SMatthias Ringwald uint32_t now = btstack_run_loop_get_time_ms(); 547*10277393SMatthias Ringwald bool packet_missed = (last_seq_no != 0) && ((last_seq_no + 1) != packet_sequence_number); 548*10277393SMatthias Ringwald if (packet_missed){ 549*10277393SMatthias Ringwald // print last packet 550*10277393SMatthias Ringwald printf("\n"); 551*10277393SMatthias Ringwald printf("%04x %10u %u ", last_seq_no, last_packet_time_ms[bis_channel], bis_channel); 552*10277393SMatthias Ringwald printf_hexdump(&last_packet_prefix[num_bis*PACKET_PREFIX_LEN], PACKET_PREFIX_LEN); 553*10277393SMatthias Ringwald last_seq_no++; 554*10277393SMatthias Ringwald 555*10277393SMatthias Ringwald printf(ANSI_COLOR_RED); 556*10277393SMatthias Ringwald while (last_seq_no < packet_sequence_number){ 557*10277393SMatthias Ringwald printf("%04x %u MISSING\n", last_seq_no, bis_channel); 558*10277393SMatthias Ringwald last_seq_no++; 559*10277393SMatthias Ringwald } 560*10277393SMatthias Ringwald printf(ANSI_COLOR_RESET); 561*10277393SMatthias Ringwald 562*10277393SMatthias Ringwald // print current packet 563*10277393SMatthias Ringwald printf("%04x %10u %u ", packet_sequence_number, now, bis_channel); 564*10277393SMatthias Ringwald printf_hexdump(&packet[offset], PACKET_PREFIX_LEN); 565*10277393SMatthias Ringwald } 566*10277393SMatthias Ringwald 567*10277393SMatthias Ringwald // cache current packet 568*10277393SMatthias Ringwald last_packet_time_ms[bis_channel] = now; 569*10277393SMatthias Ringwald last_packet_sequence[bis_channel] = packet_sequence_number; 570*10277393SMatthias Ringwald memcpy(&last_packet_prefix[num_bis*PACKET_PREFIX_LEN], &packet[offset], PACKET_PREFIX_LEN); 571*10277393SMatthias Ringwald 572*10277393SMatthias Ringwald } else { 573*10277393SMatthias Ringwald 574*10277393SMatthias Ringwald if ((packet_sequence_number & 0x7c) == 0) { 575*10277393SMatthias Ringwald printf("%04x %10u %u ", packet_sequence_number, btstack_run_loop_get_time_ms(), bis_channel); 576*10277393SMatthias Ringwald printf_hexdump(&packet[offset], iso_sdu_length); 577*10277393SMatthias Ringwald } 578*10277393SMatthias Ringwald 579*10277393SMatthias Ringwald if (lc3_frames < DUMP_LEN_LC3_FRAMES) { 580*10277393SMatthias Ringwald // store len header only for first bis 581*10277393SMatthias Ringwald if (bis_channel == 0) { 582*10277393SMatthias Ringwald uint8_t len_header[2]; 583*10277393SMatthias Ringwald little_endian_store_16(len_header, 0, num_bis * iso_sdu_length); 584*10277393SMatthias Ringwald write(dump_file, len_header, 2); 585*10277393SMatthias Ringwald } 586*10277393SMatthias Ringwald 587*10277393SMatthias Ringwald // store single channel codec frame 588*10277393SMatthias Ringwald write(dump_file, &packet[offset], iso_sdu_length); 589*10277393SMatthias Ringwald } 590*10277393SMatthias Ringwald 591*10277393SMatthias Ringwald // decode codec frame 592*10277393SMatthias Ringwald uint8_t tmp_BEC_detect; 593*10277393SMatthias Ringwald uint8_t BFI = 0; 594*10277393SMatthias Ringwald (void) lc3_decoder->decode(&decoder_contexts[bis_channel], &packet[offset], iso_sdu_length, BFI, 595*10277393SMatthias Ringwald &pcm[bis_channel * MAX_SAMPLES_PER_FRAME], number_samples_per_frame, 596*10277393SMatthias Ringwald &tmp_BEC_detect); 597*10277393SMatthias Ringwald 598*10277393SMatthias Ringwald // interleave channel samples 599*10277393SMatthias Ringwald if ((bis_channel + 1) == num_bis) { 600*10277393SMatthias Ringwald uint16_t sample; 601*10277393SMatthias Ringwald int16_t wav_frame[MAX_NUM_BIS]; 602*10277393SMatthias Ringwald uint8_t wav_channel; 603*10277393SMatthias Ringwald for (sample = 0; sample < number_samples_per_frame; sample++) { 604*10277393SMatthias Ringwald for (wav_channel = 0; wav_channel < num_bis; wav_channel++) { 605*10277393SMatthias Ringwald wav_frame[wav_channel] = pcm[wav_channel * MAX_SAMPLES_PER_FRAME + sample]; 606*10277393SMatthias Ringwald } 607*10277393SMatthias Ringwald 608*10277393SMatthias Ringwald // write wav sample 609*10277393SMatthias Ringwald if (lc3_frames < DUMP_LEN_LC3_FRAMES) { 610*10277393SMatthias Ringwald wav_writer_write_int16(num_bis, wav_frame); 611*10277393SMatthias Ringwald } 612*10277393SMatthias Ringwald 613*10277393SMatthias Ringwald // store sample in playback buffer 614*10277393SMatthias Ringwald uint32_t bytes_to_store = num_bis * 2; 615*10277393SMatthias Ringwald samples_received++; 616*10277393SMatthias Ringwald if (btstack_ring_buffer_bytes_free(&playback_buffer) >= bytes_to_store) { 617*10277393SMatthias Ringwald btstack_ring_buffer_write(&playback_buffer, (uint8_t *) wav_frame, bytes_to_store); 618*10277393SMatthias Ringwald } else { 619*10277393SMatthias Ringwald samples_dropped++; 620*10277393SMatthias Ringwald } 621*10277393SMatthias Ringwald } 622*10277393SMatthias Ringwald } 623*10277393SMatthias Ringwald 624*10277393SMatthias Ringwald log_info("Samples in playback buffer %5u", btstack_ring_buffer_bytes_available(&playback_buffer) / (num_bis * 2)); 625*10277393SMatthias Ringwald 626*10277393SMatthias Ringwald lc3_frames++; 627*10277393SMatthias Ringwald frames_per_second[bis_channel]++; 628*10277393SMatthias Ringwald 629*10277393SMatthias Ringwald uint32_t time_ms = btstack_run_loop_get_time_ms(); 630*10277393SMatthias Ringwald if (btstack_time_delta(time_ms, last_samples_report_ms) > 1000){ 631*10277393SMatthias Ringwald last_samples_report_ms = time_ms; 632*10277393SMatthias Ringwald printf("LC3 Frames: %4u - ", lc3_frames / num_bis); 633*10277393SMatthias Ringwald uint8_t i; 634*10277393SMatthias Ringwald for (i=0;i<num_bis;i++){ 635*10277393SMatthias Ringwald printf("%u ", frames_per_second[i]); 636*10277393SMatthias Ringwald frames_per_second[i] = 0; 637*10277393SMatthias Ringwald } 638*10277393SMatthias Ringwald printf(" frames per second, dropped %u of %u\n", samples_dropped, samples_received); 639*10277393SMatthias Ringwald samples_received = 0; 640*10277393SMatthias Ringwald samples_dropped = 0; 641*10277393SMatthias Ringwald } 642*10277393SMatthias Ringwald 643*10277393SMatthias Ringwald if (lc3_frames == DUMP_LEN_LC3_FRAMES){ 644*10277393SMatthias Ringwald close_files(); 645*10277393SMatthias Ringwald } 646*10277393SMatthias Ringwald } 647*10277393SMatthias Ringwald } 648*10277393SMatthias Ringwald 649*10277393SMatthias Ringwald static void show_usage(void){ 650*10277393SMatthias Ringwald printf("\n--- LE Audio Broadcast Sink Test Console ---\n"); 651*10277393SMatthias Ringwald printf("x - close files and exit\n"); 652*10277393SMatthias Ringwald printf("---\n"); 653*10277393SMatthias Ringwald } 654*10277393SMatthias Ringwald 655*10277393SMatthias Ringwald static void stdin_process(char c){ 656*10277393SMatthias Ringwald switch (c){ 657*10277393SMatthias Ringwald case 'x': 658*10277393SMatthias Ringwald close_files(); 659*10277393SMatthias Ringwald printf("Shutdown...\n"); 660*10277393SMatthias Ringwald hci_power_control(HCI_POWER_OFF); 661*10277393SMatthias Ringwald break; 662*10277393SMatthias Ringwald case '\n': 663*10277393SMatthias Ringwald case '\r': 664*10277393SMatthias Ringwald break; 665*10277393SMatthias Ringwald default: 666*10277393SMatthias Ringwald show_usage(); 667*10277393SMatthias Ringwald break; 668*10277393SMatthias Ringwald 669*10277393SMatthias Ringwald } 670*10277393SMatthias Ringwald } 671*10277393SMatthias Ringwald 672*10277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]); 673*10277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 674*10277393SMatthias Ringwald (void) argv; 675*10277393SMatthias Ringwald (void) argc; 676*10277393SMatthias Ringwald 677*10277393SMatthias Ringwald // register for HCI events 678*10277393SMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 679*10277393SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 680*10277393SMatthias Ringwald 681*10277393SMatthias Ringwald // register for ISO Packet 682*10277393SMatthias Ringwald hci_register_iso_packet_handler(&iso_packet_handler); 683*10277393SMatthias Ringwald 684*10277393SMatthias Ringwald // turn on! 685*10277393SMatthias Ringwald hci_power_control(HCI_POWER_ON); 686*10277393SMatthias Ringwald 687*10277393SMatthias Ringwald btstack_stdin_setup(stdin_process); 688*10277393SMatthias Ringwald return 0; 689*10277393SMatthias Ringwald } 690