xref: /btstack/test/le_audio/le_audio_broadcast_source.c (revision e40ee29a889d72d91eb40220df189fbf1d624a43)
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"
58*e40ee29aSMatthias Ringwald #include "btstack_lc3_google.h"
5910277393SMatthias Ringwald 
6010277393SMatthias Ringwald #include "hxcmod.h"
6110277393SMatthias Ringwald #include "mods/mod.h"
6210277393SMatthias Ringwald 
6310277393SMatthias Ringwald // PTS mode
6410277393SMatthias Ringwald // #define PTS_MODE
6510277393SMatthias Ringwald 
6610277393SMatthias Ringwald // Count mode - send packet count as test data for manual analysis
6710277393SMatthias Ringwald // #define COUNT_MODE
6810277393SMatthias Ringwald 
6910277393SMatthias Ringwald // create audio based on timer instead of num completed packets
7010277393SMatthias Ringwald // #define GENERATE_AUDIO_WITH_TIMER
7110277393SMatthias Ringwald 
7210277393SMatthias Ringwald // max config
7310277393SMatthias Ringwald #define MAX_NUM_BIS 2
7410277393SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480
7510277393SMatthias Ringwald 
7610277393SMatthias Ringwald static const uint8_t adv_sid = 0;
7710277393SMatthias Ringwald 
7810277393SMatthias Ringwald static le_advertising_set_t le_advertising_set;
7910277393SMatthias Ringwald 
8010277393SMatthias Ringwald static const le_extended_advertising_parameters_t extended_params = {
8110277393SMatthias Ringwald         .advertising_event_properties = 0,
8210277393SMatthias Ringwald         .primary_advertising_interval_min = 0x4b0, // 750 ms
8310277393SMatthias Ringwald         .primary_advertising_interval_max = 0x4b0, // 750 ms
8410277393SMatthias Ringwald         .primary_advertising_channel_map = 7,
8510277393SMatthias Ringwald         .own_address_type = 0,
8610277393SMatthias Ringwald         .peer_address_type = 0,
8710277393SMatthias Ringwald         .peer_address = 0,
8810277393SMatthias Ringwald         .advertising_filter_policy = 0,
8910277393SMatthias Ringwald         .advertising_tx_power = 10, // 10 dBm
9010277393SMatthias Ringwald         .primary_advertising_phy = 1, // LE 1M PHY
9110277393SMatthias Ringwald         .secondary_advertising_max_skip = 0,
9210277393SMatthias Ringwald         .secondary_advertising_phy = 1, // LE 1M PHY
9310277393SMatthias Ringwald         .advertising_sid = adv_sid,
9410277393SMatthias Ringwald         .scan_request_notification_enable = 0,
9510277393SMatthias Ringwald };
9610277393SMatthias Ringwald 
9710277393SMatthias Ringwald static const uint8_t extended_adv_data[] = {
9810277393SMatthias Ringwald         // 16 bit service data, ORG_BLUETOOTH_SERVICE_BASIC_AUDIO_ANNOUNCEMENT_SERVICE, Broadcast ID
9910277393SMatthias Ringwald         6, BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID, 0x52, 0x18, 0x30, 0x5d, 0x9b,
10010277393SMatthias Ringwald         // name
10110277393SMatthias Ringwald #ifdef PTS_MODE
10210277393SMatthias Ringwald         7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'P', 'T', 'S', '-', 'x', 'x'
10310277393SMatthias Ringwald #elif defined(COUNT_MODE)
10410277393SMatthias Ringwald         6, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'C', 'O', 'U', 'N', 'T'
10510277393SMatthias Ringwald #else
10610277393SMatthias Ringwald         7, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'S', 'o', 'u', 'r', 'c', 'e'
10710277393SMatthias Ringwald #endif
10810277393SMatthias Ringwald };
10910277393SMatthias Ringwald 
11010277393SMatthias Ringwald static const le_periodic_advertising_parameters_t periodic_params = {
11110277393SMatthias Ringwald         .periodic_advertising_interval_min = 0x258, // 375 ms
11210277393SMatthias Ringwald         .periodic_advertising_interval_max = 0x258, // 375 ms
11310277393SMatthias Ringwald         .periodic_advertising_properties = 0
11410277393SMatthias Ringwald };
11510277393SMatthias Ringwald 
11610277393SMatthias Ringwald static uint8_t periodic_adv_data_1[] = {
11710277393SMatthias Ringwald     // 16 bit service data
11810277393SMatthias Ringwald     37, BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID,
11910277393SMatthias Ringwald         // Level 1 - BIG Parameters (common to all BISes)
12010277393SMatthias Ringwald         0x51, 0x18,         // Basic Audio Announcement Service UUID
12110277393SMatthias Ringwald         0x28, 0x00, 0x00,   // Presentation Delay 3
12210277393SMatthias Ringwald         0x01,               // Num_Subgroups
12310277393SMatthias Ringwald         // Level 2 - BIS Subgroup Parameters (common parameters for subgroups of BISes)
12410277393SMatthias Ringwald         // offset 8
12510277393SMatthias Ringwald         0x01,               // The number of BISes in this subgroup
12610277393SMatthias Ringwald         0x06, 0x00, 0x00, 0x00, 0x00,  // 0x06 = LC3, vendor id + codec id = 0
12710277393SMatthias Ringwald         10,                 // Codec_Specific_Configuration_Length[i]
12810277393SMatthias Ringwald         // Codec_Specific_Configuration[i] = 8_2
12910277393SMatthias Ringwald         // offset 15
13010277393SMatthias Ringwald         0x02, 0x01, 0x01,       // Sampling frequency 0x01 = 0x01 / 8 kHz
13110277393SMatthias Ringwald         0x02, 0x02, 0x01,       // Frame Duration     0x02 = 0x01 / 10 ms
13210277393SMatthias Ringwald         0x03, 0x04, 0x1E, 0x00, // Octets per Frame   0x04 = 0x1e / 30
13310277393SMatthias Ringwald         4,                  // Metadata_Length[i]
13410277393SMatthias Ringwald         0x03, 0x02, 0x04, 0x00, // Metadata[i]
13510277393SMatthias Ringwald         // Level 3 - Specific BIS Parameters (if required, for individual BISes)
13610277393SMatthias Ringwald         0x01,               // BIS_index[i[k]]
13710277393SMatthias Ringwald         6,                  // Codec_Specific_Configuration_Length[i[k]]
13810277393SMatthias Ringwald         0x05, 0x03, 0x01, 0x00, 0x00, 0x00 // Codec_Specific_Configuration[i[k]]
13910277393SMatthias Ringwald };
14010277393SMatthias Ringwald 
14110277393SMatthias Ringwald static uint8_t periodic_adv_data_2[] = {
14210277393SMatthias Ringwald     // 16 bit service data
14310277393SMatthias Ringwald     37+8, BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID,
14410277393SMatthias Ringwald         // Level 1 - BIG Parameters (common to all BISes)
14510277393SMatthias Ringwald         0x51, 0x18,         // Basic Audio Announcement Service UUID
14610277393SMatthias Ringwald         0x28, 0x00, 0x00,   // Presentation Delay 3
14710277393SMatthias Ringwald         0x01,               // Num_Subgroups
14810277393SMatthias Ringwald         // Level 2 - BIS Subgroup Parameters (common parameters for subgroups of BISes)
14910277393SMatthias Ringwald         // offset 8
15010277393SMatthias Ringwald         0x02,               // The number of BISes in this subgroup
15110277393SMatthias Ringwald         0x06, 0x00, 0x00, 0x00, 0x00,  // 0x06 = LC3, vendor id + codec id = 0
15210277393SMatthias Ringwald         10,                 // Codec_Specific_Configuration_Length[i]
15310277393SMatthias Ringwald         // Codec_Specific_Configuration[0] = 8_2
15410277393SMatthias Ringwald         // offset 15
15510277393SMatthias Ringwald         0x02, 0x01, 0x01,       // Sampling frequency 0x01 = 0x01 / 8 kHz
15610277393SMatthias Ringwald         0x02, 0x02, 0x01,       // Frame Duration     0x02 = 0x01 / 10 ms
15710277393SMatthias Ringwald         0x03, 0x04, 0x1E, 0x00, // Octets per Frame   0x04 = 0x1e / 30
15810277393SMatthias Ringwald         4,                  // Metadata_Length[i]
15910277393SMatthias Ringwald         0x03, 0x02, 0x04, 0x00, // Metadata[0]
16010277393SMatthias Ringwald         // Level 3 - Specific BIS Parameters (if required, for individual BISes)
16110277393SMatthias Ringwald         0x01,               // BIS_index[i[k]]
16210277393SMatthias Ringwald         6,                  // Codec_Specific_Configuration_Length[i[k]]
16310277393SMatthias Ringwald         0x05, 0x03, 0x01, 0x00, 0x00, 0x00, // Codec_Specific_Configuration[i[k]]
16410277393SMatthias Ringwald         // Level 3 - Specific BIS Parameters (if required, for individual BISes)
16510277393SMatthias Ringwald         0x02,               // BIS_index[i[k]]
16610277393SMatthias Ringwald         6,                  // Codec_Specific_Configuration_Length[i[k]]
16710277393SMatthias Ringwald         0x05, 0x03, 0x02, 0x00, 0x00, 0x00 // Codec_Specific_Configuration[i[k]]
16810277393SMatthias Ringwald };
16910277393SMatthias Ringwald 
17010277393SMatthias Ringwald // input signal: pre-computed int16 sine wave, 96000 Hz at 300 Hz
17110277393SMatthias Ringwald static const int16_t sine_int16[] = {
17210277393SMatthias Ringwald         0,    643,   1286,   1929,   2571,   3212,   3851,   4489,   5126,   5760,
17310277393SMatthias Ringwald         6393,   7022,   7649,   8273,   8894,   9512,  10126,  10735,  11341,  11943,
17410277393SMatthias Ringwald         12539,  13131,  13718,  14300,  14876,  15446,  16011,  16569,  17121,  17666,
17510277393SMatthias Ringwald         18204,  18736,  19260,  19777,  20286,  20787,  21280,  21766,  22242,  22710,
17610277393SMatthias Ringwald         23170,  23620,  24062,  24494,  24916,  25329,  25732,  26126,  26509,  26882,
17710277393SMatthias Ringwald         27245,  27597,  27938,  28269,  28589,  28898,  29196,  29482,  29757,  30021,
17810277393SMatthias Ringwald         30273,  30513,  30742,  30958,  31163,  31356,  31537,  31705,  31862,  32006,
17910277393SMatthias Ringwald         32137,  32257,  32364,  32458,  32540,  32609,  32666,  32710,  32742,  32761,
18010277393SMatthias Ringwald         32767,  32761,  32742,  32710,  32666,  32609,  32540,  32458,  32364,  32257,
18110277393SMatthias Ringwald         32137,  32006,  31862,  31705,  31537,  31356,  31163,  30958,  30742,  30513,
18210277393SMatthias Ringwald         30273,  30021,  29757,  29482,  29196,  28898,  28589,  28269,  27938,  27597,
18310277393SMatthias Ringwald         27245,  26882,  26509,  26126,  25732,  25329,  24916,  24494,  24062,  23620,
18410277393SMatthias Ringwald         23170,  22710,  22242,  21766,  21280,  20787,  20286,  19777,  19260,  18736,
18510277393SMatthias Ringwald         18204,  17666,  17121,  16569,  16011,  15446,  14876,  14300,  13718,  13131,
18610277393SMatthias Ringwald         12539,  11943,  11341,  10735,  10126,   9512,   8894,   8273,   7649,   7022,
18710277393SMatthias Ringwald         6393,   5760,   5126,   4489,   3851,   3212,   2571,   1929,   1286,    643,
18810277393SMatthias Ringwald         0,   -643,  -1286,  -1929,  -2571,  -3212,  -3851,  -4489,  -5126,  -5760,
18910277393SMatthias Ringwald         -6393,  -7022,  -7649,  -8273,  -8894,  -9512, -10126, -10735, -11341, -11943,
19010277393SMatthias Ringwald         -12539, -13131, -13718, -14300, -14876, -15446, -16011, -16569, -17121, -17666,
19110277393SMatthias Ringwald         -18204, -18736, -19260, -19777, -20286, -20787, -21280, -21766, -22242, -22710,
19210277393SMatthias Ringwald         -23170, -23620, -24062, -24494, -24916, -25329, -25732, -26126, -26509, -26882,
19310277393SMatthias Ringwald         -27245, -27597, -27938, -28269, -28589, -28898, -29196, -29482, -29757, -30021,
19410277393SMatthias Ringwald         -30273, -30513, -30742, -30958, -31163, -31356, -31537, -31705, -31862, -32006,
19510277393SMatthias Ringwald         -32137, -32257, -32364, -32458, -32540, -32609, -32666, -32710, -32742, -32761,
19610277393SMatthias Ringwald         -32767, -32761, -32742, -32710, -32666, -32609, -32540, -32458, -32364, -32257,
19710277393SMatthias Ringwald         -32137, -32006, -31862, -31705, -31537, -31356, -31163, -30958, -30742, -30513,
19810277393SMatthias Ringwald         -30273, -30021, -29757, -29482, -29196, -28898, -28589, -28269, -27938, -27597,
19910277393SMatthias Ringwald         -27245, -26882, -26509, -26126, -25732, -25329, -24916, -24494, -24062, -23620,
20010277393SMatthias Ringwald         -23170, -22710, -22242, -21766, -21280, -20787, -20286, -19777, -19260, -18736,
20110277393SMatthias Ringwald         -18204, -17666, -17121, -16569, -16011, -15446, -14876, -14300, -13718, -13131,
20210277393SMatthias Ringwald         -12539, -11943, -11341, -10735, -10126,  -9512,  -8894,  -8273,  -7649,  -7022,
20310277393SMatthias Ringwald         -6393,  -5760,  -5126,  -4489,  -3851,  -3212,  -2571,  -1929,  -1286,   -643,
20410277393SMatthias Ringwald };
20510277393SMatthias Ringwald 
20610277393SMatthias Ringwald static bd_addr_t remote;
20710277393SMatthias Ringwald static const char * remote_addr_string = "00:1B:DC:08:E2:72";
20810277393SMatthias Ringwald 
20910277393SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
21010277393SMatthias Ringwald 
21110277393SMatthias Ringwald static uint8_t adv_handle = 0;
21210277393SMatthias Ringwald static unsigned int     next_bis_index;
21310277393SMatthias Ringwald static hci_con_handle_t bis_con_handles[MAX_NUM_BIS];
21410277393SMatthias Ringwald static uint16_t packet_sequence_numbers[MAX_NUM_BIS];
21510277393SMatthias Ringwald static uint8_t framed_pdus;
21610277393SMatthias Ringwald static bool bis_can_send[MAX_NUM_BIS];
21710277393SMatthias Ringwald static bool bis_has_data[MAX_NUM_BIS];
21810277393SMatthias Ringwald static uint8_t iso_frame_counter;
21910277393SMatthias Ringwald static uint16_t frame_duration_us;
22010277393SMatthias Ringwald 
22110277393SMatthias Ringwald // time stamping
22210277393SMatthias Ringwald #ifdef COUNT_MODE
22310277393SMatthias Ringwald #define MAX_PACKET_INTERVAL_BINS_MS 50
22410277393SMatthias Ringwald static uint32_t send_time_bins[MAX_PACKET_INTERVAL_BINS_MS];
22510277393SMatthias Ringwald static uint32_t send_last_ms;
22610277393SMatthias Ringwald #endif
22710277393SMatthias Ringwald 
22810277393SMatthias Ringwald // time based sender
22910277393SMatthias Ringwald #ifdef GENERATE_AUDIO_WITH_TIMER
23010277393SMatthias Ringwald static uint32_t next_send_time_ms;
23110277393SMatthias Ringwald static uint32_t next_send_time_additional_us;
23210277393SMatthias Ringwald static btstack_timer_source_t send_timer;
23310277393SMatthias Ringwald #endif
23410277393SMatthias Ringwald 
23510277393SMatthias Ringwald // lc3 codec config
23610277393SMatthias Ringwald static uint32_t sampling_frequency_hz;
2372fd68da2SMatthias Ringwald static btstack_lc3_frame_duration_t frame_duration;
23810277393SMatthias Ringwald static uint16_t number_samples_per_frame;
23910277393SMatthias Ringwald static uint16_t octets_per_frame;
24010277393SMatthias Ringwald static uint8_t  num_bis = 1;
24110277393SMatthias Ringwald 
24210277393SMatthias Ringwald // lc3 encoder
2432fd68da2SMatthias Ringwald static const btstack_lc3_encoder_t * lc3_encoder;
244*e40ee29aSMatthias Ringwald static btstack_lc3_encoder_google_t encoder_contexts[MAX_NUM_BIS];
24510277393SMatthias Ringwald static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
24610277393SMatthias Ringwald static uint32_t time_generation_ms;
24710277393SMatthias Ringwald 
24810277393SMatthias Ringwald // codec menu
24910277393SMatthias Ringwald static uint8_t menu_sampling_frequency;
25010277393SMatthias Ringwald static uint8_t menu_variant;
25110277393SMatthias Ringwald 
25210277393SMatthias Ringwald // mod player
25310277393SMatthias Ringwald static int hxcmod_initialized;
25410277393SMatthias Ringwald static modcontext mod_context;
25510277393SMatthias Ringwald static tracker_buffer_state trkbuf;
25610277393SMatthias Ringwald static int16_t mod_pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
25710277393SMatthias Ringwald 
25810277393SMatthias Ringwald // sine generator
25910277393SMatthias Ringwald static uint8_t  sine_step;
26010277393SMatthias Ringwald static uint16_t sine_phases[MAX_NUM_BIS];
26110277393SMatthias Ringwald 
26210277393SMatthias Ringwald // audio producer
26310277393SMatthias Ringwald static enum {
26410277393SMatthias Ringwald     AUDIO_SOURCE_SINE,
26510277393SMatthias Ringwald     AUDIO_SOURCE_MODPLAYER
26610277393SMatthias Ringwald } audio_source = AUDIO_SOURCE_MODPLAYER;
26710277393SMatthias Ringwald 
26810277393SMatthias Ringwald static enum {
26910277393SMatthias Ringwald     APP_IDLE,
27010277393SMatthias Ringwald     APP_W4_PERIODIC_ENABLED,
27110277393SMatthias Ringwald     APP_CREATE_BIG,
27210277393SMatthias Ringwald     APP_W4_CREATE_BIG_COMPLETE,
27310277393SMatthias Ringwald     APP_SET_ISO_PATH,
27410277393SMatthias Ringwald     APP_STREAMING
27510277393SMatthias Ringwald } app_state = APP_IDLE;
27610277393SMatthias Ringwald 
27710277393SMatthias Ringwald // enumerate default codec configs
27810277393SMatthias Ringwald static struct {
27910277393SMatthias Ringwald     uint32_t samplingrate_hz;
28010277393SMatthias Ringwald     uint8_t  samplingrate_index;
28110277393SMatthias Ringwald     uint8_t  num_variants;
28210277393SMatthias Ringwald     struct {
28310277393SMatthias Ringwald         const char * name;
2842fd68da2SMatthias Ringwald         btstack_lc3_frame_duration_t frame_duration;
28510277393SMatthias Ringwald         uint16_t octets_per_frame;
28610277393SMatthias Ringwald     } variants[6];
28710277393SMatthias Ringwald } codec_configurations[] = {
28810277393SMatthias Ringwald     {
28910277393SMatthias Ringwald         8000, 0x01, 2,
29010277393SMatthias Ringwald         {
2912fd68da2SMatthias Ringwald             {  "8_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 26},
2922fd68da2SMatthias Ringwald             {  "8_2", BTSTACK_LC3_FRAME_DURATION_10000US, 30}
29310277393SMatthias Ringwald         }
29410277393SMatthias Ringwald     },
29510277393SMatthias Ringwald     {
29610277393SMatthias Ringwald        16000, 0x03, 2,
29710277393SMatthias Ringwald        {
2982fd68da2SMatthias Ringwald             {  "16_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 30},
2992fd68da2SMatthias Ringwald             {  "16_2", BTSTACK_LC3_FRAME_DURATION_10000US, 40}
30010277393SMatthias Ringwald        }
30110277393SMatthias Ringwald     },
30210277393SMatthias Ringwald     {
30310277393SMatthias Ringwald         24000, 0x05, 2,
30410277393SMatthias Ringwald         {
3052fd68da2SMatthias Ringwald             {  "24_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 45},
3062fd68da2SMatthias Ringwald             {  "24_2", BTSTACK_LC3_FRAME_DURATION_10000US, 60}
30710277393SMatthias Ringwald        }
30810277393SMatthias Ringwald     },
30910277393SMatthias Ringwald     {
31010277393SMatthias Ringwald         32000, 0x06, 2,
31110277393SMatthias Ringwald         {
3122fd68da2SMatthias Ringwald             {  "32_1",  BTSTACK_LC3_FRAME_DURATION_7500US, 60},
3132fd68da2SMatthias Ringwald             {  "32_2", BTSTACK_LC3_FRAME_DURATION_10000US, 80}
31410277393SMatthias Ringwald         }
31510277393SMatthias Ringwald     },
31610277393SMatthias Ringwald     {
31710277393SMatthias Ringwald         44100, 0x07, 2,
31810277393SMatthias Ringwald         {
3192fd68da2SMatthias Ringwald             { "441_1",  BTSTACK_LC3_FRAME_DURATION_7500US,  97},
3202fd68da2SMatthias Ringwald             { "441_2", BTSTACK_LC3_FRAME_DURATION_10000US, 130}
32110277393SMatthias Ringwald         }
32210277393SMatthias Ringwald     },
32310277393SMatthias Ringwald     {
32410277393SMatthias Ringwald         48000, 0x08, 6,
32510277393SMatthias Ringwald         {
3262fd68da2SMatthias Ringwald             {  "48_1", BTSTACK_LC3_FRAME_DURATION_7500US, 75},
3272fd68da2SMatthias Ringwald             {  "48_2", BTSTACK_LC3_FRAME_DURATION_10000US, 100},
3282fd68da2SMatthias Ringwald             {  "48_3", BTSTACK_LC3_FRAME_DURATION_7500US, 90},
3292fd68da2SMatthias Ringwald             {  "48_4", BTSTACK_LC3_FRAME_DURATION_10000US, 120},
3302fd68da2SMatthias Ringwald             {  "48_5", BTSTACK_LC3_FRAME_DURATION_7500US, 117},
3312fd68da2SMatthias Ringwald             {  "48_6", BTSTACK_LC3_FRAME_DURATION_10000US, 155}
33210277393SMatthias Ringwald         }
33310277393SMatthias Ringwald     },
33410277393SMatthias Ringwald };
33510277393SMatthias Ringwald 
33610277393SMatthias Ringwald static void show_usage(void);
33710277393SMatthias Ringwald 
33810277393SMatthias Ringwald static void print_config(void) {
33910277393SMatthias Ringwald     printf("Config '%s_%u': %u, %s ms, %u octets - %s\n",
34010277393SMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].name,
34110277393SMatthias Ringwald            num_bis,
34210277393SMatthias Ringwald            codec_configurations[menu_sampling_frequency].samplingrate_hz,
3432fd68da2SMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
34410277393SMatthias Ringwald            codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame,
34510277393SMatthias Ringwald            audio_source == AUDIO_SOURCE_SINE ? "Sine" : "Modplayer");
34610277393SMatthias Ringwald }
34710277393SMatthias Ringwald 
34810277393SMatthias Ringwald static void setup_lc3_encoder(void){
34910277393SMatthias Ringwald     uint8_t channel;
35010277393SMatthias Ringwald     for (channel = 0 ; channel < num_bis ; channel++){
351*e40ee29aSMatthias Ringwald         btstack_lc3_encoder_google_t * context = &encoder_contexts[channel];
352*e40ee29aSMatthias Ringwald         lc3_encoder = btstack_lc3_encoder_google_init_instance(context);
35310277393SMatthias Ringwald         lc3_encoder->configure(context, sampling_frequency_hz, frame_duration);
35410277393SMatthias Ringwald     }
35510277393SMatthias Ringwald     number_samples_per_frame = lc3_encoder->get_number_samples_per_frame(&encoder_contexts[0]);
35610277393SMatthias Ringwald     btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
35710277393SMatthias Ringwald     printf("LC3 Encoder config: %u hz, frame duration %s ms, num samples %u, num octets %u\n",
3582fd68da2SMatthias Ringwald            sampling_frequency_hz, frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? "7.5" : "10",
35910277393SMatthias Ringwald            number_samples_per_frame, octets_per_frame);
36010277393SMatthias Ringwald }
36110277393SMatthias Ringwald 
36210277393SMatthias Ringwald static void setup_mod_player(void){
36310277393SMatthias Ringwald     if (!hxcmod_initialized) {
36410277393SMatthias Ringwald         hxcmod_initialized = hxcmod_init(&mod_context);
36510277393SMatthias Ringwald         btstack_assert(hxcmod_initialized != 0);
36610277393SMatthias Ringwald     }
36710277393SMatthias Ringwald     hxcmod_unload(&mod_context);
36810277393SMatthias Ringwald     hxcmod_setcfg(&mod_context, sampling_frequency_hz, 16, 1, 1, 1);
36910277393SMatthias Ringwald     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
37010277393SMatthias Ringwald }
37110277393SMatthias Ringwald 
37210277393SMatthias Ringwald static void generate_audio(void){
37310277393SMatthias Ringwald     uint32_t start_ms = btstack_run_loop_get_time_ms();
37410277393SMatthias Ringwald     uint16_t sample;
37510277393SMatthias Ringwald     switch (audio_source) {
37610277393SMatthias Ringwald         case AUDIO_SOURCE_SINE:
37710277393SMatthias Ringwald             // generate sine wave for all channels
37810277393SMatthias Ringwald             for (sample = 0 ; sample < number_samples_per_frame ; sample++){
37910277393SMatthias Ringwald                 uint8_t channel;
38010277393SMatthias Ringwald                 for (channel = 0; channel < num_bis; channel++) {
38110277393SMatthias Ringwald                     int16_t value = sine_int16[sine_phases[channel]] / 4;
38210277393SMatthias Ringwald                     pcm[channel * MAX_SAMPLES_PER_FRAME + sample] = value;
38310277393SMatthias Ringwald                     sine_phases[channel] += sine_step * (1+channel);    // second channel, double frequency
38410277393SMatthias Ringwald                     if (sine_phases[channel] >= (sizeof(sine_int16) / sizeof(int16_t))) {
38510277393SMatthias Ringwald                         sine_phases[channel] = 0;
38610277393SMatthias Ringwald                     }
38710277393SMatthias Ringwald                 }
38810277393SMatthias Ringwald             }
38910277393SMatthias Ringwald             break;
39010277393SMatthias Ringwald         case AUDIO_SOURCE_MODPLAYER:
39110277393SMatthias Ringwald             // mod player configured for stereo
39210277393SMatthias Ringwald             hxcmod_fillbuffer(&mod_context, (unsigned short *) &mod_pcm[0], number_samples_per_frame, &trkbuf);
39310277393SMatthias Ringwald             uint16_t i;
39410277393SMatthias Ringwald             if (num_bis == 1){
39510277393SMatthias Ringwald                 // stereo -> mono
39610277393SMatthias Ringwald                 for (i=0;i<number_samples_per_frame;i++){
39710277393SMatthias Ringwald                     pcm[i] = (mod_pcm[2*i] / 2) + (mod_pcm[2*i+1] / 2);
39810277393SMatthias Ringwald                 }
39910277393SMatthias Ringwald             } else {
40010277393SMatthias Ringwald                 // sort interleaved samples
40110277393SMatthias Ringwald                 for (i=0;i<number_samples_per_frame;i++){
40210277393SMatthias Ringwald                     pcm[i] = mod_pcm[2*i];
40310277393SMatthias Ringwald                     pcm[MAX_SAMPLES_PER_FRAME+i] = mod_pcm[2*i+1];
40410277393SMatthias Ringwald                 }
40510277393SMatthias Ringwald             }
40610277393SMatthias Ringwald             break;
40710277393SMatthias Ringwald         default:
40810277393SMatthias Ringwald             btstack_unreachable();
40910277393SMatthias Ringwald             break;
41010277393SMatthias Ringwald     }
41110277393SMatthias Ringwald     time_generation_ms = btstack_run_loop_get_time_ms() - start_ms;
41210277393SMatthias Ringwald     iso_frame_counter++;
41310277393SMatthias Ringwald }
41410277393SMatthias Ringwald 
41510277393SMatthias Ringwald static void encode_and_send(uint8_t bis_index){
41610277393SMatthias Ringwald 
41710277393SMatthias Ringwald #ifdef COUNT_MODE
41810277393SMatthias Ringwald     if (bis_index == 0) {
41910277393SMatthias Ringwald         uint32_t now = btstack_run_loop_get_time_ms();
42010277393SMatthias Ringwald         if (send_last_ms != 0) {
42110277393SMatthias Ringwald             uint16_t send_interval_ms = now - send_last_ms;
42210277393SMatthias Ringwald             if (send_interval_ms >= MAX_PACKET_INTERVAL_BINS_MS) {
42310277393SMatthias Ringwald                 printf("ERROR: send interval %u\n", send_interval_ms);
42410277393SMatthias Ringwald             } else {
42510277393SMatthias Ringwald                 send_time_bins[send_interval_ms]++;
42610277393SMatthias Ringwald             }
42710277393SMatthias Ringwald         }
42810277393SMatthias Ringwald         send_last_ms = now;
42910277393SMatthias Ringwald     }
43010277393SMatthias Ringwald #endif
43110277393SMatthias Ringwald     bool ok = hci_reserve_packet_buffer();
43210277393SMatthias Ringwald     btstack_assert(ok);
43310277393SMatthias Ringwald     uint8_t * buffer = hci_get_outgoing_packet_buffer();
43410277393SMatthias Ringwald     // complete SDU, no TimeStamp
43510277393SMatthias Ringwald     little_endian_store_16(buffer, 0, bis_con_handles[bis_index] | (2 << 12));
43610277393SMatthias Ringwald     // len
43710277393SMatthias Ringwald     little_endian_store_16(buffer, 2, 0 + 4 + octets_per_frame);
43810277393SMatthias Ringwald     // TimeStamp if TS flag is set
43910277393SMatthias Ringwald     // packet seq nr
44010277393SMatthias Ringwald     little_endian_store_16(buffer, 4, packet_sequence_numbers[bis_index]);
44110277393SMatthias Ringwald     // iso sdu len
44210277393SMatthias Ringwald     little_endian_store_16(buffer, 6, octets_per_frame);
44310277393SMatthias Ringwald #ifdef COUNT_MODE
44410277393SMatthias Ringwald     // test data: bis_index, counter
44510277393SMatthias Ringwald     buffer[8] = bis_index;
44610277393SMatthias Ringwald     memset(&buffer[9], iso_frame_counter, octets_per_frame - 1);
44710277393SMatthias Ringwald #else
44810277393SMatthias Ringwald     // encode as lc3
4499b947857SMatthias Ringwald     lc3_encoder->encode_signed_16(&encoder_contexts[bis_index], &pcm[bis_index * MAX_SAMPLES_PER_FRAME], 1, &buffer[8], octets_per_frame);
45010277393SMatthias Ringwald #endif
45110277393SMatthias Ringwald     // send
45210277393SMatthias Ringwald     hci_send_iso_packet_buffer(4 + 0 + 4 + octets_per_frame);
45310277393SMatthias Ringwald 
45410277393SMatthias Ringwald     if (((packet_sequence_numbers[bis_index] & 0x7f) == 0) && (bis_index == 0)) {
45510277393SMatthias Ringwald         printf("Encoding time: %u\n", time_generation_ms);
45610277393SMatthias Ringwald     }
45710277393SMatthias Ringwald     if ((packet_sequence_numbers[bis_index] & 0x7c) == 0){
45810277393SMatthias Ringwald         printf("%04x %10u %u ", packet_sequence_numbers[bis_index], btstack_run_loop_get_time_ms(), bis_index);
45910277393SMatthias Ringwald         printf_hexdump(&buffer[8], octets_per_frame);
46010277393SMatthias Ringwald     }
46110277393SMatthias Ringwald 
46210277393SMatthias Ringwald     packet_sequence_numbers[bis_index]++;
46310277393SMatthias Ringwald }
46410277393SMatthias Ringwald 
46510277393SMatthias Ringwald static void try_send(void){
46610277393SMatthias Ringwald     bool all_can_send = true;
46710277393SMatthias Ringwald     uint8_t i;
46810277393SMatthias Ringwald     for (i=0; i<num_bis;i++) {
46910277393SMatthias Ringwald         all_can_send &= bis_can_send[i];
47010277393SMatthias Ringwald     }
47110277393SMatthias Ringwald #ifdef PTS_MODE
47210277393SMatthias Ringwald    static uint8_t next_sender;
47310277393SMatthias Ringwald     // PTS 8.2 sends a packet after the previous one was received -> it sends at half speed for stereo configuration
47410277393SMatthias Ringwald     if (all_can_send) {
47510277393SMatthias Ringwald         if (next_sender == 0) {
47610277393SMatthias Ringwald             generate_audio();
47710277393SMatthias Ringwald         }
47810277393SMatthias Ringwald         bis_can_send[next_sender] = false;
47910277393SMatthias Ringwald         encode_and_send(next_sender);
48010277393SMatthias Ringwald         next_sender = (num_bis - 1) - next_sender;
48110277393SMatthias Ringwald     }
48210277393SMatthias Ringwald #else
48310277393SMatthias Ringwald #ifdef GENERATE_AUDIO_WITH_TIMER
48410277393SMatthias Ringwald     for (i=0;i<num_bis;i++){
48510277393SMatthias Ringwald         if (hci_is_packet_buffer_reserved()) return;
48610277393SMatthias Ringwald         if (bis_has_data[i]){
48710277393SMatthias Ringwald             bis_can_send[i] = false;
48810277393SMatthias Ringwald             bis_has_data[i] = false;
48910277393SMatthias Ringwald             encode_and_send(i);
49010277393SMatthias Ringwald             return;
49110277393SMatthias Ringwald         }
49210277393SMatthias Ringwald     }
49310277393SMatthias Ringwald #else
49410277393SMatthias Ringwald     // check if next audio frame should be produced and send
49510277393SMatthias Ringwald     if (all_can_send){
49610277393SMatthias Ringwald         generate_audio();
49710277393SMatthias Ringwald         for (i=0; i<num_bis;i++) {
49810277393SMatthias Ringwald             bis_has_data[i] = true;
49910277393SMatthias Ringwald         }
50010277393SMatthias Ringwald     }
50110277393SMatthias Ringwald 
50210277393SMatthias Ringwald     for (i=0;i<num_bis;i++){
50310277393SMatthias Ringwald         if (hci_is_packet_buffer_reserved()) return;
50410277393SMatthias Ringwald         if (bis_can_send[i] && bis_has_data[i]){
50510277393SMatthias Ringwald             bis_can_send[i] = false;
50610277393SMatthias Ringwald             bis_has_data[i] = false;
50710277393SMatthias Ringwald             encode_and_send(i);
50810277393SMatthias Ringwald             return;
50910277393SMatthias Ringwald         }
51010277393SMatthias Ringwald     }
51110277393SMatthias Ringwald #endif
51210277393SMatthias Ringwald #endif
51310277393SMatthias Ringwald }
51410277393SMatthias Ringwald 
51510277393SMatthias Ringwald #ifdef GENERATE_AUDIO_WITH_TIMER
51610277393SMatthias Ringwald static void generate_audio_timer_handler(btstack_timer_source_t *ts){
51710277393SMatthias Ringwald 
51810277393SMatthias Ringwald     generate_audio();
51910277393SMatthias Ringwald 
52010277393SMatthias Ringwald     uint8_t i;
52110277393SMatthias Ringwald     for (i=0; i<num_bis;i++) {
52210277393SMatthias Ringwald         bis_has_data[i] = true;
52310277393SMatthias Ringwald     }
52410277393SMatthias Ringwald 
52510277393SMatthias Ringwald     // next send time based on frame_duration_us
52610277393SMatthias Ringwald     next_send_time_additional_us += frame_duration_us % 1000;
52710277393SMatthias Ringwald     if (next_send_time_additional_us > 1000){
52810277393SMatthias Ringwald         next_send_time_ms++;
52910277393SMatthias Ringwald         next_send_time_additional_us -= 1000;
53010277393SMatthias Ringwald     }
53110277393SMatthias Ringwald     next_send_time_ms += frame_duration_us / 1000;
53210277393SMatthias Ringwald 
53310277393SMatthias Ringwald     uint32_t now = btstack_run_loop_get_time_ms();
53410277393SMatthias Ringwald     btstack_run_loop_set_timer(&send_timer, next_send_time_ms - now);
53510277393SMatthias Ringwald     btstack_run_loop_add_timer(&send_timer);
53610277393SMatthias Ringwald 
53710277393SMatthias Ringwald     try_send();
53810277393SMatthias Ringwald }
53910277393SMatthias Ringwald #endif
54010277393SMatthias Ringwald 
54110277393SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
54210277393SMatthias Ringwald     UNUSED(channel);
54310277393SMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
54410277393SMatthias Ringwald 
54510277393SMatthias Ringwald     switch (packet[0]) {
54610277393SMatthias Ringwald         case BTSTACK_EVENT_STATE:
54710277393SMatthias Ringwald             switch(btstack_event_state_get_state(packet)) {
54810277393SMatthias Ringwald                 case HCI_STATE_WORKING:
54910277393SMatthias Ringwald                     show_usage();
55010277393SMatthias Ringwald                     printf("Please select sample frequency and variation, then start broadcast\n");
55110277393SMatthias Ringwald                     break;
55210277393SMatthias Ringwald                 case HCI_STATE_OFF:
55310277393SMatthias Ringwald                     printf("Goodbye\n");
55410277393SMatthias Ringwald                     exit(0);
55510277393SMatthias Ringwald                     break;
55610277393SMatthias Ringwald                 default:
55710277393SMatthias Ringwald                     break;
55810277393SMatthias Ringwald             }
55910277393SMatthias Ringwald             break;
56010277393SMatthias Ringwald         case HCI_EVENT_COMMAND_COMPLETE:
56110277393SMatthias Ringwald             switch (hci_event_command_complete_get_command_opcode(packet)){
56210277393SMatthias Ringwald                 case HCI_OPCODE_HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE:
56310277393SMatthias Ringwald                     if (app_state != APP_W4_PERIODIC_ENABLED) break;
56410277393SMatthias Ringwald                     app_state = APP_CREATE_BIG;
56510277393SMatthias Ringwald                     break;
56610277393SMatthias Ringwald                 case HCI_OPCODE_HCI_LE_SETUP_ISO_DATA_PATH:
56710277393SMatthias Ringwald                     next_bis_index++;
56810277393SMatthias Ringwald                     if (next_bis_index == num_bis){
56910277393SMatthias Ringwald                         printf("%u ISO path(s) set up\n", num_bis);
57010277393SMatthias Ringwald                         // ready to send
57110277393SMatthias Ringwald                         uint8_t i;
57210277393SMatthias Ringwald                         for (i=0;i<num_bis;i++) {
57310277393SMatthias Ringwald                             bis_can_send[i] = true;
57410277393SMatthias Ringwald                         }
57510277393SMatthias Ringwald                         app_state = APP_STREAMING;
57610277393SMatthias Ringwald                         //
57710277393SMatthias Ringwald #ifdef GENERATE_AUDIO_WITH_TIMER
57810277393SMatthias Ringwald                         btstack_run_loop_set_timer_handler(&send_timer, &generate_audio_timer_handler);
57910277393SMatthias Ringwald                         uint32_t next_send_time_ms = btstack_run_loop_get_time_ms() + 10;
58010277393SMatthias Ringwald                         uint32_t now = btstack_run_loop_get_time_ms();
58110277393SMatthias Ringwald                         btstack_run_loop_set_timer(&send_timer, next_send_time_ms - now);
58210277393SMatthias Ringwald                         btstack_run_loop_add_timer(&send_timer);
58310277393SMatthias Ringwald #endif
58410277393SMatthias Ringwald                     }
58510277393SMatthias Ringwald                     break;
58610277393SMatthias Ringwald             }
58710277393SMatthias Ringwald             break;
58810277393SMatthias Ringwald         case HCI_EVENT_LE_META:
58910277393SMatthias Ringwald             switch(hci_event_le_meta_get_subevent_code(packet)){
59010277393SMatthias Ringwald                 case HCI_SUBEVENT_LE_CREATE_BIG_COMPLETE:
59110277393SMatthias Ringwald                     if (app_state == APP_W4_CREATE_BIG_COMPLETE){
59210277393SMatthias Ringwald                         uint8_t i;
59310277393SMatthias Ringwald                         printf("BIS Connection Handles: ");
59410277393SMatthias Ringwald                         for (i=0;i<num_bis;i++){
59510277393SMatthias Ringwald                             bis_con_handles[i] = little_endian_read_16(packet, 21 + 2*i);
59610277393SMatthias Ringwald                             printf("0x%04x ", bis_con_handles[i]);
59710277393SMatthias Ringwald                         }
59810277393SMatthias Ringwald                         printf("\n");
59910277393SMatthias Ringwald                         next_bis_index = 0;
60010277393SMatthias Ringwald                         app_state = APP_SET_ISO_PATH;
60110277393SMatthias Ringwald                         printf("Start streaming\n");
60210277393SMatthias Ringwald                     }
60310277393SMatthias Ringwald                     break;
60410277393SMatthias Ringwald                 default:
60510277393SMatthias Ringwald                     break;
60610277393SMatthias Ringwald             }
60710277393SMatthias Ringwald             break;
60810277393SMatthias Ringwald         case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
60910277393SMatthias Ringwald             if (size >= 3){
61010277393SMatthias Ringwald                 uint16_t num_handles = packet[2];
61110277393SMatthias Ringwald                 if (size != (3u + num_handles * 4u)) break;
61210277393SMatthias Ringwald                 uint16_t offset = 3;
61310277393SMatthias Ringwald                 uint16_t i;
61410277393SMatthias Ringwald                 for (i=0; i<num_handles;i++) {
61510277393SMatthias Ringwald                     hci_con_handle_t handle = little_endian_read_16(packet, offset) & 0x0fffu;
61610277393SMatthias Ringwald                     offset += 2u;
61710277393SMatthias Ringwald                     uint16_t num_packets = little_endian_read_16(packet, offset);
61810277393SMatthias Ringwald                     offset += 2u;
61910277393SMatthias Ringwald                     uint8_t j;
62010277393SMatthias Ringwald                     for (j=0 ; j<num_bis ; j++){
62110277393SMatthias Ringwald                         if (handle == bis_con_handles[j]){
62210277393SMatthias Ringwald                             // allow to send
62310277393SMatthias Ringwald                             bis_can_send[j] = true;
62410277393SMatthias Ringwald                         }
62510277393SMatthias Ringwald                     }
62610277393SMatthias Ringwald                 }
62710277393SMatthias Ringwald             }
62810277393SMatthias Ringwald             break;
62910277393SMatthias Ringwald         default:
63010277393SMatthias Ringwald             break;
63110277393SMatthias Ringwald     }
63210277393SMatthias Ringwald 
63310277393SMatthias Ringwald     const uint8_t broadcast_code[16] = { 0 };
63410277393SMatthias Ringwald     switch(app_state){
63510277393SMatthias Ringwald         case APP_CREATE_BIG:
63610277393SMatthias Ringwald             if (hci_can_send_command_packet_now()) {
63710277393SMatthias Ringwald                 app_state = APP_W4_CREATE_BIG_COMPLETE;
63810277393SMatthias Ringwald                 if (sampling_frequency_hz == 44100){
63910277393SMatthias Ringwald                     framed_pdus = 1;
64010277393SMatthias Ringwald                     // same config as for 48k -> frame is longer by 48/44.1
6412fd68da2SMatthias Ringwald                     frame_duration_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8163 : 10884;
64210277393SMatthias Ringwald                 } else {
64310277393SMatthias Ringwald                     framed_pdus = 0;
6442fd68da2SMatthias Ringwald                     frame_duration_us = frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 7500 : 10000;
64510277393SMatthias Ringwald                 }
64610277393SMatthias Ringwald                 hci_send_cmd(&hci_le_create_big, 0, adv_handle, num_bis, frame_duration_us, octets_per_frame, 0x1F, 2, 2, 0, framed_pdus, 0, broadcast_code);
64710277393SMatthias Ringwald             }
64810277393SMatthias Ringwald             break;
64910277393SMatthias Ringwald         case APP_SET_ISO_PATH:
65010277393SMatthias Ringwald             if (!hci_can_send_command_packet_now()) break;
65110277393SMatthias Ringwald             hci_send_cmd(&hci_le_setup_iso_data_path, bis_con_handles[next_bis_index], 0, 0,  0, 0, 0,  0, 0, NULL);
65210277393SMatthias Ringwald             break;
65310277393SMatthias Ringwald         default:
65410277393SMatthias Ringwald             break;
65510277393SMatthias Ringwald     }
65610277393SMatthias Ringwald 
65710277393SMatthias Ringwald     try_send();
65810277393SMatthias Ringwald }
65910277393SMatthias Ringwald 
66010277393SMatthias Ringwald static void show_usage(void){
66110277393SMatthias Ringwald     printf("\n--- LE Audio Broadcast Source Test Console ---\n");
66210277393SMatthias Ringwald     print_config();
66310277393SMatthias Ringwald     printf("---\n");
66410277393SMatthias Ringwald     printf("c - toggle channels\n");
66510277393SMatthias Ringwald     printf("f - next sampling frequency\n");
66610277393SMatthias Ringwald     printf("v - next codec variant\n");
66710277393SMatthias Ringwald     printf("t - toggle sine / modplayer\n");
66810277393SMatthias Ringwald     printf("s - start broadcast\n");
66910277393SMatthias Ringwald     printf("x - shutdown\n");
67010277393SMatthias Ringwald     printf("---\n");
67110277393SMatthias Ringwald }
67210277393SMatthias Ringwald 
67310277393SMatthias Ringwald static void stdin_process(char c){
67410277393SMatthias Ringwald     switch (c){
67510277393SMatthias Ringwald         case 'c':
67610277393SMatthias Ringwald             if (app_state != APP_IDLE){
67710277393SMatthias Ringwald                 printf("Codec configuration can only be changed in idle state\n");
67810277393SMatthias Ringwald                 break;
67910277393SMatthias Ringwald             }
68010277393SMatthias Ringwald             num_bis = 3 - num_bis;
68110277393SMatthias Ringwald             print_config();
68210277393SMatthias Ringwald             break;
68310277393SMatthias Ringwald         case 'f':
68410277393SMatthias Ringwald             if (app_state != APP_IDLE){
68510277393SMatthias Ringwald                 printf("Codec configuration can only be changed in idle state\n");
68610277393SMatthias Ringwald                 break;
68710277393SMatthias Ringwald             }
68810277393SMatthias Ringwald             menu_sampling_frequency++;
68910277393SMatthias Ringwald             if (menu_sampling_frequency >= 6){
69010277393SMatthias Ringwald                 menu_sampling_frequency = 0;
69110277393SMatthias Ringwald             }
69210277393SMatthias Ringwald             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
69310277393SMatthias Ringwald                 menu_variant = 0;
69410277393SMatthias Ringwald             }
69510277393SMatthias Ringwald             print_config();
69610277393SMatthias Ringwald             break;
69710277393SMatthias Ringwald         case 'v':
69810277393SMatthias Ringwald             if (app_state != APP_IDLE){
69910277393SMatthias Ringwald                 printf("Codec configuration can only be changed in idle state\n");
70010277393SMatthias Ringwald                 break;
70110277393SMatthias Ringwald             }
70210277393SMatthias Ringwald             menu_variant++;
70310277393SMatthias Ringwald             if (menu_variant >= codec_configurations[menu_sampling_frequency].num_variants){
70410277393SMatthias Ringwald                 menu_variant = 0;
70510277393SMatthias Ringwald             }
70610277393SMatthias Ringwald             print_config();
70710277393SMatthias Ringwald             break;
70810277393SMatthias Ringwald         case 'x':
70910277393SMatthias Ringwald #ifdef COUNT_MODE
71010277393SMatthias Ringwald             printf("Send statistic:\n");
71110277393SMatthias Ringwald             {
71210277393SMatthias Ringwald                 uint16_t i;
71310277393SMatthias Ringwald                 for (i=0;i<MAX_PACKET_INTERVAL_BINS_MS;i++){
71410277393SMatthias Ringwald                     printf("%2u: %5u\n", i, send_time_bins[i]);
71510277393SMatthias Ringwald                 }
71610277393SMatthias Ringwald             }
71710277393SMatthias Ringwald #endif
71810277393SMatthias Ringwald             printf("Shutdown...\n");
71910277393SMatthias Ringwald             hci_power_control(HCI_POWER_OFF);
72010277393SMatthias Ringwald             break;
72110277393SMatthias Ringwald         case 's':
72210277393SMatthias Ringwald             if (app_state != APP_IDLE){
72310277393SMatthias Ringwald                 printf("Cannot start broadcast - not in idle state\n");
72410277393SMatthias Ringwald                 break;
72510277393SMatthias Ringwald             }
72610277393SMatthias Ringwald             // use values from table
72710277393SMatthias Ringwald             sampling_frequency_hz = codec_configurations[menu_sampling_frequency].samplingrate_hz;
72810277393SMatthias Ringwald             octets_per_frame      = codec_configurations[menu_sampling_frequency].variants[menu_variant].octets_per_frame;
72910277393SMatthias Ringwald             frame_duration        = codec_configurations[menu_sampling_frequency].variants[menu_variant].frame_duration;
73010277393SMatthias Ringwald 
73110277393SMatthias Ringwald             // get num samples per frame
73210277393SMatthias Ringwald             setup_lc3_encoder();
73310277393SMatthias Ringwald 
73410277393SMatthias Ringwald             // update BASEs
73510277393SMatthias Ringwald             periodic_adv_data_1[17] = codec_configurations[menu_sampling_frequency].samplingrate_index;
7362fd68da2SMatthias Ringwald             periodic_adv_data_1[20] = (frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US) ? 0 : 1;
73710277393SMatthias Ringwald             little_endian_store_16(periodic_adv_data_1, 23, octets_per_frame);
73810277393SMatthias Ringwald 
73910277393SMatthias Ringwald             periodic_adv_data_2[17] = codec_configurations[menu_sampling_frequency].samplingrate_index;
7402fd68da2SMatthias Ringwald             periodic_adv_data_2[20] = (frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US) ? 0 : 1;
74110277393SMatthias Ringwald             little_endian_store_16(periodic_adv_data_2, 23, octets_per_frame);
74210277393SMatthias Ringwald 
74310277393SMatthias Ringwald             // setup mod player
74410277393SMatthias Ringwald             setup_mod_player();
74510277393SMatthias Ringwald 
74610277393SMatthias Ringwald             // setup sine generator
74710277393SMatthias Ringwald             if (sampling_frequency_hz == 44100){
74810277393SMatthias Ringwald                 sine_step = 2;
74910277393SMatthias Ringwald             } else {
75010277393SMatthias Ringwald                 sine_step = 96000 / sampling_frequency_hz;
75110277393SMatthias Ringwald             }
75210277393SMatthias Ringwald 
75310277393SMatthias Ringwald             // setup
75410277393SMatthias Ringwald             app_state = APP_W4_PERIODIC_ENABLED;
75510277393SMatthias Ringwald             gap_extended_advertising_setup(&le_advertising_set, &extended_params, &adv_handle);
75610277393SMatthias Ringwald             gap_extended_advertising_set_adv_data(adv_handle, sizeof(extended_adv_data), extended_adv_data);
75710277393SMatthias Ringwald             gap_periodic_advertising_set_params(adv_handle, &periodic_params);
75810277393SMatthias Ringwald             switch(num_bis){
75910277393SMatthias Ringwald                 case 1:
76010277393SMatthias Ringwald                     gap_periodic_advertising_set_data(adv_handle, sizeof(periodic_adv_data_1), periodic_adv_data_1);
76110277393SMatthias Ringwald                     printf("BASE: ");
76210277393SMatthias Ringwald                     printf_hexdump(periodic_adv_data_1, sizeof(periodic_adv_data_1));
76310277393SMatthias Ringwald                     break;
76410277393SMatthias Ringwald                 case 2:
76510277393SMatthias Ringwald                     gap_periodic_advertising_set_data(adv_handle, sizeof(periodic_adv_data_2), periodic_adv_data_2);
76610277393SMatthias Ringwald                     printf("BASE: ");
76710277393SMatthias Ringwald                     printf_hexdump(periodic_adv_data_2, sizeof(periodic_adv_data_2));
76810277393SMatthias Ringwald                     break;
76910277393SMatthias Ringwald                 default:
77010277393SMatthias Ringwald                     btstack_unreachable();
77110277393SMatthias Ringwald                     break;
77210277393SMatthias Ringwald             }
77310277393SMatthias Ringwald             gap_periodic_advertising_start(adv_handle, 0);
77410277393SMatthias Ringwald             gap_extended_advertising_start(adv_handle, 0, 0);
77510277393SMatthias Ringwald             break;
77610277393SMatthias Ringwald         case 't':
77710277393SMatthias Ringwald             audio_source = 1 - audio_source;
77810277393SMatthias Ringwald             print_config();
77910277393SMatthias Ringwald             break;
78010277393SMatthias Ringwald         case '\n':
78110277393SMatthias Ringwald         case '\r':
78210277393SMatthias Ringwald             break;
78310277393SMatthias Ringwald         default:
78410277393SMatthias Ringwald             show_usage();
78510277393SMatthias Ringwald             break;
78610277393SMatthias Ringwald     }
78710277393SMatthias Ringwald }
78810277393SMatthias Ringwald 
78910277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]);
79010277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]){
79110277393SMatthias Ringwald     (void) argv;
79210277393SMatthias Ringwald     (void) argc;
79310277393SMatthias Ringwald 
79410277393SMatthias Ringwald     // register for HCI events
79510277393SMatthias Ringwald     hci_event_callback_registration.callback = &packet_handler;
79610277393SMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
79710277393SMatthias Ringwald 
79810277393SMatthias Ringwald     // turn on!
79910277393SMatthias Ringwald     hci_power_control(HCI_POWER_ON);
80010277393SMatthias Ringwald 
80110277393SMatthias Ringwald     btstack_stdin_setup(stdin_process);
80210277393SMatthias Ringwald     return 0;
80310277393SMatthias Ringwald }
804