xref: /btstack/test/le_audio/le_audio_broadcast_source.c (revision dcd1707abac1c8773eea3b85c5ff5eaaddd4a115)
110277393SMatthias Ringwald /*
210277393SMatthias Ringwald  * Copyright (C) 2022 BlueKitchen GmbH
310277393SMatthias Ringwald  *
410277393SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
510277393SMatthias Ringwald  * modification, are permitted provided that the following conditions
610277393SMatthias Ringwald  * are met:
710277393SMatthias Ringwald  *
810277393SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
910277393SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
1010277393SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
1110277393SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
1210277393SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
1310277393SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
1410277393SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
1510277393SMatthias Ringwald  *    from this software without specific prior written permission.
1610277393SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
1710277393SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
1810277393SMatthias Ringwald  *    monetary gain.
1910277393SMatthias Ringwald  *
2010277393SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2110277393SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2210277393SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2310277393SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
2410277393SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2510277393SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2610277393SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2710277393SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2810277393SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2910277393SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3010277393SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3110277393SMatthias Ringwald  * SUCH DAMAGE.
3210277393SMatthias Ringwald  *
3310277393SMatthias Ringwald  * Please inquire about commercial licensing options at
3410277393SMatthias Ringwald  * [email protected]
3510277393SMatthias Ringwald  *
3610277393SMatthias Ringwald  */
3710277393SMatthias Ringwald 
3810277393SMatthias Ringwald #define BTSTACK_FILE__ "le_audio_broadcast_source.c"
3910277393SMatthias Ringwald 
4010277393SMatthias Ringwald /*
4110277393SMatthias Ringwald  * LE Audio Broadcast Source
4210277393SMatthias Ringwald  */
4310277393SMatthias Ringwald 
4410277393SMatthias Ringwald #include <stdint.h>
4510277393SMatthias Ringwald #include <stdio.h>
4610277393SMatthias Ringwald #include <string.h>
4710277393SMatthias Ringwald #include <btstack_debug.h>
4810277393SMatthias Ringwald 
4910277393SMatthias Ringwald #include "bluetooth_data_types.h"
5010277393SMatthias Ringwald #include "btstack_stdin.h"
5110277393SMatthias Ringwald #include "btstack_event.h"
5210277393SMatthias Ringwald #include "btstack_run_loop.h"
5310277393SMatthias Ringwald #include "gap.h"
5410277393SMatthias Ringwald #include "hci.h"
5510277393SMatthias Ringwald #include "hci_cmd.h"
5610277393SMatthias Ringwald #include "hci_dump.h"
572fd68da2SMatthias Ringwald #include "btstack_lc3.h"
58e40ee29aSMatthias Ringwald #include "btstack_lc3_google.h"
594a06e23fSMatthias Ringwald #include "le-audio/le_audio_base_builder.h"
6010277393SMatthias Ringwald 
6110277393SMatthias Ringwald #include "hxcmod.h"
6210277393SMatthias Ringwald #include "mods/mod.h"
6310277393SMatthias Ringwald 
6410277393SMatthias Ringwald // PTS mode
6510277393SMatthias Ringwald // #define PTS_MODE
6610277393SMatthias Ringwald 
6710277393SMatthias Ringwald // Count mode - send packet count as test data for manual analysis
6810277393SMatthias Ringwald // #define COUNT_MODE
6910277393SMatthias Ringwald 
7010277393SMatthias Ringwald // max config
7110277393SMatthias Ringwald #define MAX_NUM_BIS 2
7210277393SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480
733f485d09SMatthias Ringwald #define MAX_LC3_FRAME_BYTES   155
7410277393SMatthias Ringwald 
7510277393SMatthias Ringwald static const uint8_t adv_sid = 0;
7610277393SMatthias Ringwald 
7710277393SMatthias Ringwald static le_advertising_set_t le_advertising_set;
7810277393SMatthias Ringwald 
79*dcd1707aSDirk Helbig static le_extended_advertising_parameters_t extended_params = {
8010277393SMatthias Ringwald         .advertising_event_properties = 0,
8110277393SMatthias Ringwald         .primary_advertising_interval_min = 0x4b0, // 750 ms
8210277393SMatthias Ringwald         .primary_advertising_interval_max = 0x4b0, // 750 ms
8310277393SMatthias Ringwald         .primary_advertising_channel_map = 7,
84*dcd1707aSDirk Helbig         .own_address_type = BD_ADDR_TYPE_LE_PUBLIC,
8510277393SMatthias Ringwald         .peer_address_type = 0,
86c52eeb3dSMatthias Ringwald         .peer_address =  { 0 },
8710277393SMatthias Ringwald         .advertising_filter_policy = 0,
8810277393SMatthias Ringwald         .advertising_tx_power = 10, // 10 dBm
8910277393SMatthias Ringwald         .primary_advertising_phy = 1, // LE 1M PHY
9010277393SMatthias Ringwald         .secondary_advertising_max_skip = 0,
9110277393SMatthias Ringwald         .secondary_advertising_phy = 1, // LE 1M PHY
9210277393SMatthias Ringwald         .advertising_sid = adv_sid,
9310277393SMatthias Ringwald         .scan_request_notification_enable = 0,
9410277393SMatthias Ringwald };
9510277393SMatthias Ringwald 
9670718632SMatthias Ringwald // Random Broadcast ID, valid for lifetime of BIG
9770718632SMatthias Ringwald #define BROADCAST_ID (0x112233u)
9870718632SMatthias Ringwald 
9910277393SMatthias Ringwald static const uint8_t extended_adv_data[] = {
10010277393SMatthias Ringwald         // 16 bit service data, ORG_BLUETOOTH_SERVICE_BASIC_AUDIO_ANNOUNCEMENT_SERVICE, Broadcast ID
10170718632SMatthias Ringwald         6, BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID, 0x52, 0x18,
10270718632SMatthias Ringwald         BROADCAST_ID >> 16,
10370718632SMatthias Ringwald         (BROADCAST_ID >> 8) & 0xff,
10470718632SMatthias Ringwald         BROADCAST_ID & 0xff,
10510277393SMatthias Ringwald         // name
10610277393SMatthias Ringwald #ifdef PTS_MODE
10710277393SMatthias Ringwald         7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'P', 'T', 'S', '-', 'x', 'x'
10810277393SMatthias Ringwald #elif defined(COUNT_MODE)
10910277393SMatthias Ringwald         6, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'C', 'O', 'U', 'N', 'T'
11010277393SMatthias Ringwald #else
11110277393SMatthias Ringwald         7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'S', 'o', 'u', 'r', 'c', 'e'
11210277393SMatthias Ringwald #endif
11310277393SMatthias Ringwald };
11410277393SMatthias Ringwald 
11510277393SMatthias Ringwald static const le_periodic_advertising_parameters_t periodic_params = {
11610277393SMatthias Ringwald         .periodic_advertising_interval_min = 0x258, // 375 ms
11710277393SMatthias Ringwald         .periodic_advertising_interval_max = 0x258, // 375 ms
11810277393SMatthias Ringwald         .periodic_advertising_properties = 0
11910277393SMatthias Ringwald };
12010277393SMatthias Ringwald 
12110277393SMatthias Ringwald // input signal: pre-computed int16 sine wave, 96000 Hz at 300 Hz
12210277393SMatthias Ringwald static const int16_t sine_int16[] = {
12310277393SMatthias Ringwald         0,    643,   1286,   1929,   2571,   3212,   3851,   4489,   5126,   5760,
12410277393SMatthias Ringwald         6393,   7022,   7649,   8273,   8894,   9512,  10126,  10735,  11341,  11943,
12510277393SMatthias Ringwald         12539,  13131,  13718,  14300,  14876,  15446,  16011,  16569,  17121,  17666,
12610277393SMatthias Ringwald         18204,  18736,  19260,  19777,  20286,  20787,  21280,  21766,  22242,  22710,
12710277393SMatthias Ringwald         23170,  23620,  24062,  24494,  24916,  25329,  25732,  26126,  26509,  26882,
12810277393SMatthias Ringwald         27245,  27597,  27938,  28269,  28589,  28898,  29196,  29482,  29757,  30021,
12910277393SMatthias Ringwald         30273,  30513,  30742,  30958,  31163,  31356,  31537,  31705,  31862,  32006,
13010277393SMatthias Ringwald         32137,  32257,  32364,  32458,  32540,  32609,  32666,  32710,  32742,  32761,
13110277393SMatthias Ringwald         32767,  32761,  32742,  32710,  32666,  32609,  32540,  32458,  32364,  32257,
13210277393SMatthias Ringwald         32137,  32006,  31862,  31705,  31537,  31356,  31163,  30958,  30742,  30513,
13310277393SMatthias Ringwald         30273,  30021,  29757,  29482,  29196,  28898,  28589,  28269,  27938,  27597,
13410277393SMatthias Ringwald         27245,  26882,  26509,  26126,  25732,  25329,  24916,  24494,  24062,  23620,
13510277393SMatthias Ringwald         23170,  22710,  22242,  21766,  21280,  20787,  20286,  19777,  19260,  18736,
13610277393SMatthias Ringwald         18204,  17666,  17121,  16569,  16011,  15446,  14876,  14300,  13718,  13131,
13710277393SMatthias Ringwald         12539,  11943,  11341,  10735,  10126,   9512,   8894,   8273,   7649,   7022,
13810277393SMatthias Ringwald         6393,   5760,   5126,   4489,   3851,   3212,   2571,   1929,   1286,    643,
13910277393SMatthias Ringwald         0,   -643,  -1286,  -1929,  -2571,  -3212,  -3851,  -4489,  -5126,  -5760,
14010277393SMatthias Ringwald         -6393,  -7022,  -7649,  -8273,  -8894,  -9512, -10126, -10735, -11341, -11943,
14110277393SMatthias Ringwald         -12539, -13131, -13718, -14300, -14876, -15446, -16011, -16569, -17121, -17666,
14210277393SMatthias Ringwald         -18204, -18736, -19260, -19777, -20286, -20787, -21280, -21766, -22242, -22710,
14310277393SMatthias Ringwald         -23170, -23620, -24062, -24494, -24916, -25329, -25732, -26126, -26509, -26882,
14410277393SMatthias Ringwald         -27245, -27597, -27938, -28269, -28589, -28898, -29196, -29482, -29757, -30021,
14510277393SMatthias Ringwald         -30273, -30513, -30742, -30958, -31163, -31356, -31537, -31705, -31862, -32006,
14610277393SMatthias Ringwald         -32137, -32257, -32364, -32458, -32540, -32609, -32666, -32710, -32742, -32761,
14710277393SMatthias Ringwald         -32767, -32761, -32742, -32710, -32666, -32609, -32540, -32458, -32364, -32257,
14810277393SMatthias Ringwald         -32137, -32006, -31862, -31705, -31537, -31356, -31163, -30958, -30742, -30513,
14910277393SMatthias Ringwald         -30273, -30021, -29757, -29482, -29196, -28898, -28589, -28269, -27938, -27597,
15010277393SMatthias Ringwald         -27245, -26882, -26509, -26126, -25732, -25329, -24916, -24494, -24062, -23620,
15110277393SMatthias Ringwald         -23170, -22710, -22242, -21766, -21280, -20787, -20286, -19777, -19260, -18736,
15210277393SMatthias Ringwald         -18204, -17666, -17121, -16569, -16011, -15446, -14876, -14300, -13718, -13131,
15310277393SMatthias Ringwald         -12539, -11943, -11341, -10735, -10126,  -9512,  -8894,  -8273,  -7649,  -7022,
15410277393SMatthias Ringwald         -6393,  -5760,  -5126,  -4489,  -3851,  -3212,  -2571,  -1929,  -1286,   -643,
15510277393SMatthias Ringwald };
15610277393SMatthias Ringwald 
15710277393SMatthias Ringwald static bd_addr_t remote;
15810277393SMatthias Ringwald static const char * remote_addr_string = "00:1B:DC:08:E2:72";
15910277393SMatthias Ringwald 
16010277393SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
1614a06e23fSMatthias Ringwald static uint8_t period_adv_data[255];
1624a06e23fSMatthias Ringwald static uint16_t period_adv_data_len;
16310277393SMatthias Ringwald 
16410277393SMatthias Ringwald static uint8_t adv_handle = 0;
16510277393SMatthias Ringwald static unsigned int     next_bis_index;
16610277393SMatthias Ringwald static hci_con_handle_t bis_con_handles[MAX_NUM_BIS];
16710277393SMatthias Ringwald static uint16_t packet_sequence_numbers[MAX_NUM_BIS];
16810277393SMatthias Ringwald static uint8_t framed_pdus;
16910277393SMatthias Ringwald static bool bis_can_send[MAX_NUM_BIS];
17010277393SMatthias Ringwald static bool bis_has_data[MAX_NUM_BIS];
17110277393SMatthias Ringwald static uint8_t iso_frame_counter;
17210277393SMatthias Ringwald static uint16_t frame_duration_us;
17310277393SMatthias Ringwald 
174cd0bedb1SMatthias Ringwald static le_audio_big_t big_storage;
175cd0bedb1SMatthias Ringwald static le_audio_big_params_t big_params;
176cd0bedb1SMatthias Ringwald 
17710277393SMatthias Ringwald // time stamping
17810277393SMatthias Ringwald #ifdef COUNT_MODE
17910277393SMatthias Ringwald #define MAX_PACKET_INTERVAL_BINS_MS 50
18010277393SMatthias Ringwald static uint32_t send_time_bins[MAX_PACKET_INTERVAL_BINS_MS];
18110277393SMatthias Ringwald static uint32_t send_last_ms;
18210277393SMatthias Ringwald #endif
18310277393SMatthias Ringwald 
18410277393SMatthias Ringwald // lc3 codec config
185c52eeb3dSMatthias Ringwald static uint16_t sampling_frequency_hz;
1862fd68da2SMatthias Ringwald static btstack_lc3_frame_duration_t frame_duration;
18710277393SMatthias Ringwald static uint16_t number_samples_per_frame;
18810277393SMatthias Ringwald static uint16_t octets_per_frame;
18910277393SMatthias Ringwald static uint8_t  num_bis = 1;
19010277393SMatthias Ringwald 
19110277393SMatthias Ringwald // lc3 encoder
1922fd68da2SMatthias Ringwald static const btstack_lc3_encoder_t * lc3_encoder;
193e40ee29aSMatthias Ringwald static btstack_lc3_encoder_google_t encoder_contexts[MAX_NUM_BIS];
19410277393SMatthias Ringwald static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
1953f485d09SMatthias Ringwald static uint8_t iso_payload[MAX_NUM_BIS * MAX_LC3_FRAME_BYTES];
19610277393SMatthias Ringwald static uint32_t time_generation_ms;
19710277393SMatthias Ringwald 
19810277393SMatthias Ringwald // codec menu
19910277393SMatthias Ringwald static uint8_t menu_sampling_frequency;
20010277393SMatthias Ringwald static uint8_t menu_variant;
20110277393SMatthias Ringwald 
20210277393SMatthias Ringwald // mod player
20310277393SMatthias Ringwald static int hxcmod_initialized;
20410277393SMatthias Ringwald static modcontext mod_context;
20510277393SMatthias Ringwald static tracker_buffer_state trkbuf;
20610277393SMatthias Ringwald 
20710277393SMatthias Ringwald // sine generator
20810277393SMatthias Ringwald static uint8_t  sine_step;
20910277393SMatthias Ringwald static uint16_t sine_phases[MAX_NUM_BIS];
21010277393SMatthias Ringwald 
211ac95ea81SMatthias Ringwald // encryption
212ac95ea81SMatthias Ringwald static uint8_t encryption = 0;
213166aee19SMatthias Ringwald static uint8_t broadcast_code [] = {0x01, 0x02, 0x68, 0x05, 0x53, 0xF1, 0x41, 0x5A, 0xA2, 0x65, 0xBB, 0xAF, 0xC6, 0xEA, 0x03, 0xB8, };
214ac95ea81SMatthias Ringwald 
21510277393SMatthias Ringwald // audio producer
21610277393SMatthias Ringwald static enum {
21710277393SMatthias Ringwald     AUDIO_SOURCE_SINE,
21810277393SMatthias Ringwald     AUDIO_SOURCE_MODPLAYER
21910277393SMatthias Ringwald } audio_source = AUDIO_SOURCE_MODPLAYER;
22010277393SMatthias Ringwald 
22110277393SMatthias Ringwald static enum {
22210277393SMatthias Ringwald     APP_IDLE,
22310277393SMatthias Ringwald     APP_W4_CREATE_BIG_COMPLETE,
224b9b9e477SMatthias Ringwald     APP_STREAMING,
22510277393SMatthias Ringwald } app_state = APP_IDLE;
22610277393SMatthias Ringwald 
22710277393SMatthias Ringwald // enumerate default codec configs
22810277393SMatthias Ringwald static struct {
229c52eeb3dSMatthias Ringwald     uint16_t samplingrate_hz;
23010277393SMatthias Ringwald     uint8_t  samplingrate_index;
23110277393SMatthias Ringwald     uint8_t  num_variants;
23210277393SMatthias Ringwald     struct {
23310277393SMatthias Ringwald         const char * name;
2342fd68da2SMatthias Ringwald         btstack_lc3_frame_duration_t frame_duration;
23510277393SMatthias Ringwald         uint16_t octets_per_frame;
23610277393SMatthias Ringwald     } variants[6];
23710277393SMatthias Ringwald } codec_configurations[] = {
23810277393SMatthias Ringwald     {
23910277393SMatthias Ringwald         8000, 0x01, 2,
24010277393SMatthias Ringwald         {
2412fd68da2SMatthias Ringwald             {  "8_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 26},
2422fd68da2SMatthias Ringwald             {  "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30}
24310277393SMatthias Ringwald         }
24410277393SMatthias Ringwald     },
24510277393SMatthias Ringwald     {
24610277393SMatthias Ringwald        16000, 0x03, 2,
24710277393SMatthias Ringwald        {
2482fd68da2SMatthias Ringwald             {  "16_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 30},
2492fd68da2SMatthias Ringwald             {  "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40}
25010277393SMatthias Ringwald        }
25110277393SMatthias Ringwald     },
25210277393SMatthias Ringwald     {
25310277393SMatthias Ringwald         24000, 0x05, 2,
25410277393SMatthias Ringwald         {
2552fd68da2SMatthias Ringwald             {  "24_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 45},
2562fd68da2SMatthias Ringwald             {  "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60}
25710277393SMatthias Ringwald        }
25810277393SMatthias Ringwald     },
25910277393SMatthias Ringwald     {
26010277393SMatthias Ringwald         32000, 0x06, 2,
26110277393SMatthias Ringwald         {
2622fd68da2SMatthias Ringwald             {  "32_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 60},
2632fd68da2SMatthias Ringwald             {  "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80}
26410277393SMatthias Ringwald         }
26510277393SMatthias Ringwald     },
26610277393SMatthias Ringwald     {
26710277393SMatthias Ringwald         44100, 0x07, 2,
26810277393SMatthias Ringwald         {
2692fd68da2SMatthias Ringwald             { "441_1",  BTSTACK_LC3_FRAME_DURATION_7500US,  97},
2702fd68da2SMatthias Ringwald             { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130}
27110277393SMatthias Ringwald         }
27210277393SMatthias Ringwald     },
27310277393SMatthias Ringwald     {
27410277393SMatthias Ringwald         48000, 0x08, 6,
27510277393SMatthias Ringwald         {
2762fd68da2SMatthias Ringwald             {  "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75},
2772fd68da2SMatthias Ringwald             {  "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100},
2782fd68da2SMatthias Ringwald             {  "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90},
2792fd68da2SMatthias Ringwald             {  "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120},
2802fd68da2SMatthias Ringwald             {  "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117},
2812fd68da2SMatthias Ringwald             {  "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155}
28210277393SMatthias Ringwald         }
28310277393SMatthias Ringwald     },
28410277393SMatthias Ringwald };
28510277393SMatthias Ringwald 
28610277393SMatthias Ringwald static void show_usage(void);
28710277393SMatthias Ringwald 
28810277393SMatthias Ringwald static void print_config(void) {
289ac95ea81SMatthias Ringwald     printf("Config '%s_%u': %u, %s ms, %u octets - %s%s\n",
29010277393SMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].name,
29110277393SMatthias Ringwald            num_bis,
29210277393SMatthias Ringwald            codec_configurations[menu_sampling_frequency].samplingrate_hz,
2932fd68da2SMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
29410277393SMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame,
295ac95ea81SMatthias Ringwald            audio_source == AUDIO_SOURCE_SINE ? "Sine" : "Modplayer", encryption ? " (encrypted)" : "");
29610277393SMatthias Ringwald }
29710277393SMatthias Ringwald 
29810277393SMatthias Ringwald static void setup_lc3_encoder(void){
29910277393SMatthias Ringwald     uint8_t channel;
30010277393SMatthias Ringwald     for (channel = 0 ; channel < num_bis ; channel++){
301e40ee29aSMatthias Ringwald         btstack_lc3_encoder_google_t * context = &encoder_contexts[channel];
302e40ee29aSMatthias Ringwald         lc3_encoder = btstack_lc3_encoder_google_init_instance(context);
303da364eecSMatthias Ringwald         lc3_encoder->configure(context, sampling_frequency_hz, frame_duration, octets_per_frame);
30410277393SMatthias Ringwald     }
305dc0d751cSMatthias Ringwald     number_samples_per_frame = btstack_lc3_samples_per_frame(sampling_frequency_hz, frame_duration);
30610277393SMatthias Ringwald     btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
30710277393SMatthias Ringwald     printf("LC3 Encoder config: %u hz, frame duration %s ms, num samples %u, num octets %u\n",
3082fd68da2SMatthias Ringwald            sampling_frequency_hz, frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
30910277393SMatthias Ringwald            number_samples_per_frame, octets_per_frame);
31010277393SMatthias Ringwald }
31110277393SMatthias Ringwald 
31210277393SMatthias Ringwald static void setup_mod_player(void){
31310277393SMatthias Ringwald     if (!hxcmod_initialized) {
31410277393SMatthias Ringwald         hxcmod_initialized = hxcmod_init(&mod_context);
31510277393SMatthias Ringwald         btstack_assert(hxcmod_initialized != 0);
31610277393SMatthias Ringwald     }
31710277393SMatthias Ringwald     hxcmod_unload(&mod_context);
31810277393SMatthias Ringwald     hxcmod_setcfg(&mod_context, sampling_frequency_hz, 16, 1, 1, 1);
31910277393SMatthias Ringwald     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
32010277393SMatthias Ringwald }
32110277393SMatthias Ringwald 
32210277393SMatthias Ringwald static void generate_audio(void){
32310277393SMatthias Ringwald     uint32_t start_ms = btstack_run_loop_get_time_ms();
32410277393SMatthias Ringwald     uint16_t sample;
32510277393SMatthias Ringwald     switch (audio_source) {
32610277393SMatthias Ringwald         case AUDIO_SOURCE_SINE:
32710277393SMatthias Ringwald             // generate sine wave for all channels
32810277393SMatthias Ringwald             for (sample = 0 ; sample < number_samples_per_frame ; sample++){
32910277393SMatthias Ringwald                 uint8_t channel;
33010277393SMatthias Ringwald                 for (channel = 0; channel < num_bis; channel++) {
33110277393SMatthias Ringwald                     int16_t value = sine_int16[sine_phases[channel]] / 4;
332c3e2434dSMatthias Ringwald                     pcm[sample * num_bis + channel] = value;
33310277393SMatthias Ringwald                     sine_phases[channel] += sine_step * (1+channel);    // second channel, double frequency
33410277393SMatthias Ringwald                     if (sine_phases[channel] >= (sizeof(sine_int16) / sizeof(int16_t))) {
33510277393SMatthias Ringwald                         sine_phases[channel] = 0;
33610277393SMatthias Ringwald                     }
33710277393SMatthias Ringwald                 }
33810277393SMatthias Ringwald             }
33910277393SMatthias Ringwald             break;
34010277393SMatthias Ringwald         case AUDIO_SOURCE_MODPLAYER:
34110277393SMatthias Ringwald             // mod player configured for stereo
342c3e2434dSMatthias Ringwald             hxcmod_fillbuffer(&mod_context, (unsigned short *) pcm, number_samples_per_frame, &trkbuf);
34310277393SMatthias Ringwald             if (num_bis == 1) {
34410277393SMatthias Ringwald                 // stereo -> mono
345c3e2434dSMatthias Ringwald                 uint16_t i;
34610277393SMatthias Ringwald                 for (i=0;i<number_samples_per_frame;i++){
347c3e2434dSMatthias Ringwald                     pcm[i] = (pcm[2*i] / 2) + (pcm[2*i+1] / 2);
34810277393SMatthias Ringwald                 }
34910277393SMatthias Ringwald             }
35010277393SMatthias Ringwald             break;
35110277393SMatthias Ringwald         default:
35210277393SMatthias Ringwald             btstack_unreachable();
35310277393SMatthias Ringwald             break;
35410277393SMatthias Ringwald     }
35510277393SMatthias Ringwald     time_generation_ms = btstack_run_loop_get_time_ms() - start_ms;
35610277393SMatthias Ringwald     iso_frame_counter++;
35710277393SMatthias Ringwald }
35810277393SMatthias Ringwald 
3593f485d09SMatthias Ringwald static void encode(uint8_t bis_index){
3603f485d09SMatthias Ringwald     // encode as lc3
361da364eecSMatthias Ringwald     lc3_encoder->encode_signed_16(&encoder_contexts[bis_index], &pcm[bis_index], num_bis, &iso_payload[bis_index * MAX_LC3_FRAME_BYTES]);
3623f485d09SMatthias Ringwald }
3633f485d09SMatthias Ringwald 
3643f485d09SMatthias Ringwald 
3653f485d09SMatthias Ringwald static void send_iso_packet(uint8_t bis_index) {
36610277393SMatthias Ringwald 
36710277393SMatthias Ringwald #ifdef COUNT_MODE
36810277393SMatthias Ringwald     if (bis_index == 0) {
36910277393SMatthias Ringwald         uint32_t now = btstack_run_loop_get_time_ms();
37010277393SMatthias Ringwald         if (send_last_ms != 0) {
37110277393SMatthias Ringwald             uint16_t send_interval_ms = now - send_last_ms;
37210277393SMatthias Ringwald             if (send_interval_ms >= MAX_PACKET_INTERVAL_BINS_MS) {
37310277393SMatthias Ringwald                 printf("ERROR: send interval %u\n", send_interval_ms);
37410277393SMatthias Ringwald             } else {
37510277393SMatthias Ringwald                 send_time_bins[send_interval_ms]++;
37610277393SMatthias Ringwald             }
37710277393SMatthias Ringwald         }
37810277393SMatthias Ringwald         send_last_ms = now;
37910277393SMatthias Ringwald     }
38010277393SMatthias Ringwald #endif
38110277393SMatthias Ringwald     bool ok = hci_reserve_packet_buffer();
38210277393SMatthias Ringwald     btstack_assert(ok);
38310277393SMatthias Ringwald     uint8_t * buffer = hci_get_outgoing_packet_buffer();
38410277393SMatthias Ringwald     // complete SDU, no TimeStamp
38510277393SMatthias Ringwald     little_endian_store_16(buffer, 0, bis_con_handles[bis_index] | (2 << 12));
38610277393SMatthias Ringwald     // len
38710277393SMatthias Ringwald     little_endian_store_16(buffer, 2, 0 + 4 + octets_per_frame);
38810277393SMatthias Ringwald     // TimeStamp if TS flag is set
38910277393SMatthias Ringwald     // packet seq nr
39010277393SMatthias Ringwald     little_endian_store_16(buffer, 4, packet_sequence_numbers[bis_index]);
39110277393SMatthias Ringwald     // iso sdu len
39210277393SMatthias Ringwald     little_endian_store_16(buffer, 6, octets_per_frame);
39310277393SMatthias Ringwald #ifdef COUNT_MODE
39410277393SMatthias Ringwald     // test data: bis_index, counter
39510277393SMatthias Ringwald     buffer[8] = bis_index;
39610277393SMatthias Ringwald     memset(&buffer[9], iso_frame_counter, octets_per_frame - 1);
39710277393SMatthias Ringwald #else
3983f485d09SMatthias Ringwald     // copy encoded payload
3993f485d09SMatthias Ringwald     memcpy(&buffer[8], &iso_payload[bis_index * MAX_LC3_FRAME_BYTES], octets_per_frame);
40010277393SMatthias Ringwald #endif
40110277393SMatthias Ringwald     // send
40210277393SMatthias Ringwald     hci_send_iso_packet_buffer(4 + 0 + 4 + octets_per_frame);
40310277393SMatthias Ringwald 
4043f485d09SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
40510277393SMatthias Ringwald     if (((packet_sequence_numbers[bis_index] & 0x7f) == 0) && (bis_index == 0)) {
40610277393SMatthias Ringwald         printf("Encoding time: %u\n", time_generation_ms);
40710277393SMatthias Ringwald     }
4083f485d09SMatthias Ringwald #endif
40910277393SMatthias Ringwald 
41010277393SMatthias Ringwald     packet_sequence_numbers[bis_index]++;
41110277393SMatthias Ringwald }
41210277393SMatthias Ringwald 
4130be46310SMatthias Ringwald static void generate_audio_and_encode(void){
41410277393SMatthias Ringwald     uint8_t i;
41510277393SMatthias Ringwald     generate_audio();
41610277393SMatthias Ringwald     for (i = 0; i < num_bis; i++) {
4170be46310SMatthias Ringwald         encode(i);
41810277393SMatthias Ringwald         bis_has_data[i] = true;
41910277393SMatthias Ringwald     }
42010277393SMatthias Ringwald }
42110277393SMatthias Ringwald 
422*dcd1707aSDirk Helbig static bool is_zero_bd_addr( bd_addr_t address ) {
423*dcd1707aSDirk Helbig     int sum = 0;
424*dcd1707aSDirk Helbig     for( int i=0; i<6; ++i ) {
425*dcd1707aSDirk Helbig         sum += address[i];
426*dcd1707aSDirk Helbig     }
427*dcd1707aSDirk Helbig     return (sum>0)?false:true;
428*dcd1707aSDirk Helbig }
429*dcd1707aSDirk Helbig 
43044959aebSMatthias Ringwald static void setup_advertising() {
431*dcd1707aSDirk Helbig     bd_addr_t local_addr;
432*dcd1707aSDirk Helbig     gap_local_bd_addr(local_addr);
433*dcd1707aSDirk Helbig     bool local_address_invalid = is_zero_bd_addr( local_addr );
434*dcd1707aSDirk Helbig     if( local_address_invalid ) {
435*dcd1707aSDirk Helbig         extended_params.own_address_type = BD_ADDR_TYPE_LE_RANDOM;
436*dcd1707aSDirk Helbig     }
43744959aebSMatthias Ringwald     gap_extended_advertising_setup(&le_advertising_set, &extended_params, &adv_handle);
438*dcd1707aSDirk Helbig     if( local_address_invalid ) {
439*dcd1707aSDirk Helbig         bd_addr_t random_address = { 0xC1, 0x01, 0x01, 0x01, 0x01, 0x01 };
440*dcd1707aSDirk Helbig         gap_extended_advertising_set_random_address( adv_handle, random_address );
441*dcd1707aSDirk Helbig     }
44244959aebSMatthias Ringwald     gap_extended_advertising_set_adv_data(adv_handle, sizeof(extended_adv_data), extended_adv_data);
44344959aebSMatthias Ringwald     gap_periodic_advertising_set_params(adv_handle, &periodic_params);
4444a06e23fSMatthias Ringwald     gap_periodic_advertising_set_data(adv_handle, period_adv_data_len, period_adv_data);
44544959aebSMatthias Ringwald     gap_periodic_advertising_start(adv_handle, 0);
44644959aebSMatthias Ringwald     gap_extended_advertising_start(adv_handle, 0, 0);
44744959aebSMatthias Ringwald }
44844959aebSMatthias Ringwald 
44944959aebSMatthias Ringwald static void setup_big(void){
450cd0bedb1SMatthias Ringwald     // Create BIG
451cd0bedb1SMatthias Ringwald     big_params.big_handle = 0;
452cd0bedb1SMatthias Ringwald     big_params.advertising_handle = adv_handle;
453cd0bedb1SMatthias Ringwald     big_params.num_bis = num_bis;
454cd0bedb1SMatthias Ringwald     big_params.max_sdu = octets_per_frame;
455cd0bedb1SMatthias Ringwald     big_params.max_transport_latency_ms = 31;
456cd0bedb1SMatthias Ringwald     big_params.rtn = 2;
457cd0bedb1SMatthias Ringwald     big_params.phy = 2;
458cd0bedb1SMatthias Ringwald     big_params.packing = 0;
459ac95ea81SMatthias Ringwald     big_params.encryption = encryption;
460ac95ea81SMatthias Ringwald     if (encryption) {
461ac95ea81SMatthias Ringwald         memcpy(big_params.broadcast_code, &broadcast_code[0], 16);
462ac95ea81SMatthias Ringwald     } else {
463cd0bedb1SMatthias Ringwald         memset(big_params.broadcast_code, 0, 16);
464ac95ea81SMatthias Ringwald     }
465cd0bedb1SMatthias Ringwald     if (sampling_frequency_hz == 44100){
466cd0bedb1SMatthias Ringwald         // same config as for 48k -> frame is longer by 48/44.1
467cd0bedb1SMatthias Ringwald         big_params.sdu_interval_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8163 : 10884;
468cd0bedb1SMatthias Ringwald         big_params.framing = 1;
469cd0bedb1SMatthias Ringwald     } else {
470cd0bedb1SMatthias Ringwald         big_params.sdu_interval_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 7500 : 10000;
471cd0bedb1SMatthias Ringwald         big_params.framing = 0;
472cd0bedb1SMatthias Ringwald     }
473cd0bedb1SMatthias Ringwald     app_state = APP_W4_CREATE_BIG_COMPLETE;
474cd0bedb1SMatthias Ringwald     gap_big_create(&big_storage, &big_params);
475cd0bedb1SMatthias Ringwald }
476cd0bedb1SMatthias Ringwald 
47756c77a86SMatthias Ringwald 
47856c77a86SMatthias Ringwald static void start_broadcast() {// use values from table
47956c77a86SMatthias Ringwald     sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz;
48056c77a86SMatthias Ringwald     octets_per_frame      = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame;
48156c77a86SMatthias Ringwald     frame_duration        = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration;
48256c77a86SMatthias Ringwald 
48356c77a86SMatthias Ringwald     // get num samples per frame
48456c77a86SMatthias Ringwald     setup_lc3_encoder();
48556c77a86SMatthias Ringwald 
4864a06e23fSMatthias Ringwald     // setup base
4874a06e23fSMatthias Ringwald     uint8_t codec_id[] = { 0x06, 0x00, 0x00, 0x00, 0x00 };
4884a06e23fSMatthias Ringwald     uint8_t subgroup_codec_specific_configuration[] = {
4894a06e23fSMatthias Ringwald             0x02, 0x01, 0x01,
4904a06e23fSMatthias Ringwald             0x02, 0x02, 0x01,
4914a06e23fSMatthias Ringwald             0x03, 0x04, 0x1E, 0x00,
4924a06e23fSMatthias Ringwald     };
4934a06e23fSMatthias Ringwald     subgroup_codec_specific_configuration[2] = codec_configurations[menu_sampling_frequency].samplingrate_index;
4944a06e23fSMatthias Ringwald     subgroup_codec_specific_configuration[5] =  (frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US) ? 0 : 1;;
4954a06e23fSMatthias Ringwald     uint8_t subgroup_metadata[] = {
4964a06e23fSMatthias Ringwald             0x03, 0x02, 0x04, 0x00, // Metadata[i]
4974a06e23fSMatthias Ringwald     };
4984a06e23fSMatthias Ringwald     little_endian_store_16(subgroup_codec_specific_configuration, 8, octets_per_frame);
4994a06e23fSMatthias Ringwald     uint8_t bis_codec_specific_configuration_1[] = {
5004a06e23fSMatthias Ringwald             0x05, 0x03, 0x01, 0x00, 0x00, 0x00
5014a06e23fSMatthias Ringwald     };
5024a06e23fSMatthias Ringwald     uint8_t bis_codec_specific_configuration_2[] = {
5034a06e23fSMatthias Ringwald             0x05, 0x03, 0x02, 0x00, 0x00, 0x00
5044a06e23fSMatthias Ringwald     };
5050f7e8caeSMatthias Ringwald     le_audio_base_builder_t builder;
5064a06e23fSMatthias Ringwald     le_audio_base_builder_init(&builder, period_adv_data, sizeof(period_adv_data), 40);
5074a06e23fSMatthias Ringwald     le_audio_base_builder_add_subgroup(&builder, codec_id,
5084a06e23fSMatthias Ringwald                                        sizeof(subgroup_codec_specific_configuration),
5094a06e23fSMatthias Ringwald                                        subgroup_codec_specific_configuration,
5104a06e23fSMatthias Ringwald                                        sizeof(subgroup_metadata), subgroup_metadata);
5114a06e23fSMatthias Ringwald     le_audio_base_builder_add_bis(&builder, 1, sizeof(bis_codec_specific_configuration_1),
5124a06e23fSMatthias Ringwald                                   bis_codec_specific_configuration_1);
5134a06e23fSMatthias Ringwald     if (num_bis == 2){
5144a06e23fSMatthias Ringwald         le_audio_base_builder_add_bis(&builder, 2, sizeof(bis_codec_specific_configuration_2),
5154a06e23fSMatthias Ringwald                                       bis_codec_specific_configuration_2);
5164a06e23fSMatthias Ringwald     }
5174a06e23fSMatthias Ringwald     period_adv_data_len = le_audio_base_builder_get_ad_data_size(&builder);
51856c77a86SMatthias Ringwald 
51956c77a86SMatthias Ringwald     // setup mod player
52056c77a86SMatthias Ringwald     setup_mod_player();
52156c77a86SMatthias Ringwald 
52256c77a86SMatthias Ringwald     // setup sine generator
52356c77a86SMatthias Ringwald     if (sampling_frequency_hz == 44100){
52456c77a86SMatthias Ringwald         sine_step = 2;
52556c77a86SMatthias Ringwald     } else {
52656c77a86SMatthias Ringwald         sine_step = 96000 / sampling_frequency_hz;
52756c77a86SMatthias Ringwald     }
52856c77a86SMatthias Ringwald 
52956c77a86SMatthias Ringwald     // setup extended and periodic advertising
53056c77a86SMatthias Ringwald     setup_advertising();
53156c77a86SMatthias Ringwald 
53256c77a86SMatthias Ringwald     // setup big
53356c77a86SMatthias Ringwald     setup_big();
53456c77a86SMatthias Ringwald }
53556c77a86SMatthias Ringwald 
53610277393SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
53710277393SMatthias Ringwald     UNUSED(channel);
53810277393SMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
5390be46310SMatthias Ringwald     uint8_t bis_index;
54010277393SMatthias Ringwald 
54110277393SMatthias Ringwald     switch (packet[0]) {
54210277393SMatthias Ringwald         case BTSTACK_EVENT_STATE:
54310277393SMatthias Ringwald             switch(btstack_event_state_get_state(packet)) {
54410277393SMatthias Ringwald                 case HCI_STATE_WORKING:
54556c77a86SMatthias Ringwald #ifdef ENABLE_DEMO_MODE
54656c77a86SMatthias Ringwald                     // start broadcast automatically, mod player, 48_5_1
54756c77a86SMatthias Ringwald                     num_bis = 1;
54856c77a86SMatthias Ringwald                     menu_sampling_frequency = 5;
54956c77a86SMatthias Ringwald                     menu_variant = 4;
55056c77a86SMatthias Ringwald                     start_broadcast();
55156c77a86SMatthias Ringwald #else
55210277393SMatthias Ringwald                     show_usage();
55310277393SMatthias Ringwald                     printf("Please select sample frequency and variation, then start broadcast\n");
55456c77a86SMatthias Ringwald #endif
55510277393SMatthias Ringwald                     break;
55610277393SMatthias Ringwald                 case HCI_STATE_OFF:
55710277393SMatthias Ringwald                     printf("Goodbye\n");
55810277393SMatthias Ringwald                     exit(0);
55910277393SMatthias Ringwald                     break;
56010277393SMatthias Ringwald                 default:
56110277393SMatthias Ringwald                     break;
56210277393SMatthias Ringwald             }
56310277393SMatthias Ringwald             break;
564cd0bedb1SMatthias Ringwald         case HCI_EVENT_META_GAP:
565cd0bedb1SMatthias Ringwald             switch (hci_event_gap_meta_get_subevent_code(packet)){
5660be46310SMatthias Ringwald                 case GAP_SUBEVENT_BIG_CREATED:
567cd0bedb1SMatthias Ringwald                     printf("BIG Created with BIS Connection handles: \n");
5680be46310SMatthias Ringwald                     for (bis_index=0;bis_index<num_bis;bis_index++){
5690be46310SMatthias Ringwald                         bis_con_handles[bis_index] = gap_subevent_big_created_get_bis_con_handles(packet, bis_index);
5700be46310SMatthias Ringwald                         printf("0x%04x ", bis_con_handles[bis_index]);
57110277393SMatthias Ringwald                     }
57244959aebSMatthias Ringwald 
573cd0bedb1SMatthias Ringwald                     app_state = APP_STREAMING;
57410277393SMatthias Ringwald                     printf("Start streaming\n");
5750be46310SMatthias Ringwald                     generate_audio_and_encode();
5760be46310SMatthias Ringwald                     hci_request_bis_can_send_now_events(big_params.big_handle);
57710277393SMatthias Ringwald                     break;
57810277393SMatthias Ringwald                 default:
57910277393SMatthias Ringwald                     break;
58010277393SMatthias Ringwald             }
58110277393SMatthias Ringwald             break;
5820be46310SMatthias Ringwald         case HCI_EVENT_BIS_CAN_SEND_NOW:
5830d718107SMatthias Ringwald             bis_index = hci_event_bis_can_send_now_get_bis_index(packet);
5840d718107SMatthias Ringwald             send_iso_packet(bis_index);
5850be46310SMatthias Ringwald             bis_index++;
5860be46310SMatthias Ringwald             if (bis_index == num_bis){
5870be46310SMatthias Ringwald                 generate_audio_and_encode();
5880be46310SMatthias Ringwald                 hci_request_bis_can_send_now_events(big_params.big_handle);
58910277393SMatthias Ringwald             }
59010277393SMatthias Ringwald             break;
59110277393SMatthias Ringwald         default:
59210277393SMatthias Ringwald             break;
59310277393SMatthias Ringwald     }
59410277393SMatthias Ringwald }
59510277393SMatthias Ringwald 
59610277393SMatthias Ringwald static void show_usage(void){
59710277393SMatthias Ringwald     printf("\n--- LE Audio Broadcast Source Test Console ---\n");
59810277393SMatthias Ringwald     print_config();
59910277393SMatthias Ringwald     printf("---\n");
60010277393SMatthias Ringwald     printf("c - toggle channels\n");
601ac95ea81SMatthias Ringwald     printf("e - toggle encryption\n");
60210277393SMatthias Ringwald     printf("f - next sampling frequency\n");
60310277393SMatthias Ringwald     printf("v - next codec variant\n");
60410277393SMatthias Ringwald     printf("t - toggle sine / modplayer\n");
60510277393SMatthias Ringwald     printf("s - start broadcast\n");
60610277393SMatthias Ringwald     printf("---\n");
60710277393SMatthias Ringwald }
60810277393SMatthias Ringwald static void stdin_process(char c){
60910277393SMatthias Ringwald     switch (c){
61010277393SMatthias Ringwald         case 'c':
61110277393SMatthias Ringwald             if (app_state != APP_IDLE){
61210277393SMatthias Ringwald                 printf("Codec configuration can only be changed in idle state\n");
61310277393SMatthias Ringwald                 break;
61410277393SMatthias Ringwald             }
61510277393SMatthias Ringwald             num_bis = 3 - num_bis;
61610277393SMatthias Ringwald             print_config();
61710277393SMatthias Ringwald             break;
618ac95ea81SMatthias Ringwald         case 'e':
619ac95ea81SMatthias Ringwald             if (app_state != APP_IDLE){
620ac95ea81SMatthias Ringwald                 printf("Encryption can only be changed in idle state\n");
621ac95ea81SMatthias Ringwald                 break;
622ac95ea81SMatthias Ringwald             }
623ac95ea81SMatthias Ringwald             encryption = 1 - encryption;
624ac95ea81SMatthias Ringwald             print_config();
625ac95ea81SMatthias Ringwald             break;
62610277393SMatthias Ringwald         case 'f':
62710277393SMatthias Ringwald             if (app_state != APP_IDLE){
62810277393SMatthias Ringwald                 printf("Codec configuration can only be changed in idle state\n");
62910277393SMatthias Ringwald                 break;
63010277393SMatthias Ringwald             }
63110277393SMatthias Ringwald             menu_sampling_frequency++;
63210277393SMatthias Ringwald             if (menu_sampling_frequency >= 6){
63310277393SMatthias Ringwald                 menu_sampling_frequency = 0;
63410277393SMatthias Ringwald             }
63510277393SMatthias Ringwald             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
63610277393SMatthias Ringwald                 menu_variant = 0;
63710277393SMatthias Ringwald             }
63810277393SMatthias Ringwald             print_config();
63910277393SMatthias Ringwald             break;
64010277393SMatthias Ringwald         case 'v':
64110277393SMatthias Ringwald             if (app_state != APP_IDLE){
64210277393SMatthias Ringwald                 printf("Codec configuration can only be changed in idle state\n");
64310277393SMatthias Ringwald                 break;
64410277393SMatthias Ringwald             }
64510277393SMatthias Ringwald             menu_variant++;
64610277393SMatthias Ringwald             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
64710277393SMatthias Ringwald                 menu_variant = 0;
64810277393SMatthias Ringwald             }
64910277393SMatthias Ringwald             print_config();
65010277393SMatthias Ringwald             break;
65110277393SMatthias Ringwald         case 's':
65210277393SMatthias Ringwald             if (app_state != APP_IDLE){
65310277393SMatthias Ringwald                 printf("Cannot start broadcast - not in idle state\n");
65410277393SMatthias Ringwald                 break;
65510277393SMatthias Ringwald             }
65656c77a86SMatthias Ringwald             start_broadcast();
65710277393SMatthias Ringwald             break;
65810277393SMatthias Ringwald         case 't':
65910277393SMatthias Ringwald             audio_source = 1 - audio_source;
66010277393SMatthias Ringwald             print_config();
66110277393SMatthias Ringwald             break;
66210277393SMatthias Ringwald         case '\n':
66310277393SMatthias Ringwald         case '\r':
66410277393SMatthias Ringwald             break;
66510277393SMatthias Ringwald         default:
66610277393SMatthias Ringwald             show_usage();
66710277393SMatthias Ringwald             break;
66810277393SMatthias Ringwald     }
66910277393SMatthias Ringwald }
67010277393SMatthias Ringwald 
67110277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]);
67210277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]){
67310277393SMatthias Ringwald     (void) argv;
67410277393SMatthias Ringwald     (void) argc;
67510277393SMatthias Ringwald 
67610277393SMatthias Ringwald     // register for HCI events
67710277393SMatthias Ringwald     hci_event_callback_registration.callback = &packet_handler;
67810277393SMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
67910277393SMatthias Ringwald 
68010277393SMatthias Ringwald     // turn on!
68110277393SMatthias Ringwald     hci_power_control(HCI_POWER_ON);
68210277393SMatthias Ringwald 
68310277393SMatthias Ringwald     btstack_stdin_setup(stdin_process);
68410277393SMatthias Ringwald     return 0;
68510277393SMatthias Ringwald }
686