xref: /btstack/test/le_audio/le_audio_broadcast_sink.c (revision 10277393e9b7b0fd2b780785bd4268367172b11f)
1*10277393SMatthias Ringwald /*
2*10277393SMatthias Ringwald  * Copyright (C) 2022 BlueKitchen GmbH
3*10277393SMatthias Ringwald  *
4*10277393SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*10277393SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*10277393SMatthias Ringwald  * are met:
7*10277393SMatthias Ringwald  *
8*10277393SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*10277393SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*10277393SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*10277393SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*10277393SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*10277393SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*10277393SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*10277393SMatthias Ringwald  *    from this software without specific prior written permission.
16*10277393SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*10277393SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*10277393SMatthias Ringwald  *    monetary gain.
19*10277393SMatthias Ringwald  *
20*10277393SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*10277393SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*10277393SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*10277393SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*10277393SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*10277393SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*10277393SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*10277393SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*10277393SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*10277393SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*10277393SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*10277393SMatthias Ringwald  * SUCH DAMAGE.
32*10277393SMatthias Ringwald  *
33*10277393SMatthias Ringwald  * Please inquire about commercial licensing options at
34*10277393SMatthias Ringwald  * [email protected]
35*10277393SMatthias Ringwald  *
36*10277393SMatthias Ringwald  */
37*10277393SMatthias Ringwald 
38*10277393SMatthias Ringwald #define BTSTACK_FILE__ "le_audio_broadcast_sink.c"
39*10277393SMatthias Ringwald 
40*10277393SMatthias Ringwald /*
41*10277393SMatthias Ringwald  * LE Audio Broadcast Sink
42*10277393SMatthias Ringwald  */
43*10277393SMatthias Ringwald 
44*10277393SMatthias Ringwald 
45*10277393SMatthias Ringwald #include "btstack_config.h"
46*10277393SMatthias Ringwald 
47*10277393SMatthias Ringwald #include <stdint.h>
48*10277393SMatthias Ringwald #include <stdio.h>
49*10277393SMatthias Ringwald #include <stdlib.h>
50*10277393SMatthias Ringwald #include <string.h>
51*10277393SMatthias Ringwald #include <unistd.h>
52*10277393SMatthias Ringwald #include <inttypes.h>
53*10277393SMatthias Ringwald #include <fcntl.h>        // open
54*10277393SMatthias Ringwald #include <errno.h>
55*10277393SMatthias Ringwald 
56*10277393SMatthias Ringwald #include "ad_parser.h"
57*10277393SMatthias Ringwald #include "bluetooth_data_types.h"
58*10277393SMatthias Ringwald #include "bluetooth_gatt.h"
59*10277393SMatthias Ringwald #include "btstack_debug.h"
60*10277393SMatthias Ringwald #include "btstack_audio.h"
61*10277393SMatthias Ringwald #include "btstack_event.h"
62*10277393SMatthias Ringwald #include "btstack_run_loop.h"
63*10277393SMatthias Ringwald #include "btstack_ring_buffer.h"
64*10277393SMatthias Ringwald #include "btstack_stdin.h"
65*10277393SMatthias Ringwald #include "btstack_util.h"
66*10277393SMatthias Ringwald #include "gap.h"
67*10277393SMatthias Ringwald #include "hci.h"
68*10277393SMatthias Ringwald #include "hci_cmd.h"
69*10277393SMatthias Ringwald #include "lc3.h"
70*10277393SMatthias Ringwald #include "lc3_ehima.h"
71*10277393SMatthias Ringwald #include "wav_util.h"
72*10277393SMatthias Ringwald 
73*10277393SMatthias Ringwald // max config
74*10277393SMatthias Ringwald #define MAX_NUM_BIS 2
75*10277393SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480
76*10277393SMatthias Ringwald 
77*10277393SMatthias Ringwald #define DUMP_LEN_LC3_FRAMES 1000
78*10277393SMatthias Ringwald 
79*10277393SMatthias Ringwald // playback
80*10277393SMatthias Ringwald #define MAX_NUM_LC3_FRAMES   5
81*10277393SMatthias Ringwald #define MAX_BYTES_PER_SAMPLE 4
82*10277393SMatthias Ringwald #define PLAYBACK_BUFFER_SIZE (MAX_NUM_LC3_FRAMES * MAX_SAMPLES_PER_FRAME * MAX_BYTES_PER_SAMPLE)
83*10277393SMatthias Ringwald 
84*10277393SMatthias Ringwald // analysis
85*10277393SMatthias Ringwald #define PACKET_PREFIX_LEN 10
86*10277393SMatthias Ringwald 
87*10277393SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
88*10277393SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
89*10277393SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
90*10277393SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
91*10277393SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
92*10277393SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
93*10277393SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
94*10277393SMatthias Ringwald 
95*10277393SMatthias Ringwald static void show_usage(void);
96*10277393SMatthias Ringwald 
97*10277393SMatthias Ringwald static const char * filename_lc3 = "le_audio_broadcast_sink.lc3";
98*10277393SMatthias Ringwald static const char * filename_wav = "le_audio_broadcast_sink.wav";
99*10277393SMatthias Ringwald 
100*10277393SMatthias Ringwald static enum {
101*10277393SMatthias Ringwald     APP_W4_WORKING,
102*10277393SMatthias Ringwald     APP_W4_BROADCAST_ADV,
103*10277393SMatthias Ringwald     APP_W4_PA_AND_BIG_INFO,
104*10277393SMatthias Ringwald     APP_CREATE_BIG_SYNC,
105*10277393SMatthias Ringwald     APP_W4_BIG_SYNC_ESTABLISHED,
106*10277393SMatthias Ringwald     APP_SET_ISO_PATHS,
107*10277393SMatthias Ringwald     APP_STREAMING,
108*10277393SMatthias Ringwald     APP_TERMINATE_BIG,
109*10277393SMatthias Ringwald     APP_IDLE
110*10277393SMatthias Ringwald } app_state = APP_W4_WORKING;
111*10277393SMatthias Ringwald 
112*10277393SMatthias Ringwald //
113*10277393SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
114*10277393SMatthias Ringwald 
115*10277393SMatthias Ringwald static bool have_base;
116*10277393SMatthias Ringwald static bool have_big_info;
117*10277393SMatthias Ringwald 
118*10277393SMatthias Ringwald uint32_t last_samples_report_ms;
119*10277393SMatthias Ringwald uint32_t samples_received;
120*10277393SMatthias Ringwald uint32_t samples_dropped;
121*10277393SMatthias Ringwald uint16_t frames_per_second[MAX_NUM_BIS];
122*10277393SMatthias Ringwald 
123*10277393SMatthias Ringwald // remote info
124*10277393SMatthias Ringwald static char remote_name[20];
125*10277393SMatthias Ringwald static bd_addr_t remote;
126*10277393SMatthias Ringwald static bd_addr_type_t remote_type;
127*10277393SMatthias Ringwald static uint8_t remote_sid;
128*10277393SMatthias Ringwald static bool count_mode;
129*10277393SMatthias Ringwald static bool pts_mode;
130*10277393SMatthias Ringwald 
131*10277393SMatthias Ringwald // broadcast info
132*10277393SMatthias Ringwald static const uint8_t    big_handle = 1;
133*10277393SMatthias Ringwald static hci_con_handle_t sync_handle;
134*10277393SMatthias Ringwald static hci_con_handle_t bis_con_handles[MAX_NUM_BIS];
135*10277393SMatthias Ringwald static unsigned int     next_bis_index;
136*10277393SMatthias Ringwald 
137*10277393SMatthias Ringwald // analysis
138*10277393SMatthias Ringwald static uint16_t last_packet_sequence[MAX_NUM_BIS];
139*10277393SMatthias Ringwald static uint32_t last_packet_time_ms[MAX_NUM_BIS];
140*10277393SMatthias Ringwald static uint8_t last_packet_prefix[MAX_NUM_BIS * PACKET_PREFIX_LEN];
141*10277393SMatthias Ringwald 
142*10277393SMatthias Ringwald // lc3 writer
143*10277393SMatthias Ringwald static int dump_file;
144*10277393SMatthias Ringwald static uint32_t lc3_frames;
145*10277393SMatthias Ringwald 
146*10277393SMatthias Ringwald // lc3 codec config
147*10277393SMatthias Ringwald static uint32_t sampling_frequency_hz;
148*10277393SMatthias Ringwald static lc3_frame_duration_t frame_duration;
149*10277393SMatthias Ringwald static uint16_t number_samples_per_frame;
150*10277393SMatthias Ringwald static uint16_t octets_per_frame;
151*10277393SMatthias Ringwald static uint8_t  num_bis;
152*10277393SMatthias Ringwald 
153*10277393SMatthias Ringwald // lc3 decoder
154*10277393SMatthias Ringwald static const lc3_decoder_t * lc3_decoder;
155*10277393SMatthias Ringwald static lc3_decoder_ehima_t decoder_contexts[MAX_NUM_BIS];
156*10277393SMatthias Ringwald static int16_t pcm[MAX_NUM_BIS * MAX_SAMPLES_PER_FRAME];
157*10277393SMatthias Ringwald 
158*10277393SMatthias Ringwald // playback
159*10277393SMatthias Ringwald static uint8_t playback_buffer_storage[PLAYBACK_BUFFER_SIZE];
160*10277393SMatthias Ringwald static btstack_ring_buffer_t playback_buffer;
161*10277393SMatthias Ringwald 
162*10277393SMatthias Ringwald static void le_audio_broadcast_sink_playback(int16_t * buffer, uint16_t num_samples){
163*10277393SMatthias Ringwald     // called from lower-layer but guaranteed to be on main thread
164*10277393SMatthias Ringwald     uint32_t bytes_needed = num_samples * num_bis * 2;
165*10277393SMatthias Ringwald 
166*10277393SMatthias Ringwald     static bool underrun = true;
167*10277393SMatthias Ringwald 
168*10277393SMatthias Ringwald     log_info("Playback: need %u, have %u", num_samples, btstack_ring_buffer_bytes_available(&playback_buffer) / ( num_bis * 2));
169*10277393SMatthias Ringwald 
170*10277393SMatthias Ringwald     if (bytes_needed > btstack_ring_buffer_bytes_available(&playback_buffer)){
171*10277393SMatthias Ringwald         memset(buffer, 0, bytes_needed);
172*10277393SMatthias Ringwald         if (underrun == false){
173*10277393SMatthias Ringwald             log_info("Playback underrun");
174*10277393SMatthias Ringwald             underrun = true;
175*10277393SMatthias Ringwald         }
176*10277393SMatthias Ringwald         return;
177*10277393SMatthias Ringwald     }
178*10277393SMatthias Ringwald 
179*10277393SMatthias Ringwald     if (underrun){
180*10277393SMatthias Ringwald         underrun = false;
181*10277393SMatthias Ringwald         log_info("Playback started");
182*10277393SMatthias Ringwald     }
183*10277393SMatthias Ringwald     uint32_t bytes_read;
184*10277393SMatthias Ringwald     btstack_ring_buffer_read(&playback_buffer, (uint8_t *) buffer, bytes_needed, &bytes_read);
185*10277393SMatthias Ringwald     btstack_assert(bytes_read == bytes_needed);
186*10277393SMatthias Ringwald }
187*10277393SMatthias Ringwald 
188*10277393SMatthias Ringwald static void open_lc3_file(void) {
189*10277393SMatthias Ringwald     // open lc3 file
190*10277393SMatthias Ringwald     int oflags = O_WRONLY | O_CREAT | O_TRUNC;
191*10277393SMatthias Ringwald     dump_file = open(filename_lc3, oflags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
192*10277393SMatthias Ringwald     if (dump_file < 0) {
193*10277393SMatthias Ringwald         printf("failed to open file %s, errno = %d\n", filename_lc3, errno);
194*10277393SMatthias Ringwald         return;
195*10277393SMatthias Ringwald     }
196*10277393SMatthias Ringwald 
197*10277393SMatthias Ringwald     printf("LC3 binary file: %s\n", filename_lc3);
198*10277393SMatthias Ringwald 
199*10277393SMatthias Ringwald     // calc bps
200*10277393SMatthias Ringwald     uint16_t frame_duration_100us = (frame_duration == LC3_FRAME_DURATION_7500US) ? 75 : 100;
201*10277393SMatthias Ringwald     uint32_t bits_per_second = (uint32_t) octets_per_frame * num_bis * 8 * 10000 / frame_duration_100us;
202*10277393SMatthias Ringwald 
203*10277393SMatthias Ringwald     // write header for floating point implementation
204*10277393SMatthias Ringwald     uint8_t header[18];
205*10277393SMatthias Ringwald     little_endian_store_16(header, 0, 0xcc1c);
206*10277393SMatthias Ringwald     little_endian_store_16(header, 2, sizeof(header));
207*10277393SMatthias Ringwald     little_endian_store_16(header, 4, sampling_frequency_hz / 100);
208*10277393SMatthias Ringwald     little_endian_store_16(header, 6, bits_per_second / 100);
209*10277393SMatthias Ringwald     little_endian_store_16(header, 8, num_bis);
210*10277393SMatthias Ringwald     little_endian_store_16(header, 10, frame_duration_100us * 10);
211*10277393SMatthias Ringwald     little_endian_store_16(header, 12, 0);
212*10277393SMatthias Ringwald     little_endian_store_32(header, 14, DUMP_LEN_LC3_FRAMES * number_samples_per_frame);
213*10277393SMatthias Ringwald     write(dump_file, header, sizeof(header));
214*10277393SMatthias Ringwald }
215*10277393SMatthias Ringwald 
216*10277393SMatthias Ringwald static void setup_lc3_decoder(void){
217*10277393SMatthias Ringwald     uint8_t channel;
218*10277393SMatthias Ringwald     for (channel = 0 ; channel < num_bis ; channel++){
219*10277393SMatthias Ringwald         lc3_decoder_ehima_t * decoder_context = &decoder_contexts[channel];
220*10277393SMatthias Ringwald         lc3_decoder = lc3_decoder_ehima_init_instance(decoder_context);
221*10277393SMatthias Ringwald         lc3_decoder->configure(decoder_context, sampling_frequency_hz, frame_duration);
222*10277393SMatthias Ringwald     }
223*10277393SMatthias Ringwald     number_samples_per_frame = lc3_decoder->get_number_samples_per_frame(&decoder_contexts[0]);
224*10277393SMatthias Ringwald     btstack_assert(number_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
225*10277393SMatthias Ringwald }
226*10277393SMatthias Ringwald 
227*10277393SMatthias Ringwald static void close_files(void){
228*10277393SMatthias Ringwald     printf("Close files\n");
229*10277393SMatthias Ringwald     close(dump_file);
230*10277393SMatthias Ringwald     wav_writer_close();
231*10277393SMatthias Ringwald }
232*10277393SMatthias Ringwald 
233*10277393SMatthias Ringwald static void handle_periodic_advertisement(const uint8_t * packet, uint16_t size){
234*10277393SMatthias Ringwald     // periodic advertisement contains the BASE
235*10277393SMatthias Ringwald     // TODO: BASE might be split across multiple advertisements
236*10277393SMatthias Ringwald     const uint8_t * adv_data = hci_subevent_le_periodic_advertising_report_get_data(packet);
237*10277393SMatthias Ringwald     uint16_t adv_size = hci_subevent_le_periodic_advertising_report_get_data_length(packet);
238*10277393SMatthias Ringwald 
239*10277393SMatthias Ringwald     ad_context_t context;
240*10277393SMatthias Ringwald     for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)) {
241*10277393SMatthias Ringwald         uint8_t data_type = ad_iterator_get_data_type(&context);
242*10277393SMatthias Ringwald         uint8_t data_size = ad_iterator_get_data_len(&context);
243*10277393SMatthias Ringwald         const uint8_t * data = ad_iterator_get_data(&context);
244*10277393SMatthias Ringwald         uint16_t uuid;
245*10277393SMatthias Ringwald         switch (data_type){
246*10277393SMatthias Ringwald             case BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID:
247*10277393SMatthias Ringwald                 uuid = little_endian_read_16(data, 0);
248*10277393SMatthias Ringwald                 if (uuid == ORG_BLUETOOTH_SERVICE_BASIC_AUDIO_ANNOUNCEMENT_SERVICE){
249*10277393SMatthias Ringwald                     have_base = true;
250*10277393SMatthias Ringwald                     // Level 1: Group Level
251*10277393SMatthias Ringwald                     const uint8_t * base_data = &data[2];
252*10277393SMatthias Ringwald                     uint16_t base_len = data_size - 2;
253*10277393SMatthias Ringwald                     printf("BASE:\n");
254*10277393SMatthias Ringwald                     uint32_t presentation_delay = little_endian_read_24(base_data, 0);
255*10277393SMatthias Ringwald                     printf("- presentation delay: %"PRIu32" us\n", presentation_delay);
256*10277393SMatthias Ringwald                     uint8_t num_subgroups = base_data[3];
257*10277393SMatthias Ringwald                     printf("- num subgroups: %u\n", num_subgroups);
258*10277393SMatthias Ringwald                     uint8_t i;
259*10277393SMatthias Ringwald                     uint16_t offset = 4;
260*10277393SMatthias Ringwald                     for (i=0;i<num_subgroups;i++){
261*10277393SMatthias Ringwald                         // Level 2: Subgroup Level
262*10277393SMatthias Ringwald                         num_bis = base_data[offset++];
263*10277393SMatthias Ringwald                         printf("  - num bis[%u]: %u\n", i, num_bis);
264*10277393SMatthias Ringwald                         // codec_id: coding format = 0x06, vendor and coded id = 0
265*10277393SMatthias Ringwald                         offset += 5;
266*10277393SMatthias Ringwald                         uint8_t codec_specific_configuration_length = base_data[offset++];
267*10277393SMatthias Ringwald                         const uint8_t * codec_specific_configuration = &base_data[offset];
268*10277393SMatthias Ringwald                         printf("  - codec specific config[%u]: ", i);
269*10277393SMatthias Ringwald                         printf_hexdump(codec_specific_configuration, codec_specific_configuration_length);
270*10277393SMatthias Ringwald                         // parse config to get sampling frequency and frame duration
271*10277393SMatthias Ringwald                         uint8_t codec_offset = 0;
272*10277393SMatthias Ringwald                         while ((codec_offset + 1) < codec_specific_configuration_length){
273*10277393SMatthias Ringwald                             uint8_t ltv_len = codec_specific_configuration[codec_offset++];
274*10277393SMatthias Ringwald                             uint8_t ltv_type = codec_specific_configuration[codec_offset];
275*10277393SMatthias Ringwald                             const uint32_t sampling_frequency_map[] = { 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 384000 };
276*10277393SMatthias Ringwald                             uint8_t sampling_frequency_index;
277*10277393SMatthias Ringwald                             uint8_t frame_duration_index;
278*10277393SMatthias Ringwald                             switch (ltv_type){
279*10277393SMatthias Ringwald                                 case 0x01: // sampling frequency
280*10277393SMatthias Ringwald                                     sampling_frequency_index = codec_specific_configuration[codec_offset+1];
281*10277393SMatthias Ringwald                                     // TODO: check range
282*10277393SMatthias Ringwald                                     sampling_frequency_hz = sampling_frequency_map[sampling_frequency_index - 1];
283*10277393SMatthias Ringwald                                     printf("    - sampling frequency[%u]: %"PRIu32"\n", i, sampling_frequency_hz);
284*10277393SMatthias Ringwald                                     break;
285*10277393SMatthias Ringwald                                 case 0x02: // 0 = 7.5, 1 = 10 ms
286*10277393SMatthias Ringwald                                     frame_duration_index =  codec_specific_configuration[codec_offset+1];
287*10277393SMatthias Ringwald                                     frame_duration = (frame_duration_index == 0) ? LC3_FRAME_DURATION_7500US : LC3_FRAME_DURATION_10000US;
288*10277393SMatthias Ringwald                                     printf("    - frame duration[%u]: %s ms\n", i, (frame_duration == LC3_FRAME_DURATION_7500US) ? "7.5" : "10");
289*10277393SMatthias Ringwald                                     break;
290*10277393SMatthias Ringwald                                 case 0x04:  // octets per coding frame
291*10277393SMatthias Ringwald                                     octets_per_frame = little_endian_read_16(codec_specific_configuration, codec_offset+1);
292*10277393SMatthias Ringwald                                     printf("    - octets per codec frame[%u]: %u\n", i, octets_per_frame);
293*10277393SMatthias Ringwald                                     break;
294*10277393SMatthias Ringwald                                 default:
295*10277393SMatthias Ringwald                                     break;
296*10277393SMatthias Ringwald                             }
297*10277393SMatthias Ringwald                             codec_offset += ltv_len;
298*10277393SMatthias Ringwald                         }
299*10277393SMatthias Ringwald                         //
300*10277393SMatthias Ringwald                         offset += codec_specific_configuration_length;
301*10277393SMatthias Ringwald                         uint8_t metadata_length = base_data[offset++];
302*10277393SMatthias Ringwald                         const uint8_t * meta_data = &base_data[offset];
303*10277393SMatthias Ringwald                         offset += metadata_length;
304*10277393SMatthias Ringwald                         printf("  - meta data[%u]: ", i);
305*10277393SMatthias Ringwald                         printf_hexdump(meta_data, metadata_length);
306*10277393SMatthias Ringwald                         uint8_t k;
307*10277393SMatthias Ringwald                         for (k=0;k<num_bis;k++){
308*10277393SMatthias Ringwald                             // Level 3: BIS Level
309*10277393SMatthias Ringwald                             uint8_t bis_index = base_data[offset++];
310*10277393SMatthias Ringwald                             printf("    - bis index[%u][%u]: %u\n", i, k, bis_index);
311*10277393SMatthias Ringwald                             uint8_t codec_specific_configuration_length2 = base_data[offset++];
312*10277393SMatthias Ringwald                             const uint8_t * codec_specific_configuration2 = &base_data[offset];
313*10277393SMatthias Ringwald                             printf("    - codec specific config[%u][%u]: ", i, k);
314*10277393SMatthias Ringwald                             printf_hexdump(codec_specific_configuration2, codec_specific_configuration_length2);
315*10277393SMatthias Ringwald                             offset += codec_specific_configuration_length2;
316*10277393SMatthias Ringwald                         }
317*10277393SMatthias Ringwald                     }
318*10277393SMatthias Ringwald                 }
319*10277393SMatthias Ringwald                 break;
320*10277393SMatthias Ringwald             default:
321*10277393SMatthias Ringwald                 break;
322*10277393SMatthias Ringwald         }
323*10277393SMatthias Ringwald     }
324*10277393SMatthias Ringwald }
325*10277393SMatthias Ringwald 
326*10277393SMatthias Ringwald static void handle_big_info(const uint8_t * packet, uint16_t size){
327*10277393SMatthias Ringwald     printf("BIG Info advertising report\n");
328*10277393SMatthias Ringwald     sync_handle = hci_subevent_le_biginfo_advertising_report_get_sync_handle(packet);
329*10277393SMatthias Ringwald     have_big_info = true;
330*10277393SMatthias Ringwald }
331*10277393SMatthias Ringwald 
332*10277393SMatthias Ringwald static void enter_create_big_sync(void){
333*10277393SMatthias Ringwald     // stop scanning
334*10277393SMatthias Ringwald     gap_stop_scan();
335*10277393SMatthias Ringwald 
336*10277393SMatthias Ringwald     // init decoder
337*10277393SMatthias Ringwald     setup_lc3_decoder();
338*10277393SMatthias Ringwald 
339*10277393SMatthias Ringwald     printf("Configure: %u channels, sampling rate %u, samples per frame %u\n", num_bis, sampling_frequency_hz, number_samples_per_frame);
340*10277393SMatthias Ringwald 
341*10277393SMatthias Ringwald     // create lc3 file
342*10277393SMatthias Ringwald     open_lc3_file();
343*10277393SMatthias Ringwald 
344*10277393SMatthias Ringwald     // create wav file
345*10277393SMatthias Ringwald     printf("WAV file: %s\n", filename_wav);
346*10277393SMatthias Ringwald     wav_writer_open(filename_wav, num_bis, sampling_frequency_hz);
347*10277393SMatthias Ringwald 
348*10277393SMatthias Ringwald     // init playback buffer
349*10277393SMatthias Ringwald     btstack_ring_buffer_init(&playback_buffer, playback_buffer_storage, PLAYBACK_BUFFER_SIZE);
350*10277393SMatthias Ringwald 
351*10277393SMatthias Ringwald     // start playback
352*10277393SMatthias Ringwald     // PTS 8.2 sends stereo at half speed for stereo, for now playback at half speed
353*10277393SMatthias Ringwald     const btstack_audio_sink_t * sink = btstack_audio_sink_get_instance();
354*10277393SMatthias Ringwald     if (sink != NULL){
355*10277393SMatthias Ringwald         uint32_t playback_speed;
356*10277393SMatthias Ringwald         if ((num_bis > 1) && pts_mode){
357*10277393SMatthias Ringwald             playback_speed = sampling_frequency_hz / num_bis;
358*10277393SMatthias Ringwald             printf("PTS workaround: playback at %u hz\n", playback_speed);
359*10277393SMatthias Ringwald         } else {
360*10277393SMatthias Ringwald             playback_speed = sampling_frequency_hz;
361*10277393SMatthias Ringwald         };
362*10277393SMatthias Ringwald         sink->init(num_bis, sampling_frequency_hz, le_audio_broadcast_sink_playback);
363*10277393SMatthias Ringwald         sink->start_stream();
364*10277393SMatthias Ringwald     }
365*10277393SMatthias Ringwald 
366*10277393SMatthias Ringwald     app_state = APP_CREATE_BIG_SYNC;
367*10277393SMatthias Ringwald }
368*10277393SMatthias Ringwald 
369*10277393SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
370*10277393SMatthias Ringwald     UNUSED(channel);
371*10277393SMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
372*10277393SMatthias Ringwald     unsigned int i;
373*10277393SMatthias Ringwald     switch (packet[0]) {
374*10277393SMatthias Ringwald         case BTSTACK_EVENT_STATE:
375*10277393SMatthias Ringwald             switch(btstack_event_state_get_state(packet)) {
376*10277393SMatthias Ringwald                 case HCI_STATE_WORKING:
377*10277393SMatthias Ringwald                     if (app_state != APP_W4_WORKING) break;
378*10277393SMatthias Ringwald                     app_state = APP_W4_BROADCAST_ADV;
379*10277393SMatthias Ringwald                     gap_set_scan_params(1, 0x30, 0x30, 0);
380*10277393SMatthias Ringwald                     gap_start_scan();
381*10277393SMatthias Ringwald                     printf("Start scan..\n");
382*10277393SMatthias Ringwald                     break;
383*10277393SMatthias Ringwald                 case HCI_STATE_OFF:
384*10277393SMatthias Ringwald                     printf("Goodbye\n");
385*10277393SMatthias Ringwald                     exit(0);
386*10277393SMatthias Ringwald                     break;
387*10277393SMatthias Ringwald                 default:
388*10277393SMatthias Ringwald                     break;
389*10277393SMatthias Ringwald             }
390*10277393SMatthias Ringwald             break;
391*10277393SMatthias Ringwald         case GAP_EVENT_EXTENDED_ADVERTISING_REPORT:
392*10277393SMatthias Ringwald         {
393*10277393SMatthias Ringwald             if (app_state != APP_W4_BROADCAST_ADV) break;
394*10277393SMatthias Ringwald 
395*10277393SMatthias Ringwald             gap_event_extended_advertising_report_get_address(packet, remote);
396*10277393SMatthias Ringwald             uint8_t adv_size = gap_event_extended_advertising_report_get_data_length(packet);
397*10277393SMatthias Ringwald             const uint8_t * adv_data = gap_event_extended_advertising_report_get_data(packet);
398*10277393SMatthias Ringwald 
399*10277393SMatthias Ringwald             ad_context_t context;
400*10277393SMatthias Ringwald             bool found = false;
401*10277393SMatthias Ringwald             remote_name[0] = '\0';
402*10277393SMatthias Ringwald             uint16_t uuid;
403*10277393SMatthias Ringwald             for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)) {
404*10277393SMatthias Ringwald                 uint8_t data_type = ad_iterator_get_data_type(&context);
405*10277393SMatthias Ringwald                 uint8_t size = ad_iterator_get_data_len(&context);
406*10277393SMatthias Ringwald                 const uint8_t *data = ad_iterator_get_data(&context);
407*10277393SMatthias Ringwald                 switch (data_type){
408*10277393SMatthias Ringwald                     case BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID:
409*10277393SMatthias Ringwald                         uuid = little_endian_read_16(data, 0);
410*10277393SMatthias Ringwald                         if (uuid == ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE){
411*10277393SMatthias Ringwald                             found = true;
412*10277393SMatthias Ringwald                         }
413*10277393SMatthias Ringwald                         break;
414*10277393SMatthias Ringwald                     case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME:
415*10277393SMatthias Ringwald                     case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME:
416*10277393SMatthias Ringwald                         size = btstack_min(sizeof(remote_name) - 1, size);
417*10277393SMatthias Ringwald                         memcpy(remote_name, data, size);
418*10277393SMatthias Ringwald                         remote_name[size] = 0;
419*10277393SMatthias Ringwald                         break;
420*10277393SMatthias Ringwald                     default:
421*10277393SMatthias Ringwald                         break;
422*10277393SMatthias Ringwald                 }
423*10277393SMatthias Ringwald             }
424*10277393SMatthias Ringwald             if (!found) break;
425*10277393SMatthias Ringwald             remote_type = gap_event_extended_advertising_report_get_address_type(packet);
426*10277393SMatthias Ringwald             remote_sid = gap_event_extended_advertising_report_get_advertising_sid(packet);
427*10277393SMatthias Ringwald             pts_mode = strncmp("PTS-", remote_name, 4) == 0;
428*10277393SMatthias Ringwald             count_mode = strncmp("COUNT", remote_name, 5) == 0;
429*10277393SMatthias Ringwald             printf("Remote Broadcast sink found, addr %s, name: '%s' (pts-mode: %u, count: %u)\n", bd_addr_to_str(remote), remote_name, pts_mode, count_mode);
430*10277393SMatthias Ringwald             // ignore other advertisements
431*10277393SMatthias Ringwald             gap_whitelist_add(remote_type, remote);
432*10277393SMatthias Ringwald             gap_set_scan_params(1, 0x30, 0x30, 1);
433*10277393SMatthias Ringwald             // sync to PA
434*10277393SMatthias Ringwald             gap_periodic_advertiser_list_clear();
435*10277393SMatthias Ringwald             gap_periodic_advertiser_list_add(remote_type, remote, remote_sid);
436*10277393SMatthias Ringwald             app_state = APP_W4_PA_AND_BIG_INFO;
437*10277393SMatthias Ringwald             printf("Start Periodic Advertising Sync\n");
438*10277393SMatthias Ringwald             gap_periodic_advertising_create_sync(0x01, remote_sid, remote_type, remote, 0, 1000, 0);
439*10277393SMatthias Ringwald             break;
440*10277393SMatthias Ringwald         }
441*10277393SMatthias Ringwald 
442*10277393SMatthias Ringwald         case HCI_EVENT_LE_META:
443*10277393SMatthias Ringwald             switch(hci_event_le_meta_get_subevent_code(packet)) {
444*10277393SMatthias Ringwald                 case HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHMENT:
445*10277393SMatthias Ringwald                     printf("Periodic advertising sync established\n");
446*10277393SMatthias Ringwald                     break;
447*10277393SMatthias Ringwald                 case HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_REPORT:
448*10277393SMatthias Ringwald                     if (have_base) break;
449*10277393SMatthias Ringwald                     handle_periodic_advertisement(packet, size);
450*10277393SMatthias Ringwald                     if (have_big_info){
451*10277393SMatthias Ringwald                         enter_create_big_sync();
452*10277393SMatthias Ringwald                     }
453*10277393SMatthias Ringwald                     break;
454*10277393SMatthias Ringwald                 case HCI_SUBEVENT_LE_BIGINFO_ADVERTISING_REPORT:
455*10277393SMatthias Ringwald                     if (have_big_info) break;
456*10277393SMatthias Ringwald                     handle_big_info(packet, size);
457*10277393SMatthias Ringwald                     if (have_base){
458*10277393SMatthias Ringwald                         enter_create_big_sync();
459*10277393SMatthias Ringwald                     }
460*10277393SMatthias Ringwald                     break;
461*10277393SMatthias Ringwald                 case HCI_SUBEVENT_LE_BIG_SYNC_ESTABLISHED:
462*10277393SMatthias Ringwald                     printf("BIG Sync Established\n");
463*10277393SMatthias Ringwald                     if (app_state == APP_W4_BIG_SYNC_ESTABLISHED){
464*10277393SMatthias Ringwald                         gap_stop_scan();
465*10277393SMatthias Ringwald                         gap_periodic_advertising_terminate_sync(sync_handle);
466*10277393SMatthias Ringwald                         // update num_bis
467*10277393SMatthias Ringwald                         num_bis = packet[16];
468*10277393SMatthias Ringwald                         for (i=0;i<num_bis;i++){
469*10277393SMatthias Ringwald                             bis_con_handles[i] = little_endian_read_16(packet, 17 + 2*i);
470*10277393SMatthias Ringwald                         }
471*10277393SMatthias Ringwald                         next_bis_index = 0;
472*10277393SMatthias Ringwald                         app_state = APP_SET_ISO_PATHS;
473*10277393SMatthias Ringwald                     }
474*10277393SMatthias Ringwald                     break;
475*10277393SMatthias Ringwald                 default:
476*10277393SMatthias Ringwald                     break;
477*10277393SMatthias Ringwald             }
478*10277393SMatthias Ringwald         default:
479*10277393SMatthias Ringwald             break;
480*10277393SMatthias Ringwald     }
481*10277393SMatthias Ringwald 
482*10277393SMatthias Ringwald     if (!hci_can_send_command_packet_now()) return;
483*10277393SMatthias Ringwald 
484*10277393SMatthias Ringwald     const uint8_t broadcast_code[16] = { 0 };
485*10277393SMatthias Ringwald     uint8_t bis_array[MAX_NUM_BIS];
486*10277393SMatthias Ringwald     switch(app_state){
487*10277393SMatthias Ringwald         case APP_CREATE_BIG_SYNC:
488*10277393SMatthias Ringwald             app_state = APP_W4_BIG_SYNC_ESTABLISHED;
489*10277393SMatthias Ringwald             printf("BIG Create Sync for BIS: ");
490*10277393SMatthias Ringwald             for (i=0;i<num_bis;i++){
491*10277393SMatthias Ringwald                 bis_array[i] = i + 1;
492*10277393SMatthias Ringwald                 printf("%u ", bis_array[i]);
493*10277393SMatthias Ringwald             }
494*10277393SMatthias Ringwald             printf("\n");
495*10277393SMatthias Ringwald             hci_send_cmd(&hci_le_big_create_sync, big_handle, sync_handle, 0, broadcast_code, 0, 100, num_bis, bis_array);
496*10277393SMatthias Ringwald             break;
497*10277393SMatthias Ringwald         case APP_SET_ISO_PATHS:
498*10277393SMatthias Ringwald             hci_send_cmd(&hci_le_setup_iso_data_path, bis_con_handles[next_bis_index++], 1, 0, 0, 0, 0, 0, 0, NULL);
499*10277393SMatthias Ringwald             if (next_bis_index == num_bis){
500*10277393SMatthias Ringwald                 app_state = APP_STREAMING;
501*10277393SMatthias Ringwald                 last_samples_report_ms = btstack_run_loop_get_time_ms();
502*10277393SMatthias Ringwald             }
503*10277393SMatthias Ringwald             break;
504*10277393SMatthias Ringwald         case APP_TERMINATE_BIG:
505*10277393SMatthias Ringwald             hci_send_cmd(&hci_le_big_terminate_sync, big_handle);
506*10277393SMatthias Ringwald             app_state = APP_IDLE;
507*10277393SMatthias Ringwald             printf("Shutdown...\n");
508*10277393SMatthias Ringwald             hci_power_control(HCI_POWER_OFF);
509*10277393SMatthias Ringwald             break;
510*10277393SMatthias Ringwald         default:
511*10277393SMatthias Ringwald             break;
512*10277393SMatthias Ringwald     }
513*10277393SMatthias Ringwald }
514*10277393SMatthias Ringwald 
515*10277393SMatthias Ringwald static void iso_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
516*10277393SMatthias Ringwald 
517*10277393SMatthias Ringwald     uint16_t header = little_endian_read_16(packet, 0);
518*10277393SMatthias Ringwald     hci_con_handle_t con_handle = header & 0x0fff;
519*10277393SMatthias Ringwald     uint8_t pb_flag = (header >> 12) & 3;
520*10277393SMatthias Ringwald     uint8_t ts_flag = (header >> 14) & 1;
521*10277393SMatthias Ringwald     uint16_t iso_load_len = little_endian_read_16(packet, 2);
522*10277393SMatthias Ringwald 
523*10277393SMatthias Ringwald     uint16_t offset = 4;
524*10277393SMatthias Ringwald     uint32_t time_stamp = 0;
525*10277393SMatthias Ringwald     if (ts_flag){
526*10277393SMatthias Ringwald         uint32_t time_stamp = little_endian_read_32(packet, offset);
527*10277393SMatthias Ringwald         offset += 4;
528*10277393SMatthias Ringwald     }
529*10277393SMatthias Ringwald 
530*10277393SMatthias Ringwald     uint16_t packet_sequence_number = little_endian_read_16(packet, offset);
531*10277393SMatthias Ringwald     offset += 2;
532*10277393SMatthias Ringwald 
533*10277393SMatthias Ringwald     uint16_t header_2 = little_endian_read_16(packet, offset);
534*10277393SMatthias Ringwald     uint16_t iso_sdu_length = header_2 & 0x3fff;
535*10277393SMatthias Ringwald     uint8_t packet_status_flag = (uint8_t) (header_2 >> 14);
536*10277393SMatthias Ringwald     offset += 2;
537*10277393SMatthias Ringwald 
538*10277393SMatthias Ringwald     if (iso_sdu_length == 0) return;
539*10277393SMatthias Ringwald 
540*10277393SMatthias Ringwald     // infer channel from con handle - only works for up to 2 channels
541*10277393SMatthias Ringwald     uint8_t bis_channel = (con_handle == bis_con_handles[0]) ? 0 : 1;
542*10277393SMatthias Ringwald 
543*10277393SMatthias Ringwald     if (count_mode){
544*10277393SMatthias Ringwald         // check for missing packet
545*10277393SMatthias Ringwald         uint16_t last_seq_no = last_packet_sequence[bis_channel];
546*10277393SMatthias Ringwald         uint32_t now = btstack_run_loop_get_time_ms();
547*10277393SMatthias Ringwald         bool packet_missed = (last_seq_no != 0) && ((last_seq_no + 1) != packet_sequence_number);
548*10277393SMatthias Ringwald         if (packet_missed){
549*10277393SMatthias Ringwald             // print last packet
550*10277393SMatthias Ringwald             printf("\n");
551*10277393SMatthias Ringwald             printf("%04x %10u %u ", last_seq_no, last_packet_time_ms[bis_channel], bis_channel);
552*10277393SMatthias Ringwald             printf_hexdump(&last_packet_prefix[num_bis*PACKET_PREFIX_LEN], PACKET_PREFIX_LEN);
553*10277393SMatthias Ringwald             last_seq_no++;
554*10277393SMatthias Ringwald 
555*10277393SMatthias Ringwald             printf(ANSI_COLOR_RED);
556*10277393SMatthias Ringwald             while (last_seq_no < packet_sequence_number){
557*10277393SMatthias Ringwald                 printf("%04x            %u MISSING\n", last_seq_no, bis_channel);
558*10277393SMatthias Ringwald                 last_seq_no++;
559*10277393SMatthias Ringwald             }
560*10277393SMatthias Ringwald             printf(ANSI_COLOR_RESET);
561*10277393SMatthias Ringwald 
562*10277393SMatthias Ringwald             // print current packet
563*10277393SMatthias Ringwald             printf("%04x %10u %u ", packet_sequence_number, now, bis_channel);
564*10277393SMatthias Ringwald             printf_hexdump(&packet[offset], PACKET_PREFIX_LEN);
565*10277393SMatthias Ringwald         }
566*10277393SMatthias Ringwald 
567*10277393SMatthias Ringwald         // cache current packet
568*10277393SMatthias Ringwald         last_packet_time_ms[bis_channel] = now;
569*10277393SMatthias Ringwald         last_packet_sequence[bis_channel] = packet_sequence_number;
570*10277393SMatthias Ringwald         memcpy(&last_packet_prefix[num_bis*PACKET_PREFIX_LEN], &packet[offset], PACKET_PREFIX_LEN);
571*10277393SMatthias Ringwald 
572*10277393SMatthias Ringwald     } else {
573*10277393SMatthias Ringwald 
574*10277393SMatthias Ringwald         if ((packet_sequence_number & 0x7c) == 0) {
575*10277393SMatthias Ringwald             printf("%04x %10u %u ", packet_sequence_number, btstack_run_loop_get_time_ms(), bis_channel);
576*10277393SMatthias Ringwald             printf_hexdump(&packet[offset], iso_sdu_length);
577*10277393SMatthias Ringwald         }
578*10277393SMatthias Ringwald 
579*10277393SMatthias Ringwald         if (lc3_frames < DUMP_LEN_LC3_FRAMES) {
580*10277393SMatthias Ringwald             // store len header only for first bis
581*10277393SMatthias Ringwald             if (bis_channel == 0) {
582*10277393SMatthias Ringwald                 uint8_t len_header[2];
583*10277393SMatthias Ringwald                 little_endian_store_16(len_header, 0, num_bis * iso_sdu_length);
584*10277393SMatthias Ringwald                 write(dump_file, len_header, 2);
585*10277393SMatthias Ringwald             }
586*10277393SMatthias Ringwald 
587*10277393SMatthias Ringwald             // store single channel codec frame
588*10277393SMatthias Ringwald             write(dump_file, &packet[offset], iso_sdu_length);
589*10277393SMatthias Ringwald         }
590*10277393SMatthias Ringwald 
591*10277393SMatthias Ringwald         // decode codec frame
592*10277393SMatthias Ringwald         uint8_t tmp_BEC_detect;
593*10277393SMatthias Ringwald         uint8_t BFI = 0;
594*10277393SMatthias Ringwald         (void) lc3_decoder->decode(&decoder_contexts[bis_channel], &packet[offset], iso_sdu_length, BFI,
595*10277393SMatthias Ringwald                                    &pcm[bis_channel * MAX_SAMPLES_PER_FRAME], number_samples_per_frame,
596*10277393SMatthias Ringwald                                    &tmp_BEC_detect);
597*10277393SMatthias Ringwald 
598*10277393SMatthias Ringwald         // interleave channel samples
599*10277393SMatthias Ringwald         if ((bis_channel + 1) == num_bis) {
600*10277393SMatthias Ringwald             uint16_t sample;
601*10277393SMatthias Ringwald             int16_t wav_frame[MAX_NUM_BIS];
602*10277393SMatthias Ringwald             uint8_t wav_channel;
603*10277393SMatthias Ringwald             for (sample = 0; sample < number_samples_per_frame; sample++) {
604*10277393SMatthias Ringwald                 for (wav_channel = 0; wav_channel < num_bis; wav_channel++) {
605*10277393SMatthias Ringwald                     wav_frame[wav_channel] = pcm[wav_channel * MAX_SAMPLES_PER_FRAME + sample];
606*10277393SMatthias Ringwald                 }
607*10277393SMatthias Ringwald 
608*10277393SMatthias Ringwald                 // write wav sample
609*10277393SMatthias Ringwald                 if (lc3_frames < DUMP_LEN_LC3_FRAMES) {
610*10277393SMatthias Ringwald                     wav_writer_write_int16(num_bis, wav_frame);
611*10277393SMatthias Ringwald                 }
612*10277393SMatthias Ringwald 
613*10277393SMatthias Ringwald                 // store sample in playback buffer
614*10277393SMatthias Ringwald                 uint32_t bytes_to_store = num_bis * 2;
615*10277393SMatthias Ringwald                 samples_received++;
616*10277393SMatthias Ringwald                 if (btstack_ring_buffer_bytes_free(&playback_buffer) >= bytes_to_store) {
617*10277393SMatthias Ringwald                     btstack_ring_buffer_write(&playback_buffer, (uint8_t *) wav_frame, bytes_to_store);
618*10277393SMatthias Ringwald                 } else {
619*10277393SMatthias Ringwald                     samples_dropped++;
620*10277393SMatthias Ringwald                 }
621*10277393SMatthias Ringwald             }
622*10277393SMatthias Ringwald         }
623*10277393SMatthias Ringwald 
624*10277393SMatthias Ringwald         log_info("Samples in playback buffer %5u", btstack_ring_buffer_bytes_available(&playback_buffer) / (num_bis * 2));
625*10277393SMatthias Ringwald 
626*10277393SMatthias Ringwald         lc3_frames++;
627*10277393SMatthias Ringwald         frames_per_second[bis_channel]++;
628*10277393SMatthias Ringwald 
629*10277393SMatthias Ringwald         uint32_t time_ms = btstack_run_loop_get_time_ms();
630*10277393SMatthias Ringwald         if (btstack_time_delta(time_ms, last_samples_report_ms) > 1000){
631*10277393SMatthias Ringwald             last_samples_report_ms = time_ms;
632*10277393SMatthias Ringwald             printf("LC3 Frames: %4u - ", lc3_frames / num_bis);
633*10277393SMatthias Ringwald             uint8_t i;
634*10277393SMatthias Ringwald             for (i=0;i<num_bis;i++){
635*10277393SMatthias Ringwald                 printf("%u ", frames_per_second[i]);
636*10277393SMatthias Ringwald                 frames_per_second[i] = 0;
637*10277393SMatthias Ringwald             }
638*10277393SMatthias Ringwald             printf(" frames per second, dropped %u of %u\n", samples_dropped, samples_received);
639*10277393SMatthias Ringwald             samples_received = 0;
640*10277393SMatthias Ringwald             samples_dropped  =  0;
641*10277393SMatthias Ringwald         }
642*10277393SMatthias Ringwald 
643*10277393SMatthias Ringwald         if (lc3_frames == DUMP_LEN_LC3_FRAMES){
644*10277393SMatthias Ringwald             close_files();
645*10277393SMatthias Ringwald         }
646*10277393SMatthias Ringwald     }
647*10277393SMatthias Ringwald }
648*10277393SMatthias Ringwald 
649*10277393SMatthias Ringwald static void show_usage(void){
650*10277393SMatthias Ringwald     printf("\n--- LE Audio Broadcast Sink Test Console ---\n");
651*10277393SMatthias Ringwald     printf("x - close files and exit\n");
652*10277393SMatthias Ringwald     printf("---\n");
653*10277393SMatthias Ringwald }
654*10277393SMatthias Ringwald 
655*10277393SMatthias Ringwald static void stdin_process(char c){
656*10277393SMatthias Ringwald     switch (c){
657*10277393SMatthias Ringwald         case 'x':
658*10277393SMatthias Ringwald             close_files();
659*10277393SMatthias Ringwald             printf("Shutdown...\n");
660*10277393SMatthias Ringwald             hci_power_control(HCI_POWER_OFF);
661*10277393SMatthias Ringwald             break;
662*10277393SMatthias Ringwald         case '\n':
663*10277393SMatthias Ringwald         case '\r':
664*10277393SMatthias Ringwald             break;
665*10277393SMatthias Ringwald         default:
666*10277393SMatthias Ringwald             show_usage();
667*10277393SMatthias Ringwald             break;
668*10277393SMatthias Ringwald 
669*10277393SMatthias Ringwald     }
670*10277393SMatthias Ringwald }
671*10277393SMatthias Ringwald 
672*10277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]);
673*10277393SMatthias Ringwald int btstack_main(int argc, const char * argv[]){
674*10277393SMatthias Ringwald     (void) argv;
675*10277393SMatthias Ringwald     (void) argc;
676*10277393SMatthias Ringwald 
677*10277393SMatthias Ringwald     // register for HCI events
678*10277393SMatthias Ringwald     hci_event_callback_registration.callback = &packet_handler;
679*10277393SMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
680*10277393SMatthias Ringwald 
681*10277393SMatthias Ringwald     // register for ISO Packet
682*10277393SMatthias Ringwald     hci_register_iso_packet_handler(&iso_packet_handler);
683*10277393SMatthias Ringwald 
684*10277393SMatthias Ringwald     // turn on!
685*10277393SMatthias Ringwald     hci_power_control(HCI_POWER_ON);
686*10277393SMatthias Ringwald 
687*10277393SMatthias Ringwald     btstack_stdin_setup(stdin_process);
688*10277393SMatthias Ringwald     return 0;
689*10277393SMatthias Ringwald }
690