1*922a5394SMatthias Ringwald /* 2*922a5394SMatthias Ringwald * Copyright (C) 2022 BlueKitchen GmbH 3*922a5394SMatthias Ringwald * 4*922a5394SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*922a5394SMatthias Ringwald * modification, are permitted provided that the following conditions 6*922a5394SMatthias Ringwald * are met: 7*922a5394SMatthias Ringwald * 8*922a5394SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*922a5394SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*922a5394SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*922a5394SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*922a5394SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*922a5394SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*922a5394SMatthias Ringwald * contributors may be used to endorse or promote products derived 15*922a5394SMatthias Ringwald * from this software without specific prior written permission. 16*922a5394SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*922a5394SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*922a5394SMatthias Ringwald * monetary gain. 19*922a5394SMatthias Ringwald * 20*922a5394SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*922a5394SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*922a5394SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*922a5394SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24*922a5394SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*922a5394SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*922a5394SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*922a5394SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*922a5394SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*922a5394SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*922a5394SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*922a5394SMatthias Ringwald * SUCH DAMAGE. 32*922a5394SMatthias Ringwald * 33*922a5394SMatthias Ringwald * Please inquire about commercial licensing options at 34*922a5394SMatthias Ringwald * [email protected] 35*922a5394SMatthias Ringwald * 36*922a5394SMatthias Ringwald */ 37*922a5394SMatthias Ringwald 38*922a5394SMatthias Ringwald #define BTSTACK_FILE__ "le_audio_unicast_sink.c" 39*922a5394SMatthias Ringwald 40*922a5394SMatthias Ringwald /* 41*922a5394SMatthias Ringwald * LE Audio Unicast Sink 42*922a5394SMatthias Ringwald * Until GATT Services are available, we encode LC3 config in advertising 43*922a5394SMatthias Ringwald */ 44*922a5394SMatthias Ringwald 45*922a5394SMatthias Ringwald 46*922a5394SMatthias Ringwald #include "btstack_config.h" 47*922a5394SMatthias Ringwald 48*922a5394SMatthias Ringwald #include <stdint.h> 49*922a5394SMatthias Ringwald #include <stdio.h> 50*922a5394SMatthias Ringwald #include <stdlib.h> 51*922a5394SMatthias Ringwald #include <string.h> 52*922a5394SMatthias Ringwald 53*922a5394SMatthias Ringwald #include "ad_parser.h" 54*922a5394SMatthias Ringwald #include "bluetooth_data_types.h" 55*922a5394SMatthias Ringwald #include "bluetooth_company_id.h" 56*922a5394SMatthias Ringwald #include "btstack_debug.h" 57*922a5394SMatthias Ringwald #include "btstack_event.h" 58*922a5394SMatthias Ringwald #include "btstack_stdin.h" 59*922a5394SMatthias Ringwald #include "gap.h" 60*922a5394SMatthias Ringwald #include "hci.h" 61*922a5394SMatthias Ringwald #include "le_audio_demo_util_sink.h" 62*922a5394SMatthias Ringwald #include "le_audio_demo_util_source.h" 63*922a5394SMatthias Ringwald 64*922a5394SMatthias Ringwald // max config 65*922a5394SMatthias Ringwald #define MAX_CHANNELS 2 66*922a5394SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480 67*922a5394SMatthias Ringwald 68*922a5394SMatthias Ringwald static void show_usage(void); 69*922a5394SMatthias Ringwald 70*922a5394SMatthias Ringwald static enum { 71*922a5394SMatthias Ringwald APP_W4_WORKING, 72*922a5394SMatthias Ringwald APP_W4_SOURCE_ADV, 73*922a5394SMatthias Ringwald APP_W4_CIG_COMPLETE, 74*922a5394SMatthias Ringwald APP_W4_CIS_CREATED, 75*922a5394SMatthias Ringwald APP_STREAMING, 76*922a5394SMatthias Ringwald APP_IDLE, 77*922a5394SMatthias Ringwald } app_state = APP_W4_WORKING; 78*922a5394SMatthias Ringwald 79*922a5394SMatthias Ringwald // 80*922a5394SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 81*922a5394SMatthias Ringwald 82*922a5394SMatthias Ringwald // remote info 83*922a5394SMatthias Ringwald static char remote_name[20]; 84*922a5394SMatthias Ringwald static bd_addr_t remote_addr; 85*922a5394SMatthias Ringwald static bd_addr_type_t remote_type; 86*922a5394SMatthias Ringwald static hci_con_handle_t remote_handle; 87*922a5394SMatthias Ringwald 88*922a5394SMatthias Ringwald static le_audio_cig_t cig; 89*922a5394SMatthias Ringwald static le_audio_cig_params_t cig_params; 90*922a5394SMatthias Ringwald 91*922a5394SMatthias Ringwald // iso info 92*922a5394SMatthias Ringwald static bool framed_pdus; 93*922a5394SMatthias Ringwald static uint16_t frame_duration_us; 94*922a5394SMatthias Ringwald 95*922a5394SMatthias Ringwald static uint8_t num_cis; 96*922a5394SMatthias Ringwald static hci_con_handle_t cis_con_handles[MAX_CHANNELS]; 97*922a5394SMatthias Ringwald static bool cis_established[MAX_CHANNELS]; 98*922a5394SMatthias Ringwald 99*922a5394SMatthias Ringwald // lc3 codec config 100*922a5394SMatthias Ringwald static uint16_t sampling_frequency_hz; 101*922a5394SMatthias Ringwald static btstack_lc3_frame_duration_t frame_duration; 102*922a5394SMatthias Ringwald static uint16_t number_samples_per_frame; 103*922a5394SMatthias Ringwald static uint16_t octets_per_frame; 104*922a5394SMatthias Ringwald static uint8_t num_channels; 105*922a5394SMatthias Ringwald 106*922a5394SMatthias Ringwald // microphone 107*922a5394SMatthias Ringwald static bool microphone_enable; 108*922a5394SMatthias Ringwald 109*922a5394SMatthias Ringwald static void start_scanning() { 110*922a5394SMatthias Ringwald app_state = APP_W4_SOURCE_ADV; 111*922a5394SMatthias Ringwald gap_set_scan_params(1, 0x30, 0x30, 0); 112*922a5394SMatthias Ringwald gap_start_scan(); 113*922a5394SMatthias Ringwald printf("Start scan..\n"); 114*922a5394SMatthias Ringwald } 115*922a5394SMatthias Ringwald 116*922a5394SMatthias Ringwald static void create_cig() { 117*922a5394SMatthias Ringwald if (sampling_frequency_hz == 44100){ 118*922a5394SMatthias Ringwald framed_pdus = 1; 119*922a5394SMatthias Ringwald // same config as for 48k -> frame is longer by 48/44.1 120*922a5394SMatthias Ringwald frame_duration_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8163 : 10884; 121*922a5394SMatthias Ringwald } else { 122*922a5394SMatthias Ringwald framed_pdus = 0; 123*922a5394SMatthias Ringwald frame_duration_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 7500 : 10000; 124*922a5394SMatthias Ringwald } 125*922a5394SMatthias Ringwald 126*922a5394SMatthias Ringwald printf("Send: LE Set CIG Parameters\n"); 127*922a5394SMatthias Ringwald 128*922a5394SMatthias Ringwald num_cis = 1; 129*922a5394SMatthias Ringwald cig_params.cig_id = 0; 130*922a5394SMatthias Ringwald cig_params.num_cis = 1; 131*922a5394SMatthias Ringwald cig_params.sdu_interval_c_to_p = frame_duration_us; 132*922a5394SMatthias Ringwald cig_params.sdu_interval_p_to_c = frame_duration_us; 133*922a5394SMatthias Ringwald cig_params.worst_case_sca = 0; // 251 ppm to 500 ppm 134*922a5394SMatthias Ringwald cig_params.packing = 0; // sequential 135*922a5394SMatthias Ringwald cig_params.framing = framed_pdus; 136*922a5394SMatthias Ringwald cig_params.max_transport_latency_c_to_p = 40; 137*922a5394SMatthias Ringwald cig_params.max_transport_latency_p_to_c = 40; 138*922a5394SMatthias Ringwald uint8_t i; 139*922a5394SMatthias Ringwald uint16_t max_sdu_c_to_p = microphone_enable ? octets_per_frame : 0; 140*922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 141*922a5394SMatthias Ringwald cig_params.cis_params[i].cis_id = i; 142*922a5394SMatthias Ringwald cig_params.cis_params[i].max_sdu_c_to_p = max_sdu_c_to_p; 143*922a5394SMatthias Ringwald cig_params.cis_params[i].max_sdu_p_to_c = num_channels * octets_per_frame; 144*922a5394SMatthias Ringwald cig_params.cis_params[i].phy_c_to_p = 2; // 2M 145*922a5394SMatthias Ringwald cig_params.cis_params[i].phy_p_to_c = 2; // 2M 146*922a5394SMatthias Ringwald cig_params.cis_params[i].rtn_c_to_p = 2; 147*922a5394SMatthias Ringwald cig_params.cis_params[i].rtn_p_to_c = 2; 148*922a5394SMatthias Ringwald } 149*922a5394SMatthias Ringwald 150*922a5394SMatthias Ringwald app_state = APP_W4_CIG_COMPLETE; 151*922a5394SMatthias Ringwald gap_cig_create(&cig, &cig_params); 152*922a5394SMatthias Ringwald } 153*922a5394SMatthias Ringwald 154*922a5394SMatthias Ringwald static void enter_streaming(void){ 155*922a5394SMatthias Ringwald // init source 156*922a5394SMatthias Ringwald if (microphone_enable){ 157*922a5394SMatthias Ringwald le_audio_demo_util_source_configure(1, 1, sampling_frequency_hz, frame_duration, octets_per_frame); 158*922a5394SMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(AUDIO_SOURCE_SINE); 159*922a5394SMatthias Ringwald } 160*922a5394SMatthias Ringwald // init sink 161*922a5394SMatthias Ringwald uint16_t iso_interval_1250us = frame_duration_us / 1250; 162*922a5394SMatthias Ringwald uint8_t flush_timeout = 1; 163*922a5394SMatthias Ringwald le_audio_demo_util_sink_configure_unicast(1, num_channels, sampling_frequency_hz, frame_duration, octets_per_frame, 164*922a5394SMatthias Ringwald iso_interval_1250us, flush_timeout); 165*922a5394SMatthias Ringwald printf("Configure: %u channels, sampling rate %u, samples per frame %u\n", num_channels, sampling_frequency_hz, number_samples_per_frame); 166*922a5394SMatthias Ringwald } 167*922a5394SMatthias Ringwald 168*922a5394SMatthias Ringwald 169*922a5394SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 170*922a5394SMatthias Ringwald UNUSED(channel); 171*922a5394SMatthias Ringwald bd_addr_t event_addr; 172*922a5394SMatthias Ringwald hci_con_handle_t cis_handle; 173*922a5394SMatthias Ringwald unsigned int i; 174*922a5394SMatthias Ringwald uint8_t status; 175*922a5394SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 176*922a5394SMatthias Ringwald switch (packet[0]) { 177*922a5394SMatthias Ringwald case BTSTACK_EVENT_STATE: 178*922a5394SMatthias Ringwald switch(btstack_event_state_get_state(packet)) { 179*922a5394SMatthias Ringwald case HCI_STATE_WORKING: 180*922a5394SMatthias Ringwald #ifdef ENABLE_DEMO_MODE 181*922a5394SMatthias Ringwald if (app_state != APP_W4_WORKING) break; 182*922a5394SMatthias Ringwald start_scanning(); 183*922a5394SMatthias Ringwald #else 184*922a5394SMatthias Ringwald show_usage(); 185*922a5394SMatthias Ringwald #endif 186*922a5394SMatthias Ringwald break; 187*922a5394SMatthias Ringwald case HCI_STATE_OFF: 188*922a5394SMatthias Ringwald printf("Goodbye\n"); 189*922a5394SMatthias Ringwald exit(0); 190*922a5394SMatthias Ringwald break; 191*922a5394SMatthias Ringwald default: 192*922a5394SMatthias Ringwald break; 193*922a5394SMatthias Ringwald } 194*922a5394SMatthias Ringwald break; 195*922a5394SMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 196*922a5394SMatthias Ringwald if (hci_event_disconnection_complete_get_connection_handle(packet) == remote_handle){ 197*922a5394SMatthias Ringwald printf("Disconnected, back to scanning\n"); 198*922a5394SMatthias Ringwald le_audio_demo_util_sink_close(); 199*922a5394SMatthias Ringwald start_scanning(); 200*922a5394SMatthias Ringwald } 201*922a5394SMatthias Ringwald break; 202*922a5394SMatthias Ringwald case GAP_EVENT_ADVERTISING_REPORT: 203*922a5394SMatthias Ringwald { 204*922a5394SMatthias Ringwald if (app_state != APP_W4_SOURCE_ADV) break; 205*922a5394SMatthias Ringwald 206*922a5394SMatthias Ringwald gap_event_advertising_report_get_address(packet, remote_addr); 207*922a5394SMatthias Ringwald uint8_t adv_size = gap_event_advertising_report_get_data_length(packet); 208*922a5394SMatthias Ringwald const uint8_t * adv_data = gap_event_advertising_report_get_data(packet); 209*922a5394SMatthias Ringwald 210*922a5394SMatthias Ringwald ad_context_t context; 211*922a5394SMatthias Ringwald bool found = false; 212*922a5394SMatthias Ringwald remote_name[0] = '\0'; 213*922a5394SMatthias Ringwald uint16_t uuid; 214*922a5394SMatthias Ringwald uint16_t company_id; 215*922a5394SMatthias Ringwald for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)) { 216*922a5394SMatthias Ringwald uint8_t data_type = ad_iterator_get_data_type(&context); 217*922a5394SMatthias Ringwald uint8_t size = ad_iterator_get_data_len(&context); 218*922a5394SMatthias Ringwald const uint8_t *data = ad_iterator_get_data(&context); 219*922a5394SMatthias Ringwald switch (data_type){ 220*922a5394SMatthias Ringwald case BLUETOOTH_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA: 221*922a5394SMatthias Ringwald company_id = little_endian_read_16(data, 0); 222*922a5394SMatthias Ringwald if (company_id == BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH){ 223*922a5394SMatthias Ringwald // subtype = 0 -> le audio unicast source 224*922a5394SMatthias Ringwald uint8_t subtype = data[2]; 225*922a5394SMatthias Ringwald if (subtype != 0) break; 226*922a5394SMatthias Ringwald // flags 227*922a5394SMatthias Ringwald uint8_t flags = data[3]; 228*922a5394SMatthias Ringwald // num channels 229*922a5394SMatthias Ringwald num_channels = data[4]; 230*922a5394SMatthias Ringwald if (num_channels > 2) break; 231*922a5394SMatthias Ringwald // sampling frequency 232*922a5394SMatthias Ringwald sampling_frequency_hz = 1000 * data[5]; 233*922a5394SMatthias Ringwald // frame duration 234*922a5394SMatthias Ringwald frame_duration = data[6] == 0 ? BTSTACK_LC3_FRAME_DURATION_7500US : BTSTACK_LC3_FRAME_DURATION_10000US; 235*922a5394SMatthias Ringwald // octets per frame 236*922a5394SMatthias Ringwald octets_per_frame = data[7]; 237*922a5394SMatthias Ringwald // done 238*922a5394SMatthias Ringwald found = true; 239*922a5394SMatthias Ringwald } 240*922a5394SMatthias Ringwald break; 241*922a5394SMatthias Ringwald case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME: 242*922a5394SMatthias Ringwald case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME: 243*922a5394SMatthias Ringwald size = btstack_min(sizeof(remote_name) - 1, size); 244*922a5394SMatthias Ringwald memcpy(remote_name, data, size); 245*922a5394SMatthias Ringwald remote_name[size] = 0; 246*922a5394SMatthias Ringwald break; 247*922a5394SMatthias Ringwald default: 248*922a5394SMatthias Ringwald break; 249*922a5394SMatthias Ringwald } 250*922a5394SMatthias Ringwald } 251*922a5394SMatthias Ringwald if (!found) break; 252*922a5394SMatthias Ringwald remote_type = gap_event_advertising_report_get_address_type(packet); 253*922a5394SMatthias Ringwald printf("Remote Unicast source found, addr %s, name: '%s'\n", bd_addr_to_str(remote_addr), remote_name); 254*922a5394SMatthias Ringwald // stop scanning 255*922a5394SMatthias Ringwald app_state = APP_W4_CIS_CREATED; 256*922a5394SMatthias Ringwald gap_stop_scan(); 257*922a5394SMatthias Ringwald gap_connect(remote_addr, remote_type); 258*922a5394SMatthias Ringwald break; 259*922a5394SMatthias Ringwald } 260*922a5394SMatthias Ringwald 261*922a5394SMatthias Ringwald case HCI_EVENT_LE_META: 262*922a5394SMatthias Ringwald switch(hci_event_le_meta_get_subevent_code(packet)) { 263*922a5394SMatthias Ringwald case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: 264*922a5394SMatthias Ringwald enter_streaming(); 265*922a5394SMatthias Ringwald hci_subevent_le_connection_complete_get_peer_address(packet, event_addr); 266*922a5394SMatthias Ringwald remote_handle = hci_subevent_le_connection_complete_get_connection_handle(packet); 267*922a5394SMatthias Ringwald printf("Connected, remote %s, handle %04x\n", bd_addr_to_str(event_addr), remote_handle); 268*922a5394SMatthias Ringwald create_cig(); 269*922a5394SMatthias Ringwald break; 270*922a5394SMatthias Ringwald default: 271*922a5394SMatthias Ringwald break; 272*922a5394SMatthias Ringwald } 273*922a5394SMatthias Ringwald break; 274*922a5394SMatthias Ringwald case HCI_EVENT_META_GAP: 275*922a5394SMatthias Ringwald switch (hci_event_gap_meta_get_subevent_code(packet)){ 276*922a5394SMatthias Ringwald case GAP_SUBEVENT_CIG_CREATED: 277*922a5394SMatthias Ringwald if (app_state == APP_W4_CIG_COMPLETE){ 278*922a5394SMatthias Ringwald printf("CIS Connection Handles: "); 279*922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 280*922a5394SMatthias Ringwald cis_con_handles[i] = gap_subevent_cig_created_get_cis_con_handles(packet, i); 281*922a5394SMatthias Ringwald printf("0x%04x ", cis_con_handles[i]); 282*922a5394SMatthias Ringwald } 283*922a5394SMatthias Ringwald printf("\n"); 284*922a5394SMatthias Ringwald 285*922a5394SMatthias Ringwald printf("Create CIS\n"); 286*922a5394SMatthias Ringwald hci_con_handle_t acl_connection_handles[MAX_CHANNELS]; 287*922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 288*922a5394SMatthias Ringwald acl_connection_handles[i] = remote_handle; 289*922a5394SMatthias Ringwald } 290*922a5394SMatthias Ringwald gap_cis_create(cig_params.cig_id, cis_con_handles, acl_connection_handles); 291*922a5394SMatthias Ringwald app_state = APP_W4_CIS_CREATED; 292*922a5394SMatthias Ringwald } 293*922a5394SMatthias Ringwald break; 294*922a5394SMatthias Ringwald case GAP_SUBEVENT_CIS_CREATED: 295*922a5394SMatthias Ringwald status = gap_subevent_big_created_get_status(packet); 296*922a5394SMatthias Ringwald cis_handle = gap_subevent_cis_created_get_cis_con_handle(packet); 297*922a5394SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 298*922a5394SMatthias Ringwald // only look for cis handle 299*922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 300*922a5394SMatthias Ringwald if (cis_handle == cis_con_handles[i]){ 301*922a5394SMatthias Ringwald cis_established[i] = true; 302*922a5394SMatthias Ringwald } 303*922a5394SMatthias Ringwald } 304*922a5394SMatthias Ringwald // check for complete 305*922a5394SMatthias Ringwald bool complete = true; 306*922a5394SMatthias Ringwald for (i=0; i < num_cis; i++) { 307*922a5394SMatthias Ringwald complete &= cis_established[i]; 308*922a5394SMatthias Ringwald } 309*922a5394SMatthias Ringwald if (complete) { 310*922a5394SMatthias Ringwald printf("All CIS Established\n"); 311*922a5394SMatthias Ringwald app_state = APP_STREAMING; 312*922a5394SMatthias Ringwald // start sending 313*922a5394SMatthias Ringwald if (microphone_enable){ 314*922a5394SMatthias Ringwald hci_request_cis_can_send_now_events(cis_con_handles[0]); 315*922a5394SMatthias Ringwald } 316*922a5394SMatthias Ringwald } 317*922a5394SMatthias Ringwald } else { 318*922a5394SMatthias Ringwald printf("CIS Create failed with status 0x%02x for con handle 0x%04x\n", status, cis_handle); 319*922a5394SMatthias Ringwald } 320*922a5394SMatthias Ringwald break; 321*922a5394SMatthias Ringwald default: 322*922a5394SMatthias Ringwald break; 323*922a5394SMatthias Ringwald } 324*922a5394SMatthias Ringwald break; 325*922a5394SMatthias Ringwald case HCI_EVENT_CIS_CAN_SEND_NOW: 326*922a5394SMatthias Ringwald le_audio_demo_util_source_send(0, cis_con_handles[0]); 327*922a5394SMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(AUDIO_SOURCE_SINE); 328*922a5394SMatthias Ringwald hci_request_cis_can_send_now_events(cis_con_handles[0]); 329*922a5394SMatthias Ringwald break; 330*922a5394SMatthias Ringwald default: 331*922a5394SMatthias Ringwald break; 332*922a5394SMatthias Ringwald } 333*922a5394SMatthias Ringwald } 334*922a5394SMatthias Ringwald 335*922a5394SMatthias Ringwald static void iso_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 336*922a5394SMatthias Ringwald le_audio_demo_util_sink_receive(0, packet, size); 337*922a5394SMatthias Ringwald } 338*922a5394SMatthias Ringwald 339*922a5394SMatthias Ringwald static void show_usage(void){ 340*922a5394SMatthias Ringwald printf("\n--- LE Audio Unicast Sink Test Console ---\n"); 341*922a5394SMatthias Ringwald printf("s - start scanning\n"); 342*922a5394SMatthias Ringwald #ifdef HAVE_LC3PLUS 343*922a5394SMatthias Ringwald printf("q - use LC3plus decoder if 10 ms ISO interval is used\n"); 344*922a5394SMatthias Ringwald #endif 345*922a5394SMatthias Ringwald printf("m - enable virtual microphone\n"); 346*922a5394SMatthias Ringwald printf("---\n"); 347*922a5394SMatthias Ringwald } 348*922a5394SMatthias Ringwald 349*922a5394SMatthias Ringwald static void stdin_process(char c){ 350*922a5394SMatthias Ringwald switch (c){ 351*922a5394SMatthias Ringwald case 's': 352*922a5394SMatthias Ringwald if (app_state != APP_W4_WORKING) break; 353*922a5394SMatthias Ringwald start_scanning(); 354*922a5394SMatthias Ringwald break; 355*922a5394SMatthias Ringwald #ifdef HAVE_LC3PLUS 356*922a5394SMatthias Ringwald case 'q': 357*922a5394SMatthias Ringwald printf("Use LC3 Plust for 10 ms frames\n"); 358*922a5394SMatthias Ringwald le_audio_demo_sink_enable_lc3plus(true); 359*922a5394SMatthias Ringwald break; 360*922a5394SMatthias Ringwald #endif 361*922a5394SMatthias Ringwald case 'm': 362*922a5394SMatthias Ringwald printf("Enable virtual microphone\n"); 363*922a5394SMatthias Ringwald microphone_enable = true; 364*922a5394SMatthias Ringwald break; 365*922a5394SMatthias Ringwald case '\n': 366*922a5394SMatthias Ringwald case '\r': 367*922a5394SMatthias Ringwald break; 368*922a5394SMatthias Ringwald default: 369*922a5394SMatthias Ringwald show_usage(); 370*922a5394SMatthias Ringwald break; 371*922a5394SMatthias Ringwald 372*922a5394SMatthias Ringwald } 373*922a5394SMatthias Ringwald } 374*922a5394SMatthias Ringwald 375*922a5394SMatthias Ringwald int btstack_main(int argc, const char * argv[]); 376*922a5394SMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 377*922a5394SMatthias Ringwald (void) argv; 378*922a5394SMatthias Ringwald (void) argc; 379*922a5394SMatthias Ringwald 380*922a5394SMatthias Ringwald // register for HCI events 381*922a5394SMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 382*922a5394SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 383*922a5394SMatthias Ringwald 384*922a5394SMatthias Ringwald // register for ISO Packet 385*922a5394SMatthias Ringwald hci_register_iso_packet_handler(&iso_packet_handler); 386*922a5394SMatthias Ringwald 387*922a5394SMatthias Ringwald // setup audio processing 388*922a5394SMatthias Ringwald le_audio_demo_util_sink_init("le_audio_unicast_sink.wav"); 389*922a5394SMatthias Ringwald le_audio_demo_util_source_init(); 390*922a5394SMatthias Ringwald 391*922a5394SMatthias Ringwald // turn on! 392*922a5394SMatthias Ringwald hci_power_control(HCI_POWER_ON); 393*922a5394SMatthias Ringwald 394*922a5394SMatthias Ringwald btstack_stdin_setup(stdin_process); 395*922a5394SMatthias Ringwald return 0; 396*922a5394SMatthias Ringwald } 397