1922a5394SMatthias Ringwald /* 2922a5394SMatthias Ringwald * Copyright (C) 2022 BlueKitchen GmbH 3922a5394SMatthias Ringwald * 4922a5394SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5922a5394SMatthias Ringwald * modification, are permitted provided that the following conditions 6922a5394SMatthias Ringwald * are met: 7922a5394SMatthias Ringwald * 8922a5394SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9922a5394SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10922a5394SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11922a5394SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12922a5394SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13922a5394SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14922a5394SMatthias Ringwald * contributors may be used to endorse or promote products derived 15922a5394SMatthias Ringwald * from this software without specific prior written permission. 16922a5394SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17922a5394SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18922a5394SMatthias Ringwald * monetary gain. 19922a5394SMatthias Ringwald * 20922a5394SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21922a5394SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22922a5394SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23922a5394SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24922a5394SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25922a5394SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26922a5394SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27922a5394SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28922a5394SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29922a5394SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30922a5394SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31922a5394SMatthias Ringwald * SUCH DAMAGE. 32922a5394SMatthias Ringwald * 33922a5394SMatthias Ringwald * Please inquire about commercial licensing options at 34922a5394SMatthias Ringwald * [email protected] 35922a5394SMatthias Ringwald * 36922a5394SMatthias Ringwald */ 37922a5394SMatthias Ringwald 38922a5394SMatthias Ringwald #define BTSTACK_FILE__ "le_audio_unicast_sink.c" 39922a5394SMatthias Ringwald 40922a5394SMatthias Ringwald /* 41922a5394SMatthias Ringwald * LE Audio Unicast Sink 42922a5394SMatthias Ringwald * Until GATT Services are available, we encode LC3 config in advertising 43922a5394SMatthias Ringwald */ 44922a5394SMatthias Ringwald 45922a5394SMatthias Ringwald 46922a5394SMatthias Ringwald #include "btstack_config.h" 47922a5394SMatthias Ringwald 48922a5394SMatthias Ringwald #include <stdint.h> 49922a5394SMatthias Ringwald #include <stdio.h> 50922a5394SMatthias Ringwald #include <stdlib.h> 51922a5394SMatthias Ringwald #include <string.h> 52922a5394SMatthias Ringwald 53922a5394SMatthias Ringwald #include "ad_parser.h" 54922a5394SMatthias Ringwald #include "bluetooth_data_types.h" 55922a5394SMatthias Ringwald #include "bluetooth_company_id.h" 56922a5394SMatthias Ringwald #include "btstack_debug.h" 57922a5394SMatthias Ringwald #include "btstack_event.h" 58922a5394SMatthias Ringwald #include "btstack_stdin.h" 59922a5394SMatthias Ringwald #include "gap.h" 60922a5394SMatthias Ringwald #include "hci.h" 61922a5394SMatthias Ringwald #include "le_audio_demo_util_sink.h" 62922a5394SMatthias Ringwald #include "le_audio_demo_util_source.h" 63922a5394SMatthias Ringwald 64922a5394SMatthias Ringwald // max config 65922a5394SMatthias Ringwald #define MAX_CHANNELS 2 66922a5394SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480 67922a5394SMatthias Ringwald 68922a5394SMatthias Ringwald static void show_usage(void); 69922a5394SMatthias Ringwald 70922a5394SMatthias Ringwald static enum { 71922a5394SMatthias Ringwald APP_W4_WORKING, 72922a5394SMatthias Ringwald APP_W4_SOURCE_ADV, 73922a5394SMatthias Ringwald APP_W4_CIG_COMPLETE, 74922a5394SMatthias Ringwald APP_W4_CIS_CREATED, 75922a5394SMatthias Ringwald APP_STREAMING, 76922a5394SMatthias Ringwald APP_IDLE, 77922a5394SMatthias Ringwald } app_state = APP_W4_WORKING; 78922a5394SMatthias Ringwald 79922a5394SMatthias Ringwald // 80922a5394SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 81922a5394SMatthias Ringwald 82922a5394SMatthias Ringwald // remote info 83922a5394SMatthias Ringwald static char remote_name[20]; 84922a5394SMatthias Ringwald static bd_addr_t remote_addr; 85922a5394SMatthias Ringwald static bd_addr_type_t remote_type; 86922a5394SMatthias Ringwald static hci_con_handle_t remote_handle; 87922a5394SMatthias Ringwald 88922a5394SMatthias Ringwald static le_audio_cig_t cig; 89922a5394SMatthias Ringwald static le_audio_cig_params_t cig_params; 90922a5394SMatthias Ringwald 91922a5394SMatthias Ringwald // iso info 92922a5394SMatthias Ringwald static bool framed_pdus; 93922a5394SMatthias Ringwald static uint16_t frame_duration_us; 94922a5394SMatthias Ringwald 95922a5394SMatthias Ringwald static uint8_t num_cis; 96922a5394SMatthias Ringwald static hci_con_handle_t cis_con_handles[MAX_CHANNELS]; 97922a5394SMatthias Ringwald static bool cis_established[MAX_CHANNELS]; 98922a5394SMatthias Ringwald 99922a5394SMatthias Ringwald // lc3 codec config 100922a5394SMatthias Ringwald static uint16_t sampling_frequency_hz; 101922a5394SMatthias Ringwald static btstack_lc3_frame_duration_t frame_duration; 102922a5394SMatthias Ringwald static uint16_t number_samples_per_frame; 103922a5394SMatthias Ringwald static uint16_t octets_per_frame; 104922a5394SMatthias Ringwald static uint8_t num_channels; 105922a5394SMatthias Ringwald 106922a5394SMatthias Ringwald // microphone 107922a5394SMatthias Ringwald static bool microphone_enable; 108922a5394SMatthias Ringwald 109922a5394SMatthias Ringwald static void start_scanning() { 110922a5394SMatthias Ringwald app_state = APP_W4_SOURCE_ADV; 111922a5394SMatthias Ringwald gap_set_scan_params(1, 0x30, 0x30, 0); 112922a5394SMatthias Ringwald gap_start_scan(); 113922a5394SMatthias Ringwald printf("Start scan..\n"); 114922a5394SMatthias Ringwald } 115922a5394SMatthias Ringwald 116922a5394SMatthias Ringwald static void create_cig() { 117922a5394SMatthias Ringwald if (sampling_frequency_hz == 44100){ 118922a5394SMatthias Ringwald framed_pdus = 1; 119922a5394SMatthias Ringwald // same config as for 48k -> frame is longer by 48/44.1 120922a5394SMatthias Ringwald frame_duration_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8163 : 10884; 121922a5394SMatthias Ringwald } else { 122922a5394SMatthias Ringwald framed_pdus = 0; 123922a5394SMatthias Ringwald frame_duration_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 7500 : 10000; 124922a5394SMatthias Ringwald } 125922a5394SMatthias Ringwald 126922a5394SMatthias Ringwald printf("Send: LE Set CIG Parameters\n"); 127922a5394SMatthias Ringwald 128922a5394SMatthias Ringwald num_cis = 1; 129922a5394SMatthias Ringwald cig_params.cig_id = 0; 130922a5394SMatthias Ringwald cig_params.num_cis = 1; 131922a5394SMatthias Ringwald cig_params.sdu_interval_c_to_p = frame_duration_us; 132922a5394SMatthias Ringwald cig_params.sdu_interval_p_to_c = frame_duration_us; 133922a5394SMatthias Ringwald cig_params.worst_case_sca = 0; // 251 ppm to 500 ppm 134922a5394SMatthias Ringwald cig_params.packing = 0; // sequential 135922a5394SMatthias Ringwald cig_params.framing = framed_pdus; 136922a5394SMatthias Ringwald cig_params.max_transport_latency_c_to_p = 40; 137922a5394SMatthias Ringwald cig_params.max_transport_latency_p_to_c = 40; 138922a5394SMatthias Ringwald uint8_t i; 139922a5394SMatthias Ringwald uint16_t max_sdu_c_to_p = microphone_enable ? octets_per_frame : 0; 140922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 141922a5394SMatthias Ringwald cig_params.cis_params[i].cis_id = i; 142922a5394SMatthias Ringwald cig_params.cis_params[i].max_sdu_c_to_p = max_sdu_c_to_p; 143922a5394SMatthias Ringwald cig_params.cis_params[i].max_sdu_p_to_c = num_channels * octets_per_frame; 144922a5394SMatthias Ringwald cig_params.cis_params[i].phy_c_to_p = 2; // 2M 145922a5394SMatthias Ringwald cig_params.cis_params[i].phy_p_to_c = 2; // 2M 146922a5394SMatthias Ringwald cig_params.cis_params[i].rtn_c_to_p = 2; 147922a5394SMatthias Ringwald cig_params.cis_params[i].rtn_p_to_c = 2; 148922a5394SMatthias Ringwald } 149922a5394SMatthias Ringwald 150922a5394SMatthias Ringwald app_state = APP_W4_CIG_COMPLETE; 151922a5394SMatthias Ringwald gap_cig_create(&cig, &cig_params); 152922a5394SMatthias Ringwald } 153922a5394SMatthias Ringwald 154922a5394SMatthias Ringwald static void enter_streaming(void){ 155922a5394SMatthias Ringwald // init source 156922a5394SMatthias Ringwald if (microphone_enable){ 157922a5394SMatthias Ringwald le_audio_demo_util_source_configure(1, 1, sampling_frequency_hz, frame_duration, octets_per_frame); 158922a5394SMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(AUDIO_SOURCE_SINE); 159922a5394SMatthias Ringwald } 160922a5394SMatthias Ringwald // init sink 161922a5394SMatthias Ringwald uint16_t iso_interval_1250us = frame_duration_us / 1250; 162922a5394SMatthias Ringwald uint8_t flush_timeout = 1; 163922a5394SMatthias Ringwald le_audio_demo_util_sink_configure_unicast(1, num_channels, sampling_frequency_hz, frame_duration, octets_per_frame, 164922a5394SMatthias Ringwald iso_interval_1250us, flush_timeout); 165922a5394SMatthias Ringwald printf("Configure: %u channels, sampling rate %u, samples per frame %u\n", num_channels, sampling_frequency_hz, number_samples_per_frame); 166922a5394SMatthias Ringwald } 167922a5394SMatthias Ringwald 168922a5394SMatthias Ringwald 169922a5394SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 170922a5394SMatthias Ringwald UNUSED(channel); 171922a5394SMatthias Ringwald bd_addr_t event_addr; 172922a5394SMatthias Ringwald hci_con_handle_t cis_handle; 173922a5394SMatthias Ringwald unsigned int i; 174922a5394SMatthias Ringwald uint8_t status; 175922a5394SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 176922a5394SMatthias Ringwald switch (packet[0]) { 177922a5394SMatthias Ringwald case BTSTACK_EVENT_STATE: 178922a5394SMatthias Ringwald switch(btstack_event_state_get_state(packet)) { 179922a5394SMatthias Ringwald case HCI_STATE_WORKING: 180922a5394SMatthias Ringwald #ifdef ENABLE_DEMO_MODE 181922a5394SMatthias Ringwald if (app_state != APP_W4_WORKING) break; 182922a5394SMatthias Ringwald start_scanning(); 183922a5394SMatthias Ringwald #else 184922a5394SMatthias Ringwald show_usage(); 185922a5394SMatthias Ringwald #endif 186922a5394SMatthias Ringwald break; 187922a5394SMatthias Ringwald case HCI_STATE_OFF: 188922a5394SMatthias Ringwald printf("Goodbye\n"); 189922a5394SMatthias Ringwald exit(0); 190922a5394SMatthias Ringwald break; 191922a5394SMatthias Ringwald default: 192922a5394SMatthias Ringwald break; 193922a5394SMatthias Ringwald } 194922a5394SMatthias Ringwald break; 195922a5394SMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 196922a5394SMatthias Ringwald if (hci_event_disconnection_complete_get_connection_handle(packet) == remote_handle){ 197922a5394SMatthias Ringwald printf("Disconnected, back to scanning\n"); 198922a5394SMatthias Ringwald le_audio_demo_util_sink_close(); 199922a5394SMatthias Ringwald start_scanning(); 200922a5394SMatthias Ringwald } 201922a5394SMatthias Ringwald break; 202922a5394SMatthias Ringwald case GAP_EVENT_ADVERTISING_REPORT: 203922a5394SMatthias Ringwald { 204922a5394SMatthias Ringwald if (app_state != APP_W4_SOURCE_ADV) break; 205922a5394SMatthias Ringwald 206922a5394SMatthias Ringwald gap_event_advertising_report_get_address(packet, remote_addr); 207922a5394SMatthias Ringwald uint8_t adv_size = gap_event_advertising_report_get_data_length(packet); 208922a5394SMatthias Ringwald const uint8_t * adv_data = gap_event_advertising_report_get_data(packet); 209922a5394SMatthias Ringwald 210922a5394SMatthias Ringwald ad_context_t context; 211922a5394SMatthias Ringwald bool found = false; 212922a5394SMatthias Ringwald remote_name[0] = '\0'; 213922a5394SMatthias Ringwald uint16_t uuid; 214922a5394SMatthias Ringwald uint16_t company_id; 215922a5394SMatthias Ringwald for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)) { 216922a5394SMatthias Ringwald uint8_t data_type = ad_iterator_get_data_type(&context); 217922a5394SMatthias Ringwald uint8_t size = ad_iterator_get_data_len(&context); 218922a5394SMatthias Ringwald const uint8_t *data = ad_iterator_get_data(&context); 219922a5394SMatthias Ringwald switch (data_type){ 220922a5394SMatthias Ringwald case BLUETOOTH_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA: 221922a5394SMatthias Ringwald company_id = little_endian_read_16(data, 0); 222922a5394SMatthias Ringwald if (company_id == BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH){ 223922a5394SMatthias Ringwald // subtype = 0 -> le audio unicast source 224922a5394SMatthias Ringwald uint8_t subtype = data[2]; 225922a5394SMatthias Ringwald if (subtype != 0) break; 226922a5394SMatthias Ringwald // flags 227922a5394SMatthias Ringwald uint8_t flags = data[3]; 228922a5394SMatthias Ringwald // num channels 229922a5394SMatthias Ringwald num_channels = data[4]; 230922a5394SMatthias Ringwald if (num_channels > 2) break; 231922a5394SMatthias Ringwald // sampling frequency 232922a5394SMatthias Ringwald sampling_frequency_hz = 1000 * data[5]; 233922a5394SMatthias Ringwald // frame duration 234922a5394SMatthias Ringwald frame_duration = data[6] == 0 ? BTSTACK_LC3_FRAME_DURATION_7500US : BTSTACK_LC3_FRAME_DURATION_10000US; 235922a5394SMatthias Ringwald // octets per frame 236922a5394SMatthias Ringwald octets_per_frame = data[7]; 237922a5394SMatthias Ringwald // done 238922a5394SMatthias Ringwald found = true; 239922a5394SMatthias Ringwald } 240922a5394SMatthias Ringwald break; 241922a5394SMatthias Ringwald case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME: 242922a5394SMatthias Ringwald case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME: 243922a5394SMatthias Ringwald size = btstack_min(sizeof(remote_name) - 1, size); 244922a5394SMatthias Ringwald memcpy(remote_name, data, size); 245922a5394SMatthias Ringwald remote_name[size] = 0; 246922a5394SMatthias Ringwald break; 247922a5394SMatthias Ringwald default: 248922a5394SMatthias Ringwald break; 249922a5394SMatthias Ringwald } 250922a5394SMatthias Ringwald } 251922a5394SMatthias Ringwald if (!found) break; 252922a5394SMatthias Ringwald remote_type = gap_event_advertising_report_get_address_type(packet); 253922a5394SMatthias Ringwald printf("Remote Unicast source found, addr %s, name: '%s'\n", bd_addr_to_str(remote_addr), remote_name); 254922a5394SMatthias Ringwald // stop scanning 255922a5394SMatthias Ringwald app_state = APP_W4_CIS_CREATED; 256922a5394SMatthias Ringwald gap_stop_scan(); 257922a5394SMatthias Ringwald gap_connect(remote_addr, remote_type); 258922a5394SMatthias Ringwald break; 259922a5394SMatthias Ringwald } 260922a5394SMatthias Ringwald 261922a5394SMatthias Ringwald case HCI_EVENT_LE_META: 262922a5394SMatthias Ringwald switch(hci_event_le_meta_get_subevent_code(packet)) { 263922a5394SMatthias Ringwald case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: 264922a5394SMatthias Ringwald enter_streaming(); 265922a5394SMatthias Ringwald hci_subevent_le_connection_complete_get_peer_address(packet, event_addr); 266922a5394SMatthias Ringwald remote_handle = hci_subevent_le_connection_complete_get_connection_handle(packet); 267922a5394SMatthias Ringwald printf("Connected, remote %s, handle %04x\n", bd_addr_to_str(event_addr), remote_handle); 268922a5394SMatthias Ringwald create_cig(); 269922a5394SMatthias Ringwald break; 270922a5394SMatthias Ringwald default: 271922a5394SMatthias Ringwald break; 272922a5394SMatthias Ringwald } 273922a5394SMatthias Ringwald break; 274922a5394SMatthias Ringwald case HCI_EVENT_META_GAP: 275922a5394SMatthias Ringwald switch (hci_event_gap_meta_get_subevent_code(packet)){ 276922a5394SMatthias Ringwald case GAP_SUBEVENT_CIG_CREATED: 277922a5394SMatthias Ringwald if (app_state == APP_W4_CIG_COMPLETE){ 278922a5394SMatthias Ringwald printf("CIS Connection Handles: "); 279922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 280922a5394SMatthias Ringwald cis_con_handles[i] = gap_subevent_cig_created_get_cis_con_handles(packet, i); 281922a5394SMatthias Ringwald printf("0x%04x ", cis_con_handles[i]); 282922a5394SMatthias Ringwald } 283922a5394SMatthias Ringwald printf("\n"); 284922a5394SMatthias Ringwald 285922a5394SMatthias Ringwald printf("Create CIS\n"); 286922a5394SMatthias Ringwald hci_con_handle_t acl_connection_handles[MAX_CHANNELS]; 287922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 288922a5394SMatthias Ringwald acl_connection_handles[i] = remote_handle; 289922a5394SMatthias Ringwald } 290922a5394SMatthias Ringwald gap_cis_create(cig_params.cig_id, cis_con_handles, acl_connection_handles); 291922a5394SMatthias Ringwald app_state = APP_W4_CIS_CREATED; 292922a5394SMatthias Ringwald } 293922a5394SMatthias Ringwald break; 294922a5394SMatthias Ringwald case GAP_SUBEVENT_CIS_CREATED: 295922a5394SMatthias Ringwald status = gap_subevent_big_created_get_status(packet); 296922a5394SMatthias Ringwald cis_handle = gap_subevent_cis_created_get_cis_con_handle(packet); 297922a5394SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 298922a5394SMatthias Ringwald // only look for cis handle 299922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 300922a5394SMatthias Ringwald if (cis_handle == cis_con_handles[i]){ 301922a5394SMatthias Ringwald cis_established[i] = true; 302922a5394SMatthias Ringwald } 303922a5394SMatthias Ringwald } 304922a5394SMatthias Ringwald // check for complete 305922a5394SMatthias Ringwald bool complete = true; 306922a5394SMatthias Ringwald for (i=0; i < num_cis; i++) { 307922a5394SMatthias Ringwald complete &= cis_established[i]; 308922a5394SMatthias Ringwald } 309922a5394SMatthias Ringwald if (complete) { 310922a5394SMatthias Ringwald printf("All CIS Established\n"); 311922a5394SMatthias Ringwald app_state = APP_STREAMING; 312922a5394SMatthias Ringwald // start sending 313922a5394SMatthias Ringwald if (microphone_enable){ 314922a5394SMatthias Ringwald hci_request_cis_can_send_now_events(cis_con_handles[0]); 315922a5394SMatthias Ringwald } 316922a5394SMatthias Ringwald } 317922a5394SMatthias Ringwald } else { 318922a5394SMatthias Ringwald printf("CIS Create failed with status 0x%02x for con handle 0x%04x\n", status, cis_handle); 319922a5394SMatthias Ringwald } 320922a5394SMatthias Ringwald break; 321922a5394SMatthias Ringwald default: 322922a5394SMatthias Ringwald break; 323922a5394SMatthias Ringwald } 324922a5394SMatthias Ringwald break; 325922a5394SMatthias Ringwald case HCI_EVENT_CIS_CAN_SEND_NOW: 326922a5394SMatthias Ringwald le_audio_demo_util_source_send(0, cis_con_handles[0]); 327922a5394SMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(AUDIO_SOURCE_SINE); 328922a5394SMatthias Ringwald hci_request_cis_can_send_now_events(cis_con_handles[0]); 329922a5394SMatthias Ringwald break; 330922a5394SMatthias Ringwald default: 331922a5394SMatthias Ringwald break; 332922a5394SMatthias Ringwald } 333922a5394SMatthias Ringwald } 334922a5394SMatthias Ringwald 335922a5394SMatthias Ringwald static void iso_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 336922a5394SMatthias Ringwald le_audio_demo_util_sink_receive(0, packet, size); 337922a5394SMatthias Ringwald } 338922a5394SMatthias Ringwald 339922a5394SMatthias Ringwald static void show_usage(void){ 340922a5394SMatthias Ringwald printf("\n--- LE Audio Unicast Sink Test Console ---\n"); 341922a5394SMatthias Ringwald printf("s - start scanning\n"); 342922a5394SMatthias Ringwald #ifdef HAVE_LC3PLUS 343922a5394SMatthias Ringwald printf("q - use LC3plus decoder if 10 ms ISO interval is used\n"); 344922a5394SMatthias Ringwald #endif 345922a5394SMatthias Ringwald printf("m - enable virtual microphone\n"); 346922a5394SMatthias Ringwald printf("---\n"); 347922a5394SMatthias Ringwald } 348922a5394SMatthias Ringwald 349922a5394SMatthias Ringwald static void stdin_process(char c){ 350922a5394SMatthias Ringwald switch (c){ 351922a5394SMatthias Ringwald case 's': 352922a5394SMatthias Ringwald if (app_state != APP_W4_WORKING) break; 353922a5394SMatthias Ringwald start_scanning(); 354922a5394SMatthias Ringwald break; 355922a5394SMatthias Ringwald #ifdef HAVE_LC3PLUS 356922a5394SMatthias Ringwald case 'q': 357922a5394SMatthias Ringwald printf("Use LC3 Plust for 10 ms frames\n"); 358*1eafc990SEdison David le_audio_demo_util_sink_enable_lc3plus(true); 359922a5394SMatthias Ringwald break; 360922a5394SMatthias Ringwald #endif 361922a5394SMatthias Ringwald case 'm': 362922a5394SMatthias Ringwald printf("Enable virtual microphone\n"); 363922a5394SMatthias Ringwald microphone_enable = true; 364922a5394SMatthias Ringwald break; 365922a5394SMatthias Ringwald case '\n': 366922a5394SMatthias Ringwald case '\r': 367922a5394SMatthias Ringwald break; 368922a5394SMatthias Ringwald default: 369922a5394SMatthias Ringwald show_usage(); 370922a5394SMatthias Ringwald break; 371922a5394SMatthias Ringwald 372922a5394SMatthias Ringwald } 373922a5394SMatthias Ringwald } 374922a5394SMatthias Ringwald 375922a5394SMatthias Ringwald int btstack_main(int argc, const char * argv[]); 376922a5394SMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 377922a5394SMatthias Ringwald (void) argv; 378922a5394SMatthias Ringwald (void) argc; 379922a5394SMatthias Ringwald 380922a5394SMatthias Ringwald // register for HCI events 381922a5394SMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 382922a5394SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 383922a5394SMatthias Ringwald 384922a5394SMatthias Ringwald // register for ISO Packet 385922a5394SMatthias Ringwald hci_register_iso_packet_handler(&iso_packet_handler); 386922a5394SMatthias Ringwald 387922a5394SMatthias Ringwald // setup audio processing 388922a5394SMatthias Ringwald le_audio_demo_util_sink_init("le_audio_unicast_sink.wav"); 389922a5394SMatthias Ringwald le_audio_demo_util_source_init(); 390922a5394SMatthias Ringwald 391922a5394SMatthias Ringwald // turn on! 392922a5394SMatthias Ringwald hci_power_control(HCI_POWER_ON); 393922a5394SMatthias Ringwald 394922a5394SMatthias Ringwald btstack_stdin_setup(stdin_process); 395922a5394SMatthias Ringwald return 0; 396922a5394SMatthias Ringwald } 397