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_source.c" 39*922a5394SMatthias Ringwald 40*922a5394SMatthias Ringwald /* 41*922a5394SMatthias Ringwald * LE Audio Unicast Source 42*922a5394SMatthias Ringwald * Until GATT Services are available, we encode LC3 config in advertising 43*922a5394SMatthias Ringwald */ 44*922a5394SMatthias Ringwald 45*922a5394SMatthias Ringwald #include <stdint.h> 46*922a5394SMatthias Ringwald #include <stdio.h> 47*922a5394SMatthias Ringwald #include <string.h> 48*922a5394SMatthias Ringwald #include <btstack_debug.h> 49*922a5394SMatthias Ringwald 50*922a5394SMatthias Ringwald #include "bluetooth_data_types.h" 51*922a5394SMatthias Ringwald #include "bluetooth_company_id.h" 52*922a5394SMatthias Ringwald #include "btstack_stdin.h" 53*922a5394SMatthias Ringwald #include "btstack_event.h" 54*922a5394SMatthias Ringwald #include "gap.h" 55*922a5394SMatthias Ringwald #include "hci.h" 56*922a5394SMatthias Ringwald #include "btstack_lc3.h" 57*922a5394SMatthias Ringwald #include "btstack_lc3_google.h" 58*922a5394SMatthias Ringwald #include "le_audio_demo_util_source.h" 59*922a5394SMatthias Ringwald #include "le_audio_demo_util_sink.h" 60*922a5394SMatthias Ringwald 61*922a5394SMatthias Ringwald // max config 62*922a5394SMatthias Ringwald #define MAX_CHANNELS 2 63*922a5394SMatthias Ringwald #define MAX_NUM_CIS 1 64*922a5394SMatthias Ringwald 65*922a5394SMatthias Ringwald 66*922a5394SMatthias Ringwald static uint8_t adv_data[] = { 67*922a5394SMatthias Ringwald // Manufacturer Specific Data to indicate codec 68*922a5394SMatthias Ringwald 9, 69*922a5394SMatthias Ringwald BLUETOOTH_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA, 70*922a5394SMatthias Ringwald BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH & 0xff, 71*922a5394SMatthias Ringwald BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH >> 8, 72*922a5394SMatthias Ringwald 0, // subtype: LE Audio Connection Source 73*922a5394SMatthias Ringwald 0, // flags 74*922a5394SMatthias Ringwald 1, // num bis 75*922a5394SMatthias Ringwald 8, // sampling frequency in khz 76*922a5394SMatthias Ringwald 0, // frame duration 77*922a5394SMatthias Ringwald 26, // octets per frame 78*922a5394SMatthias Ringwald // name 79*922a5394SMatthias Ringwald 7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'S', 'o', 'u', 'r', 'c', 'e' 80*922a5394SMatthias Ringwald }; 81*922a5394SMatthias Ringwald 82*922a5394SMatthias Ringwald static bd_addr_t remote; 83*922a5394SMatthias Ringwald 84*922a5394SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 85*922a5394SMatthias Ringwald 86*922a5394SMatthias Ringwald static unsigned int next_cis_index; 87*922a5394SMatthias Ringwald static hci_con_handle_t cis_con_handles[MAX_NUM_CIS]; 88*922a5394SMatthias Ringwald static bool cis_established[MAX_NUM_CIS]; 89*922a5394SMatthias Ringwald static uint8_t iso_frame_counter; 90*922a5394SMatthias Ringwald static uint8_t num_cis; 91*922a5394SMatthias Ringwald 92*922a5394SMatthias Ringwald // time stamping 93*922a5394SMatthias Ringwald #ifdef COUNT_MODE 94*922a5394SMatthias Ringwald #define MAX_PACKET_INTERVAL_BINS_MS 50 95*922a5394SMatthias Ringwald static uint32_t send_time_bins[MAX_PACKET_INTERVAL_BINS_MS]; 96*922a5394SMatthias Ringwald static uint32_t send_last_ms; 97*922a5394SMatthias Ringwald #endif 98*922a5394SMatthias Ringwald 99*922a5394SMatthias Ringwald // lc3 codec config 100*922a5394SMatthias Ringwald static uint32_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 = 1; 105*922a5394SMatthias Ringwald 106*922a5394SMatthias Ringwald // codec menu 107*922a5394SMatthias Ringwald static uint8_t menu_sampling_frequency; 108*922a5394SMatthias Ringwald static uint8_t menu_variant; 109*922a5394SMatthias Ringwald 110*922a5394SMatthias Ringwald // audio producer 111*922a5394SMatthias Ringwald static le_audio_demo_source_generator audio_source = AUDIO_SOURCE_MODPLAYER; 112*922a5394SMatthias Ringwald 113*922a5394SMatthias Ringwald static enum { 114*922a5394SMatthias Ringwald APP_W4_WORKING, 115*922a5394SMatthias Ringwald APP_IDLE, 116*922a5394SMatthias Ringwald APP_W4_CIS_COMPLETE, 117*922a5394SMatthias Ringwald APP_STREAMING, 118*922a5394SMatthias Ringwald } app_state = APP_W4_WORKING; 119*922a5394SMatthias Ringwald 120*922a5394SMatthias Ringwald // enumerate default codec configs 121*922a5394SMatthias Ringwald static struct { 122*922a5394SMatthias Ringwald uint16_t samplingrate_hz; 123*922a5394SMatthias Ringwald uint8_t samplingrate_index; 124*922a5394SMatthias Ringwald uint8_t num_variants; 125*922a5394SMatthias Ringwald struct { 126*922a5394SMatthias Ringwald const char * name; 127*922a5394SMatthias Ringwald btstack_lc3_frame_duration_t frame_duration; 128*922a5394SMatthias Ringwald uint16_t octets_per_frame; 129*922a5394SMatthias Ringwald } variants[6]; 130*922a5394SMatthias Ringwald } codec_configurations[] = { 131*922a5394SMatthias Ringwald { 132*922a5394SMatthias Ringwald 8000, 0x01, 2, 133*922a5394SMatthias Ringwald { 134*922a5394SMatthias Ringwald { "8_1", BTSTACK_LC3_FRAME_DURATION_7500US, 26}, 135*922a5394SMatthias Ringwald { "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30} 136*922a5394SMatthias Ringwald } 137*922a5394SMatthias Ringwald }, 138*922a5394SMatthias Ringwald { 139*922a5394SMatthias Ringwald 16000, 0x03, 2, 140*922a5394SMatthias Ringwald { 141*922a5394SMatthias Ringwald { "16_1", BTSTACK_LC3_FRAME_DURATION_7500US, 30}, 142*922a5394SMatthias Ringwald { "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40} 143*922a5394SMatthias Ringwald } 144*922a5394SMatthias Ringwald }, 145*922a5394SMatthias Ringwald { 146*922a5394SMatthias Ringwald 24000, 0x05, 2, 147*922a5394SMatthias Ringwald { 148*922a5394SMatthias Ringwald { "24_1", BTSTACK_LC3_FRAME_DURATION_7500US, 45}, 149*922a5394SMatthias Ringwald { "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60} 150*922a5394SMatthias Ringwald } 151*922a5394SMatthias Ringwald }, 152*922a5394SMatthias Ringwald { 153*922a5394SMatthias Ringwald 32000, 0x06, 2, 154*922a5394SMatthias Ringwald { 155*922a5394SMatthias Ringwald { "32_1", BTSTACK_LC3_FRAME_DURATION_7500US, 60}, 156*922a5394SMatthias Ringwald { "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80} 157*922a5394SMatthias Ringwald } 158*922a5394SMatthias Ringwald }, 159*922a5394SMatthias Ringwald { 160*922a5394SMatthias Ringwald 44100, 0x07, 2, 161*922a5394SMatthias Ringwald { 162*922a5394SMatthias Ringwald { "441_1", BTSTACK_LC3_FRAME_DURATION_7500US, 97}, 163*922a5394SMatthias Ringwald { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130} 164*922a5394SMatthias Ringwald } 165*922a5394SMatthias Ringwald }, 166*922a5394SMatthias Ringwald { 167*922a5394SMatthias Ringwald 48000, 0x08, 6, 168*922a5394SMatthias Ringwald { 169*922a5394SMatthias Ringwald { "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75}, 170*922a5394SMatthias Ringwald { "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100}, 171*922a5394SMatthias Ringwald { "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90}, 172*922a5394SMatthias Ringwald { "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120}, 173*922a5394SMatthias Ringwald { "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117}, 174*922a5394SMatthias Ringwald { "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155} 175*922a5394SMatthias Ringwald } 176*922a5394SMatthias Ringwald }, 177*922a5394SMatthias Ringwald }; 178*922a5394SMatthias Ringwald 179*922a5394SMatthias Ringwald static void show_usage(void); 180*922a5394SMatthias Ringwald 181*922a5394SMatthias Ringwald static void print_config(void) { 182*922a5394SMatthias Ringwald printf("Config '%s_%u': %u, %s ms, %u octets - %s\n", 183*922a5394SMatthias Ringwald codec_configurations[menu_sampling_frequency].variants[menu_variant].name, 184*922a5394SMatthias Ringwald num_channels, 185*922a5394SMatthias Ringwald codec_configurations[menu_sampling_frequency].samplingrate_hz, 186*922a5394SMatthias Ringwald codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10", 187*922a5394SMatthias Ringwald codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame, 188*922a5394SMatthias Ringwald audio_source == AUDIO_SOURCE_SINE ? "Sine" : "Modplayer"); 189*922a5394SMatthias Ringwald } 190*922a5394SMatthias Ringwald 191*922a5394SMatthias Ringwald static void start_unicast() { 192*922a5394SMatthias Ringwald // use values from table 193*922a5394SMatthias Ringwald sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz; 194*922a5394SMatthias Ringwald octets_per_frame = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame; 195*922a5394SMatthias Ringwald frame_duration = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration; 196*922a5394SMatthias Ringwald 197*922a5394SMatthias Ringwald le_audio_demo_util_source_configure(1, num_channels, sampling_frequency_hz, frame_duration, octets_per_frame); 198*922a5394SMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(audio_source); 199*922a5394SMatthias Ringwald 200*922a5394SMatthias Ringwald // update adv / BASE 201*922a5394SMatthias Ringwald adv_data[4] = 0; // subtype 202*922a5394SMatthias Ringwald adv_data[5] = 0; // flags 203*922a5394SMatthias Ringwald adv_data[6] = num_channels; 204*922a5394SMatthias Ringwald adv_data[7] = sampling_frequency_hz / 1000; 205*922a5394SMatthias Ringwald adv_data[8] = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 0 : 1; 206*922a5394SMatthias Ringwald adv_data[9] = octets_per_frame; 207*922a5394SMatthias Ringwald 208*922a5394SMatthias Ringwald // setup advertisements 209*922a5394SMatthias Ringwald uint16_t adv_int_min = 0x0030; 210*922a5394SMatthias Ringwald uint16_t adv_int_max = 0x0030; 211*922a5394SMatthias Ringwald uint8_t adv_type = 0; 212*922a5394SMatthias Ringwald bd_addr_t null_addr; 213*922a5394SMatthias Ringwald memset(null_addr, 0, 6); 214*922a5394SMatthias Ringwald gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); 215*922a5394SMatthias Ringwald gap_advertisements_set_data(sizeof(adv_data), adv_data); 216*922a5394SMatthias Ringwald gap_advertisements_enable(1); 217*922a5394SMatthias Ringwald num_cis = 1; 218*922a5394SMatthias Ringwald app_state = APP_W4_CIS_COMPLETE; 219*922a5394SMatthias Ringwald } 220*922a5394SMatthias Ringwald 221*922a5394SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 222*922a5394SMatthias Ringwald UNUSED(channel); 223*922a5394SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 224*922a5394SMatthias Ringwald 225*922a5394SMatthias Ringwald hci_con_handle_t cis_con_handle; 226*922a5394SMatthias Ringwald uint8_t i; 227*922a5394SMatthias Ringwald 228*922a5394SMatthias Ringwald switch (packet[0]) { 229*922a5394SMatthias Ringwald case BTSTACK_EVENT_STATE: 230*922a5394SMatthias Ringwald switch(btstack_event_state_get_state(packet)) { 231*922a5394SMatthias Ringwald case HCI_STATE_WORKING: 232*922a5394SMatthias Ringwald app_state = APP_IDLE; 233*922a5394SMatthias Ringwald #ifdef ENABLE_DEMO_MODE 234*922a5394SMatthias Ringwald // start unicast automatically, mod player, 48_5_2 235*922a5394SMatthias Ringwald num_channels = 2; 236*922a5394SMatthias Ringwald menu_sampling_frequency = 5; 237*922a5394SMatthias Ringwald menu_variant = 4; 238*922a5394SMatthias Ringwald start_unicast(); 239*922a5394SMatthias Ringwald #else 240*922a5394SMatthias Ringwald show_usage(); 241*922a5394SMatthias Ringwald printf("Please select sample frequency and variation, then start advertising\n"); 242*922a5394SMatthias Ringwald #endif 243*922a5394SMatthias Ringwald break; 244*922a5394SMatthias Ringwald case HCI_STATE_OFF: 245*922a5394SMatthias Ringwald printf("Goodbye\n"); 246*922a5394SMatthias Ringwald exit(0); 247*922a5394SMatthias Ringwald break; 248*922a5394SMatthias Ringwald default: 249*922a5394SMatthias Ringwald break; 250*922a5394SMatthias Ringwald } 251*922a5394SMatthias Ringwald break; 252*922a5394SMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 253*922a5394SMatthias Ringwald cis_con_handle = hci_event_disconnection_complete_get_connection_handle(packet); 254*922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 255*922a5394SMatthias Ringwald if (cis_con_handle == cis_con_handles[i]){ 256*922a5394SMatthias Ringwald le_audio_demo_util_sink_close(); 257*922a5394SMatthias Ringwald } 258*922a5394SMatthias Ringwald } 259*922a5394SMatthias Ringwald break; 260*922a5394SMatthias Ringwald case HCI_EVENT_LE_META: 261*922a5394SMatthias Ringwald switch(hci_event_le_meta_get_subevent_code(packet)){ 262*922a5394SMatthias Ringwald case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: 263*922a5394SMatthias Ringwald next_cis_index = 0; 264*922a5394SMatthias Ringwald break; 265*922a5394SMatthias Ringwald case HCI_SUBEVENT_LE_CIS_REQUEST: 266*922a5394SMatthias Ringwald cis_con_handles[next_cis_index] = hci_subevent_le_cis_request_get_cis_connection_handle(packet); 267*922a5394SMatthias Ringwald gap_cis_accept(cis_con_handles[next_cis_index]); 268*922a5394SMatthias Ringwald next_cis_index++; 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_CIS_CREATED: { 277*922a5394SMatthias Ringwald cis_con_handle = gap_subevent_cis_created_get_cis_con_handle(packet); 278*922a5394SMatthias Ringwald for (i=0; i < num_cis; i++){ 279*922a5394SMatthias Ringwald if (cis_con_handle == cis_con_handles[i]){ 280*922a5394SMatthias Ringwald cis_established[i] = true; 281*922a5394SMatthias Ringwald } 282*922a5394SMatthias Ringwald } 283*922a5394SMatthias Ringwald // check for complete 284*922a5394SMatthias Ringwald bool complete = true; 285*922a5394SMatthias Ringwald for (i=0; i < num_cis; i++) { 286*922a5394SMatthias Ringwald complete &= cis_established[i]; 287*922a5394SMatthias Ringwald } 288*922a5394SMatthias Ringwald // ready to send 289*922a5394SMatthias Ringwald if (complete) { 290*922a5394SMatthias Ringwald printf("All CIS Established and ISO Path setup\n"); 291*922a5394SMatthias Ringwald 292*922a5394SMatthias Ringwald // init sink 293*922a5394SMatthias Ringwald uint16_t iso_interval_1250us = gap_subevent_cis_created_get_iso_interval_1250us(packet); 294*922a5394SMatthias Ringwald uint8_t flush_timeout = gap_subevent_cis_created_get_flush_timeout_c_to_p(packet); 295*922a5394SMatthias Ringwald le_audio_demo_util_sink_configure_unicast(1, 1, sampling_frequency_hz, frame_duration, 296*922a5394SMatthias Ringwald octets_per_frame, 297*922a5394SMatthias Ringwald iso_interval_1250us, flush_timeout); 298*922a5394SMatthias Ringwald 299*922a5394SMatthias Ringwald next_cis_index = 0; 300*922a5394SMatthias Ringwald app_state = APP_STREAMING; 301*922a5394SMatthias Ringwald 302*922a5394SMatthias Ringwald hci_request_cis_can_send_now_events(cis_con_handles[0]); 303*922a5394SMatthias Ringwald } 304*922a5394SMatthias Ringwald break; 305*922a5394SMatthias Ringwald } 306*922a5394SMatthias Ringwald } 307*922a5394SMatthias Ringwald break; 308*922a5394SMatthias Ringwald case HCI_EVENT_CIS_CAN_SEND_NOW: 309*922a5394SMatthias Ringwald cis_con_handle = hci_event_cis_can_send_now_get_cis_con_handle(packet); 310*922a5394SMatthias Ringwald for (i=0;i<num_cis;i++){ 311*922a5394SMatthias Ringwald if (cis_con_handle == cis_con_handles[i]){ 312*922a5394SMatthias Ringwald // allow to send 313*922a5394SMatthias Ringwald le_audio_demo_util_source_send(i, cis_con_handle); 314*922a5394SMatthias Ringwald le_audio_demo_util_source_generate_iso_frame(audio_source); 315*922a5394SMatthias Ringwald hci_request_cis_can_send_now_events(cis_con_handle); 316*922a5394SMatthias Ringwald } 317*922a5394SMatthias Ringwald } 318*922a5394SMatthias Ringwald break; 319*922a5394SMatthias Ringwald 320*922a5394SMatthias Ringwald default: 321*922a5394SMatthias Ringwald break; 322*922a5394SMatthias Ringwald } 323*922a5394SMatthias Ringwald } 324*922a5394SMatthias Ringwald 325*922a5394SMatthias Ringwald static void iso_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 326*922a5394SMatthias Ringwald le_audio_demo_util_sink_receive(0, packet, size); 327*922a5394SMatthias Ringwald } 328*922a5394SMatthias Ringwald 329*922a5394SMatthias Ringwald static void show_usage(void){ 330*922a5394SMatthias Ringwald printf("\n--- LE Audio Unicast Source Test Console ---\n"); 331*922a5394SMatthias Ringwald print_config(); 332*922a5394SMatthias Ringwald printf("---\n"); 333*922a5394SMatthias Ringwald printf("c - toggle channels\n"); 334*922a5394SMatthias Ringwald printf("f - next sampling frequency\n"); 335*922a5394SMatthias Ringwald printf("v - next codec variant\n"); 336*922a5394SMatthias Ringwald printf("t - toggle sine / modplayer\n"); 337*922a5394SMatthias Ringwald printf("s - start advertising\n"); 338*922a5394SMatthias Ringwald printf("x - shutdown\n"); 339*922a5394SMatthias Ringwald printf("---\n"); 340*922a5394SMatthias Ringwald } 341*922a5394SMatthias Ringwald 342*922a5394SMatthias Ringwald static void stdin_process(char c){ 343*922a5394SMatthias Ringwald switch (c){ 344*922a5394SMatthias Ringwald case 'c': 345*922a5394SMatthias Ringwald if (app_state != APP_IDLE){ 346*922a5394SMatthias Ringwald printf("Codec configuration can only be changed in idle state\n"); 347*922a5394SMatthias Ringwald break; 348*922a5394SMatthias Ringwald } 349*922a5394SMatthias Ringwald num_channels = 3 - num_channels; 350*922a5394SMatthias Ringwald print_config(); 351*922a5394SMatthias Ringwald break; 352*922a5394SMatthias Ringwald case 'f': 353*922a5394SMatthias Ringwald if (app_state != APP_IDLE){ 354*922a5394SMatthias Ringwald printf("Codec configuration can only be changed in idle state\n"); 355*922a5394SMatthias Ringwald break; 356*922a5394SMatthias Ringwald } 357*922a5394SMatthias Ringwald menu_sampling_frequency++; 358*922a5394SMatthias Ringwald if (menu_sampling_frequency >= 6){ 359*922a5394SMatthias Ringwald menu_sampling_frequency = 0; 360*922a5394SMatthias Ringwald } 361*922a5394SMatthias Ringwald if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){ 362*922a5394SMatthias Ringwald menu_variant = 0; 363*922a5394SMatthias Ringwald } 364*922a5394SMatthias Ringwald print_config(); 365*922a5394SMatthias Ringwald break; 366*922a5394SMatthias Ringwald case 'v': 367*922a5394SMatthias Ringwald if (app_state != APP_IDLE){ 368*922a5394SMatthias Ringwald printf("Codec configuration can only be changed in idle state\n"); 369*922a5394SMatthias Ringwald break; 370*922a5394SMatthias Ringwald } 371*922a5394SMatthias Ringwald menu_variant++; 372*922a5394SMatthias Ringwald if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){ 373*922a5394SMatthias Ringwald menu_variant = 0; 374*922a5394SMatthias Ringwald } 375*922a5394SMatthias Ringwald print_config(); 376*922a5394SMatthias Ringwald break; 377*922a5394SMatthias Ringwald case 's': 378*922a5394SMatthias Ringwald if (app_state != APP_IDLE){ 379*922a5394SMatthias Ringwald printf("Cannot start advertising - not in idle state\n"); 380*922a5394SMatthias Ringwald break; 381*922a5394SMatthias Ringwald } 382*922a5394SMatthias Ringwald start_unicast(); 383*922a5394SMatthias Ringwald 384*922a5394SMatthias Ringwald break; 385*922a5394SMatthias Ringwald case 't': 386*922a5394SMatthias Ringwald audio_source = 1 - audio_source; 387*922a5394SMatthias Ringwald print_config(); 388*922a5394SMatthias Ringwald break; 389*922a5394SMatthias Ringwald case '\n': 390*922a5394SMatthias Ringwald case '\r': 391*922a5394SMatthias Ringwald break; 392*922a5394SMatthias Ringwald default: 393*922a5394SMatthias Ringwald show_usage(); 394*922a5394SMatthias Ringwald break; 395*922a5394SMatthias Ringwald } 396*922a5394SMatthias Ringwald } 397*922a5394SMatthias Ringwald 398*922a5394SMatthias Ringwald int btstack_main(int argc, const char * argv[]); 399*922a5394SMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 400*922a5394SMatthias Ringwald (void) argv; 401*922a5394SMatthias Ringwald (void) argc; 402*922a5394SMatthias Ringwald 403*922a5394SMatthias Ringwald // register for HCI events 404*922a5394SMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 405*922a5394SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 406*922a5394SMatthias Ringwald 407*922a5394SMatthias Ringwald // register for ISO Packet 408*922a5394SMatthias Ringwald hci_register_iso_packet_handler(&iso_packet_handler); 409*922a5394SMatthias Ringwald 410*922a5394SMatthias Ringwald // setup audio processing 411*922a5394SMatthias Ringwald le_audio_demo_util_sink_init("le_audio_unicast_source.wav"); 412*922a5394SMatthias Ringwald le_audio_demo_util_source_init(); 413*922a5394SMatthias Ringwald 414*922a5394SMatthias Ringwald // turn on! 415*922a5394SMatthias Ringwald hci_power_control(HCI_POWER_ON); 416*922a5394SMatthias Ringwald 417*922a5394SMatthias Ringwald btstack_stdin_setup(stdin_process); 418*922a5394SMatthias Ringwald return 0; 419*922a5394SMatthias Ringwald } 420