xref: /btstack/example/le_audio_demo_util_sink.c (revision 24b69d49bc179fd737e711799d7dd499cbeb047f)
1*24b69d49SMatthias Ringwald /*
2*24b69d49SMatthias Ringwald  * Copyright (C) {copyright_year} BlueKitchen GmbH
3*24b69d49SMatthias Ringwald  *
4*24b69d49SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*24b69d49SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*24b69d49SMatthias Ringwald  * are met:
7*24b69d49SMatthias Ringwald  *
8*24b69d49SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*24b69d49SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*24b69d49SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*24b69d49SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*24b69d49SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*24b69d49SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*24b69d49SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*24b69d49SMatthias Ringwald  *    from this software without specific prior written permission.
16*24b69d49SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*24b69d49SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*24b69d49SMatthias Ringwald  *    monetary gain.
19*24b69d49SMatthias Ringwald  *
20*24b69d49SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*24b69d49SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*24b69d49SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*24b69d49SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*24b69d49SMatthias Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*24b69d49SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*24b69d49SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*24b69d49SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*24b69d49SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*24b69d49SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*24b69d49SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*24b69d49SMatthias Ringwald  * SUCH DAMAGE.
32*24b69d49SMatthias Ringwald  *
33*24b69d49SMatthias Ringwald  * Please inquire about commercial licensing options at
34*24b69d49SMatthias Ringwald  * [email protected]
35*24b69d49SMatthias Ringwald  *
36*24b69d49SMatthias Ringwald  */
37*24b69d49SMatthias Ringwald 
38*24b69d49SMatthias Ringwald #define BTSTACK_FILE__ "le_audio_demo_util_sink.c"
39*24b69d49SMatthias Ringwald 
40*24b69d49SMatthias Ringwald #include "le_audio_demo_util_sink.h"
41*24b69d49SMatthias Ringwald 
42*24b69d49SMatthias Ringwald #include "btstack_bool.h"
43*24b69d49SMatthias Ringwald #include "btstack_config.h"
44*24b69d49SMatthias Ringwald #include <btstack_debug.h>
45*24b69d49SMatthias Ringwald #include <printf.h>
46*24b69d49SMatthias Ringwald 
47*24b69d49SMatthias Ringwald #include "hci.h"
48*24b69d49SMatthias Ringwald #include "btstack_audio.h"
49*24b69d49SMatthias Ringwald #include "btstack_lc3_google.h"
50*24b69d49SMatthias Ringwald #include "btstack_lc3plus_fraunhofer.h"
51*24b69d49SMatthias Ringwald 
52*24b69d49SMatthias Ringwald #include "hxcmod.h"
53*24b69d49SMatthias Ringwald #include "mods/mod.h"
54*24b69d49SMatthias Ringwald 
55*24b69d49SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
56*24b69d49SMatthias Ringwald #include "wav_util.h"
57*24b69d49SMatthias Ringwald #include "btstack_ring_buffer.h"
58*24b69d49SMatthias Ringwald 
59*24b69d49SMatthias Ringwald #endif
60*24b69d49SMatthias Ringwald 
61*24b69d49SMatthias Ringwald //#define DEBUG_PLC
62*24b69d49SMatthias Ringwald #ifdef DEBUG_PLC
63*24b69d49SMatthias Ringwald #define printf_plc(...) printf(__VA_ARGS__)
64*24b69d49SMatthias Ringwald #else
65*24b69d49SMatthias Ringwald #define printf_plc(...)  (void)(0);
66*24b69d49SMatthias Ringwald #endif
67*24b69d49SMatthias Ringwald 
68*24b69d49SMatthias Ringwald #define MAX_CHANNELS 2
69*24b69d49SMatthias Ringwald #define MAX_SAMPLES_PER_FRAME 480
70*24b69d49SMatthias Ringwald #define MAX_LC3_FRAME_BYTES   155
71*24b69d49SMatthias Ringwald 
72*24b69d49SMatthias Ringwald // playback
73*24b69d49SMatthias Ringwald #define MAX_NUM_LC3_FRAMES   15
74*24b69d49SMatthias Ringwald #define MAX_BYTES_PER_SAMPLE 4
75*24b69d49SMatthias Ringwald #define PLAYBACK_BUFFER_SIZE (MAX_NUM_LC3_FRAMES * MAX_SAMPLES_PER_FRAME * MAX_BYTES_PER_SAMPLE)
76*24b69d49SMatthias Ringwald #define PLAYBACK_START_MS (MAX_NUM_LC3_FRAMES * 20 / 3)
77*24b69d49SMatthias Ringwald 
78*24b69d49SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
79*24b69d49SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
80*24b69d49SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
81*24b69d49SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
82*24b69d49SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
83*24b69d49SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
84*24b69d49SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
85*24b69d49SMatthias Ringwald 
86*24b69d49SMatthias Ringwald // SINK
87*24b69d49SMatthias Ringwald 
88*24b69d49SMatthias Ringwald static const char * le_audio_demo_sink_filename_wav;
89*24b69d49SMatthias Ringwald 
90*24b69d49SMatthias Ringwald static btstack_lc3_frame_duration_t le_audio_demo_sink_frame_duration;
91*24b69d49SMatthias Ringwald static hci_iso_type_t               le_audio_demo_sink_type;
92*24b69d49SMatthias Ringwald 
93*24b69d49SMatthias Ringwald static uint32_t le_audio_demo_sink_sampling_frequency_hz;
94*24b69d49SMatthias Ringwald static uint16_t le_audio_demo_sink_num_samples_per_frame;
95*24b69d49SMatthias Ringwald static uint8_t  le_audio_demo_sink_num_streams;
96*24b69d49SMatthias Ringwald static uint8_t  le_audio_demo_sink_num_channels_per_stream;
97*24b69d49SMatthias Ringwald static uint8_t  le_audio_demo_sink_num_channels;
98*24b69d49SMatthias Ringwald static uint16_t le_audio_demo_sink_octets_per_frame;
99*24b69d49SMatthias Ringwald static uint16_t le_audio_demo_sink_iso_interval_1250us;
100*24b69d49SMatthias Ringwald static uint8_t  le_audio_demo_sink_flush_timeout;
101*24b69d49SMatthias Ringwald static uint8_t  le_audio_demo_sink_pre_transmission_offset;
102*24b69d49SMatthias Ringwald 
103*24b69d49SMatthias Ringwald // playback
104*24b69d49SMatthias Ringwald static uint16_t              playback_start_threshold_bytes;
105*24b69d49SMatthias Ringwald static bool                  playback_active;
106*24b69d49SMatthias Ringwald static uint8_t               playback_buffer_storage[PLAYBACK_BUFFER_SIZE];
107*24b69d49SMatthias Ringwald static btstack_ring_buffer_t playback_buffer;
108*24b69d49SMatthias Ringwald 
109*24b69d49SMatthias Ringwald // PLC
110*24b69d49SMatthias Ringwald static bool     stream_last_packet_received[MAX_CHANNELS];
111*24b69d49SMatthias Ringwald static uint16_t stream_last_packet_sequence[MAX_CHANNELS];
112*24b69d49SMatthias Ringwald static uint16_t group_last_packet_sequence;
113*24b69d49SMatthias Ringwald static bool     group_last_packet_received;
114*24b69d49SMatthias Ringwald 
115*24b69d49SMatthias Ringwald static uint32_t le_audio_demo_sink_lc3_frames;
116*24b69d49SMatthias Ringwald static uint32_t samples_received;
117*24b69d49SMatthias Ringwald static uint32_t samples_played;
118*24b69d49SMatthias Ringwald static uint32_t samples_dropped;
119*24b69d49SMatthias Ringwald 
120*24b69d49SMatthias Ringwald static btstack_timer_source_t next_packet_timer;
121*24b69d49SMatthias Ringwald 
122*24b69d49SMatthias Ringwald // lc3 decoder
123*24b69d49SMatthias Ringwald static bool le_audio_demo_lc3plus_decoder_requested = false;
124*24b69d49SMatthias Ringwald static const btstack_lc3_decoder_t * lc3_decoder;
125*24b69d49SMatthias Ringwald static int16_t pcm[MAX_CHANNELS * MAX_SAMPLES_PER_FRAME];
126*24b69d49SMatthias Ringwald static bool have_pcm[MAX_CHANNELS];
127*24b69d49SMatthias Ringwald 
128*24b69d49SMatthias Ringwald static btstack_lc3_decoder_google_t google_decoder_contexts[MAX_CHANNELS];
129*24b69d49SMatthias Ringwald #ifdef HAVE_LC3PLUS
130*24b69d49SMatthias Ringwald static btstack_lc3plus_fraunhofer_decoder_t fraunhofer_decoder_contexts[MAX_CHANNELS];
131*24b69d49SMatthias Ringwald #endif
132*24b69d49SMatthias Ringwald static void * decoder_contexts[MAX_CHANNELS];
133*24b69d49SMatthias Ringwald 
134*24b69d49SMatthias Ringwald static void le_audio_connection_sink_playback(int16_t * buffer, uint16_t num_samples){
135*24b69d49SMatthias Ringwald     // called from lower-layer but guaranteed to be on main thread
136*24b69d49SMatthias Ringwald     log_info("Playback: need %u, have %u", num_samples, btstack_ring_buffer_bytes_available(&playback_buffer) / (le_audio_demo_sink_num_channels * 2));
137*24b69d49SMatthias Ringwald 
138*24b69d49SMatthias Ringwald     samples_played += num_samples;
139*24b69d49SMatthias Ringwald 
140*24b69d49SMatthias Ringwald     uint32_t bytes_needed = num_samples * le_audio_demo_sink_num_channels * 2;
141*24b69d49SMatthias Ringwald     if (playback_active == false){
142*24b69d49SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&playback_buffer) >= playback_start_threshold_bytes) {
143*24b69d49SMatthias Ringwald             log_info("Playback started");
144*24b69d49SMatthias Ringwald             playback_active = true;
145*24b69d49SMatthias Ringwald         }
146*24b69d49SMatthias Ringwald     } else {
147*24b69d49SMatthias Ringwald         if (bytes_needed > btstack_ring_buffer_bytes_available(&playback_buffer)) {
148*24b69d49SMatthias Ringwald             log_info("Playback underrun");
149*24b69d49SMatthias Ringwald             printf("Playback Underrun\n");
150*24b69d49SMatthias Ringwald             // empty buffer
151*24b69d49SMatthias Ringwald             uint32_t bytes_read;
152*24b69d49SMatthias Ringwald             btstack_ring_buffer_read(&playback_buffer, (uint8_t *) buffer, bytes_needed, &bytes_read);
153*24b69d49SMatthias Ringwald             playback_active = false;
154*24b69d49SMatthias Ringwald         }
155*24b69d49SMatthias Ringwald     }
156*24b69d49SMatthias Ringwald 
157*24b69d49SMatthias Ringwald     if (playback_active){
158*24b69d49SMatthias Ringwald         uint32_t bytes_read;
159*24b69d49SMatthias Ringwald         btstack_ring_buffer_read(&playback_buffer, (uint8_t *) buffer, bytes_needed, &bytes_read);
160*24b69d49SMatthias Ringwald         btstack_assert(bytes_read == bytes_needed);
161*24b69d49SMatthias Ringwald     } else {
162*24b69d49SMatthias Ringwald         memset(buffer, 0, bytes_needed);
163*24b69d49SMatthias Ringwald     }
164*24b69d49SMatthias Ringwald }
165*24b69d49SMatthias Ringwald 
166*24b69d49SMatthias Ringwald static void setup_lc3_decoder(void){
167*24b69d49SMatthias Ringwald     uint8_t channel;
168*24b69d49SMatthias Ringwald     for (channel = 0 ; channel < le_audio_demo_sink_num_channels ; channel++){
169*24b69d49SMatthias Ringwald         // pick decoder
170*24b69d49SMatthias Ringwald         void * decoder_context = NULL;
171*24b69d49SMatthias Ringwald #ifdef HAVE_LC3PLUS
172*24b69d49SMatthias Ringwald         if (use_lc3plus_decoder){
173*24b69d49SMatthias Ringwald             decoder_context = &fraunhofer_decoder_contexts[channel];
174*24b69d49SMatthias Ringwald             lc3_decoder = btstack_lc3plus_fraunhofer_decoder_init_instance(decoder_context);
175*24b69d49SMatthias Ringwald         }
176*24b69d49SMatthias Ringwald         else
177*24b69d49SMatthias Ringwald #endif
178*24b69d49SMatthias Ringwald         {
179*24b69d49SMatthias Ringwald             decoder_context = &google_decoder_contexts[channel];
180*24b69d49SMatthias Ringwald             lc3_decoder = btstack_lc3_decoder_google_init_instance(decoder_context);
181*24b69d49SMatthias Ringwald         }
182*24b69d49SMatthias Ringwald         decoder_contexts[channel] = decoder_context;
183*24b69d49SMatthias Ringwald         lc3_decoder->configure(decoder_context, le_audio_demo_sink_sampling_frequency_hz, le_audio_demo_sink_frame_duration, le_audio_demo_sink_octets_per_frame);
184*24b69d49SMatthias Ringwald     }
185*24b69d49SMatthias Ringwald     btstack_assert(le_audio_demo_sink_num_samples_per_frame <= MAX_SAMPLES_PER_FRAME);
186*24b69d49SMatthias Ringwald }
187*24b69d49SMatthias Ringwald 
188*24b69d49SMatthias Ringwald static void store_samples_in_ringbuffer(void){
189*24b69d49SMatthias Ringwald     // check if we have all channels
190*24b69d49SMatthias Ringwald     uint8_t channel;
191*24b69d49SMatthias Ringwald     for (channel = 0; channel < le_audio_demo_sink_num_channels; channel++){
192*24b69d49SMatthias Ringwald         if (have_pcm[channel] == false) return;
193*24b69d49SMatthias Ringwald     }
194*24b69d49SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
195*24b69d49SMatthias Ringwald     // write wav samples
196*24b69d49SMatthias Ringwald     wav_writer_write_int16(le_audio_demo_sink_num_channels * le_audio_demo_sink_num_samples_per_frame, pcm);
197*24b69d49SMatthias Ringwald #endif
198*24b69d49SMatthias Ringwald     // store samples in playback buffer
199*24b69d49SMatthias Ringwald     uint32_t bytes_to_store = le_audio_demo_sink_num_channels * le_audio_demo_sink_num_samples_per_frame * 2;
200*24b69d49SMatthias Ringwald     samples_received += le_audio_demo_sink_num_samples_per_frame;
201*24b69d49SMatthias Ringwald     if (btstack_ring_buffer_bytes_free(&playback_buffer) >= bytes_to_store) {
202*24b69d49SMatthias Ringwald         btstack_ring_buffer_write(&playback_buffer, (uint8_t *) pcm, bytes_to_store);
203*24b69d49SMatthias Ringwald     } else {
204*24b69d49SMatthias Ringwald         printf("Samples dropped\n");
205*24b69d49SMatthias Ringwald         samples_dropped += le_audio_demo_sink_num_samples_per_frame;
206*24b69d49SMatthias Ringwald     }
207*24b69d49SMatthias Ringwald     memset(have_pcm, 0, sizeof(have_pcm));
208*24b69d49SMatthias Ringwald }
209*24b69d49SMatthias Ringwald 
210*24b69d49SMatthias Ringwald static void plc_do(uint8_t stream_index) {
211*24b69d49SMatthias Ringwald     // inject packet
212*24b69d49SMatthias Ringwald     uint8_t tmp_BEC_detect;
213*24b69d49SMatthias Ringwald     uint8_t BFI = 1;
214*24b69d49SMatthias Ringwald     uint8_t i;
215*24b69d49SMatthias Ringwald     for (i = 0; i < le_audio_demo_sink_num_channels_per_stream; i++){
216*24b69d49SMatthias Ringwald         uint8_t effective_channel = stream_index + i;
217*24b69d49SMatthias Ringwald         (void) lc3_decoder->decode_signed_16(decoder_contexts[effective_channel], NULL, BFI,
218*24b69d49SMatthias Ringwald                                              &pcm[effective_channel], le_audio_demo_sink_num_channels,
219*24b69d49SMatthias Ringwald                                              &tmp_BEC_detect);
220*24b69d49SMatthias Ringwald     }
221*24b69d49SMatthias Ringwald     // and store in ringbuffer when PCM for all channels is available
222*24b69d49SMatthias Ringwald     store_samples_in_ringbuffer();
223*24b69d49SMatthias Ringwald }
224*24b69d49SMatthias Ringwald 
225*24b69d49SMatthias Ringwald //
226*24b69d49SMatthias Ringwald // Perform PLC for packets missing in previous intervals
227*24b69d49SMatthias Ringwald //
228*24b69d49SMatthias Ringwald // assumptions:
229*24b69d49SMatthias Ringwald // - packet sequence number is monotonic increasing
230*24b69d49SMatthias Ringwald // - if packet with seq nr x is received, all packets with smaller seq number are either received or missed
231*24b69d49SMatthias Ringwald static void plc_check(uint16_t packet_sequence_number) {
232*24b69d49SMatthias Ringwald     while (group_last_packet_sequence != packet_sequence_number){
233*24b69d49SMatthias Ringwald         uint8_t i;
234*24b69d49SMatthias Ringwald         for (i=0;i<le_audio_demo_sink_num_streams;i++){
235*24b69d49SMatthias Ringwald             // deal with first packet missing. inject silent samples, pcm buffer is memset to zero at start
236*24b69d49SMatthias Ringwald             if (stream_last_packet_received[i] == false){
237*24b69d49SMatthias Ringwald                 printf_plc("- ISO #%u, very first packet missing\n", i);
238*24b69d49SMatthias Ringwald                 have_pcm[i] = true;
239*24b69d49SMatthias Ringwald                 store_samples_in_ringbuffer();
240*24b69d49SMatthias Ringwald 
241*24b69d49SMatthias Ringwald                 stream_last_packet_received[i] = true;
242*24b69d49SMatthias Ringwald                 stream_last_packet_sequence[i] = group_last_packet_sequence;
243*24b69d49SMatthias Ringwald                 continue;
244*24b69d49SMatthias Ringwald             }
245*24b69d49SMatthias Ringwald 
246*24b69d49SMatthias Ringwald             // missing packet if big sequence counter is higher than bis sequence counter
247*24b69d49SMatthias Ringwald             if (btstack_time16_delta(group_last_packet_sequence, stream_last_packet_sequence[i]) > 0) {
248*24b69d49SMatthias Ringwald                 printf_plc("- ISO #%u, PLC for %u\n", i, group_last_packet_sequence);
249*24b69d49SMatthias Ringwald                 plc_do(i);
250*24b69d49SMatthias Ringwald                 btstack_assert((stream_last_packet_sequence[i] + 1) == group_last_packet_sequence);
251*24b69d49SMatthias Ringwald                 stream_last_packet_sequence[i] = group_last_packet_sequence;
252*24b69d49SMatthias Ringwald             }
253*24b69d49SMatthias Ringwald         }
254*24b69d49SMatthias Ringwald         group_last_packet_sequence++;
255*24b69d49SMatthias Ringwald     }
256*24b69d49SMatthias Ringwald }
257*24b69d49SMatthias Ringwald 
258*24b69d49SMatthias Ringwald static void plc_timeout(btstack_timer_source_t * timer) {
259*24b69d49SMatthias Ringwald     // Restart timer. This will loose sync with ISO interval, but if we stop caring if we loose that many packets
260*24b69d49SMatthias Ringwald     uint32_t frame_duration_ms = le_audio_demo_sink_frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8 : 10;
261*24b69d49SMatthias Ringwald     btstack_run_loop_set_timer(timer, frame_duration_ms);
262*24b69d49SMatthias Ringwald     btstack_run_loop_set_timer_handler(timer, plc_timeout);
263*24b69d49SMatthias Ringwald     btstack_run_loop_add_timer(timer);
264*24b69d49SMatthias Ringwald 
265*24b69d49SMatthias Ringwald     // assume no packet received in iso interval
266*24b69d49SMatthias Ringwald     plc_check(group_last_packet_sequence + 1);
267*24b69d49SMatthias Ringwald }
268*24b69d49SMatthias Ringwald 
269*24b69d49SMatthias Ringwald void le_audio_demo_util_sink_init(const char * filename_wav){
270*24b69d49SMatthias Ringwald     le_audio_demo_sink_filename_wav = filename_wav;
271*24b69d49SMatthias Ringwald }
272*24b69d49SMatthias Ringwald 
273*24b69d49SMatthias Ringwald void le_audio_demo_util_sink_enable_lc3plus(bool enable){
274*24b69d49SMatthias Ringwald     le_audio_demo_lc3plus_decoder_requested = enable;
275*24b69d49SMatthias Ringwald }
276*24b69d49SMatthias Ringwald 
277*24b69d49SMatthias Ringwald void le_audio_demo_util_sink_configure_general(uint8_t num_streams, uint8_t num_channels_per_stream,
278*24b69d49SMatthias Ringwald                                                uint32_t sampling_frequency_hz,
279*24b69d49SMatthias Ringwald                                                btstack_lc3_frame_duration_t frame_duration, uint16_t octets_per_frame,
280*24b69d49SMatthias Ringwald                                                uint32_t iso_interval_1250us) {
281*24b69d49SMatthias Ringwald     le_audio_demo_sink_sampling_frequency_hz = sampling_frequency_hz;
282*24b69d49SMatthias Ringwald     le_audio_demo_sink_frame_duration = frame_duration;
283*24b69d49SMatthias Ringwald     le_audio_demo_sink_octets_per_frame = octets_per_frame;
284*24b69d49SMatthias Ringwald     le_audio_demo_sink_iso_interval_1250us = iso_interval_1250us;
285*24b69d49SMatthias Ringwald     le_audio_demo_sink_num_streams = num_streams;
286*24b69d49SMatthias Ringwald     le_audio_demo_sink_num_channels_per_stream = num_channels_per_stream;
287*24b69d49SMatthias Ringwald 
288*24b69d49SMatthias Ringwald     le_audio_demo_sink_num_channels = le_audio_demo_sink_num_streams * le_audio_demo_sink_num_channels_per_stream;
289*24b69d49SMatthias Ringwald     btstack_assert((le_audio_demo_sink_num_channels == 1) || (le_audio_demo_sink_num_channels == 2));
290*24b69d49SMatthias Ringwald 
291*24b69d49SMatthias Ringwald     le_audio_demo_sink_lc3_frames = 0;
292*24b69d49SMatthias Ringwald 
293*24b69d49SMatthias Ringwald     le_audio_demo_sink_num_samples_per_frame = btstack_lc3_samples_per_frame(le_audio_demo_sink_sampling_frequency_hz, le_audio_demo_sink_frame_duration);
294*24b69d49SMatthias Ringwald 
295*24b69d49SMatthias Ringwald     // switch to lc3plus if requested and possible
296*24b69d49SMatthias Ringwald     bool use_lc3plus_decoder = le_audio_demo_lc3plus_decoder_requested && (frame_duration == BTSTACK_LC3_FRAME_DURATION_10000US);
297*24b69d49SMatthias Ringwald 
298*24b69d49SMatthias Ringwald     // init decoder
299*24b69d49SMatthias Ringwald     setup_lc3_decoder();
300*24b69d49SMatthias Ringwald 
301*24b69d49SMatthias Ringwald     printf("Configure: %u streams, %u channels per stream, sampling rate %u, samples per frame %u, lc3plus %u\n",
302*24b69d49SMatthias Ringwald            num_streams, num_channels_per_stream, sampling_frequency_hz, le_audio_demo_sink_num_samples_per_frame, use_lc3plus_decoder);
303*24b69d49SMatthias Ringwald 
304*24b69d49SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
305*24b69d49SMatthias Ringwald     // create wav file
306*24b69d49SMatthias Ringwald     printf("WAV file: %s\n", le_audio_demo_sink_filename_wav);
307*24b69d49SMatthias Ringwald     wav_writer_open(le_audio_demo_sink_filename_wav, le_audio_demo_sink_num_channels, le_audio_demo_sink_sampling_frequency_hz);
308*24b69d49SMatthias Ringwald #endif
309*24b69d49SMatthias Ringwald 
310*24b69d49SMatthias Ringwald     // init playback buffer
311*24b69d49SMatthias Ringwald     btstack_ring_buffer_init(&playback_buffer, playback_buffer_storage, PLAYBACK_BUFFER_SIZE);
312*24b69d49SMatthias Ringwald 
313*24b69d49SMatthias Ringwald     // calc start threshold in bytes for PLAYBACK_START_MS
314*24b69d49SMatthias Ringwald     playback_start_threshold_bytes = (sampling_frequency_hz / 1000 * PLAYBACK_START_MS) * le_audio_demo_sink_num_channels * 2;
315*24b69d49SMatthias Ringwald 
316*24b69d49SMatthias Ringwald     // start playback
317*24b69d49SMatthias Ringwald     const btstack_audio_sink_t * sink = btstack_audio_sink_get_instance();
318*24b69d49SMatthias Ringwald     if (sink != NULL){
319*24b69d49SMatthias Ringwald         sink->init(le_audio_demo_sink_num_channels, le_audio_demo_sink_sampling_frequency_hz, le_audio_connection_sink_playback);
320*24b69d49SMatthias Ringwald         sink->start_stream();
321*24b69d49SMatthias Ringwald     }
322*24b69d49SMatthias Ringwald }
323*24b69d49SMatthias Ringwald 
324*24b69d49SMatthias Ringwald void le_audio_demo_util_sink_configure_unicast(uint8_t num_streams, uint8_t num_channels_per_stream, uint32_t sampling_frequency_hz,
325*24b69d49SMatthias Ringwald                                                btstack_lc3_frame_duration_t frame_duration, uint16_t octets_per_frame,
326*24b69d49SMatthias Ringwald                                                uint32_t iso_interval_1250us, uint8_t flush_timeout){
327*24b69d49SMatthias Ringwald     le_audio_demo_sink_type = HCI_ISO_TYPE_CIS;
328*24b69d49SMatthias Ringwald     le_audio_demo_sink_flush_timeout = flush_timeout;
329*24b69d49SMatthias Ringwald     le_audio_demo_util_sink_configure_general(num_streams, num_channels_per_stream, sampling_frequency_hz,
330*24b69d49SMatthias Ringwald                                               frame_duration, octets_per_frame, iso_interval_1250us);
331*24b69d49SMatthias Ringwald }
332*24b69d49SMatthias Ringwald 
333*24b69d49SMatthias Ringwald void le_audio_demo_util_sink_configure_broadcast(uint8_t num_streams, uint8_t num_channels_per_stream, uint32_t sampling_frequency_hz,
334*24b69d49SMatthias Ringwald                                                btstack_lc3_frame_duration_t frame_duration, uint16_t octets_per_frame,
335*24b69d49SMatthias Ringwald                                                uint32_t iso_interval_1250us, uint8_t pre_transmission_offset) {
336*24b69d49SMatthias Ringwald     le_audio_demo_sink_type = HCI_ISO_TYPE_BIS;
337*24b69d49SMatthias Ringwald     le_audio_demo_sink_pre_transmission_offset = pre_transmission_offset;
338*24b69d49SMatthias Ringwald     le_audio_demo_util_sink_configure_unicast(num_streams, num_channels_per_stream, sampling_frequency_hz, frame_duration,
339*24b69d49SMatthias Ringwald                                               octets_per_frame, iso_interval_1250us, pre_transmission_offset);
340*24b69d49SMatthias Ringwald }
341*24b69d49SMatthias Ringwald 
342*24b69d49SMatthias Ringwald void le_audio_demo_util_sink_receive(uint8_t stream_index, uint8_t *packet, uint16_t size) {
343*24b69d49SMatthias Ringwald     uint16_t header = little_endian_read_16(packet, 0);
344*24b69d49SMatthias Ringwald     hci_con_handle_t con_handle = header & 0x0fff;
345*24b69d49SMatthias Ringwald     uint8_t pb_flag = (header >> 12) & 3;
346*24b69d49SMatthias Ringwald     uint8_t ts_flag = (header >> 14) & 1;
347*24b69d49SMatthias Ringwald     uint16_t iso_load_len = little_endian_read_16(packet, 2);
348*24b69d49SMatthias Ringwald 
349*24b69d49SMatthias Ringwald     uint16_t offset = 4;
350*24b69d49SMatthias Ringwald     uint32_t time_stamp = 0;
351*24b69d49SMatthias Ringwald     if (ts_flag){
352*24b69d49SMatthias Ringwald         uint32_t time_stamp = little_endian_read_32(packet, offset);
353*24b69d49SMatthias Ringwald         offset += 4;
354*24b69d49SMatthias Ringwald     }
355*24b69d49SMatthias Ringwald 
356*24b69d49SMatthias Ringwald     uint32_t receive_time_ms = btstack_run_loop_get_time_ms();
357*24b69d49SMatthias Ringwald 
358*24b69d49SMatthias Ringwald     uint16_t packet_sequence_number = little_endian_read_16(packet, offset);
359*24b69d49SMatthias Ringwald     offset += 2;
360*24b69d49SMatthias Ringwald 
361*24b69d49SMatthias Ringwald     uint16_t header_2 = little_endian_read_16(packet, offset);
362*24b69d49SMatthias Ringwald     uint16_t iso_sdu_length = header_2 & 0x3fff;
363*24b69d49SMatthias Ringwald     uint8_t packet_status_flag = (uint8_t) (header_2 >> 14);
364*24b69d49SMatthias Ringwald     offset += 2;
365*24b69d49SMatthias Ringwald 
366*24b69d49SMatthias Ringwald     if (iso_sdu_length == 0) return;
367*24b69d49SMatthias Ringwald 
368*24b69d49SMatthias Ringwald     if (iso_sdu_length != le_audio_demo_sink_num_channels_per_stream * le_audio_demo_sink_octets_per_frame) {
369*24b69d49SMatthias Ringwald         printf("ISO Length %u != %u * %u\n", iso_sdu_length, le_audio_demo_sink_num_channels_per_stream, le_audio_demo_sink_octets_per_frame);
370*24b69d49SMatthias Ringwald         return;
371*24b69d49SMatthias Ringwald     }
372*24b69d49SMatthias Ringwald 
373*24b69d49SMatthias Ringwald     // start with first packet on first stream
374*24b69d49SMatthias Ringwald     if (group_last_packet_received == false){
375*24b69d49SMatthias Ringwald         if (stream_index != 0){
376*24b69d49SMatthias Ringwald             printf("Ignore first packet for second stream\n");
377*24b69d49SMatthias Ringwald             return;
378*24b69d49SMatthias Ringwald         }
379*24b69d49SMatthias Ringwald         group_last_packet_received = true;
380*24b69d49SMatthias Ringwald         group_last_packet_sequence = packet_sequence_number;
381*24b69d49SMatthias Ringwald     }
382*24b69d49SMatthias Ringwald 
383*24b69d49SMatthias Ringwald     if (stream_last_packet_received[stream_index]) {
384*24b69d49SMatthias Ringwald         printf_plc("ISO #%u, receive %u\n", stream_index, packet_sequence_number);
385*24b69d49SMatthias Ringwald 
386*24b69d49SMatthias Ringwald         int16_t packet_sequence_delta = btstack_time16_delta(packet_sequence_number,
387*24b69d49SMatthias Ringwald                                                              stream_last_packet_sequence[stream_index]);
388*24b69d49SMatthias Ringwald         if (packet_sequence_delta < 1) {
389*24b69d49SMatthias Ringwald             // drop delayed packet that had already been generated by PLC
390*24b69d49SMatthias Ringwald             printf_plc("- dropping delayed packet. Current sequence number %u, last received or generated by PLC: %u\n",
391*24b69d49SMatthias Ringwald                        packet_sequence_number, stream_last_packet_sequence[stream_index]);
392*24b69d49SMatthias Ringwald             return;
393*24b69d49SMatthias Ringwald         }
394*24b69d49SMatthias Ringwald         // simple check
395*24b69d49SMatthias Ringwald         if (packet_sequence_number != stream_last_packet_sequence[stream_index] + 1) {
396*24b69d49SMatthias Ringwald             printf_plc("- ISO #%u, missing %u\n", stream_index, stream_last_packet_sequence[stream_index] + 1);
397*24b69d49SMatthias Ringwald         }
398*24b69d49SMatthias Ringwald     } else {
399*24b69d49SMatthias Ringwald         printf_plc("ISO %u, first packet seq number %u\n", stream_index, packet_sequence_number);
400*24b69d49SMatthias Ringwald         stream_last_packet_received[stream_index] = true;
401*24b69d49SMatthias Ringwald     }
402*24b69d49SMatthias Ringwald 
403*24b69d49SMatthias Ringwald     plc_check(packet_sequence_number);
404*24b69d49SMatthias Ringwald 
405*24b69d49SMatthias Ringwald     uint8_t i;
406*24b69d49SMatthias Ringwald     for (i = 0 ; i < le_audio_demo_sink_num_channels_per_stream ; i++){
407*24b69d49SMatthias Ringwald         // decode codec frame
408*24b69d49SMatthias Ringwald         uint8_t tmp_BEC_detect;
409*24b69d49SMatthias Ringwald         uint8_t BFI = 0;
410*24b69d49SMatthias Ringwald         uint8_t effective_channel = stream_index + i;
411*24b69d49SMatthias Ringwald         (void) lc3_decoder->decode_signed_16(decoder_contexts[effective_channel], &packet[offset], BFI,
412*24b69d49SMatthias Ringwald                                              &pcm[effective_channel], le_audio_demo_sink_num_channels,
413*24b69d49SMatthias Ringwald                                              &tmp_BEC_detect);
414*24b69d49SMatthias Ringwald         offset += le_audio_demo_sink_octets_per_frame;
415*24b69d49SMatthias Ringwald         have_pcm[stream_index + i] = true;
416*24b69d49SMatthias Ringwald     }
417*24b69d49SMatthias Ringwald 
418*24b69d49SMatthias Ringwald     store_samples_in_ringbuffer();
419*24b69d49SMatthias Ringwald 
420*24b69d49SMatthias Ringwald     log_info("Samples in playback buffer %5u", btstack_ring_buffer_bytes_available(&playback_buffer) / (le_audio_demo_sink_num_channels * 2));
421*24b69d49SMatthias Ringwald 
422*24b69d49SMatthias Ringwald     le_audio_demo_sink_lc3_frames++;
423*24b69d49SMatthias Ringwald 
424*24b69d49SMatthias Ringwald     // PLC
425*24b69d49SMatthias Ringwald     uint32_t frame_duration_ms = le_audio_demo_sink_frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US ? 8 : 10;
426*24b69d49SMatthias Ringwald     uint32_t timeout_ms = frame_duration_ms * 5 / 2;
427*24b69d49SMatthias Ringwald     btstack_run_loop_remove_timer(&next_packet_timer);
428*24b69d49SMatthias Ringwald     btstack_run_loop_set_timer(&next_packet_timer, timeout_ms);
429*24b69d49SMatthias Ringwald     btstack_run_loop_set_timer_handler(&next_packet_timer, plc_timeout);
430*24b69d49SMatthias Ringwald     btstack_run_loop_add_timer(&next_packet_timer);
431*24b69d49SMatthias Ringwald 
432*24b69d49SMatthias Ringwald     if (samples_received >= le_audio_demo_sink_sampling_frequency_hz){
433*24b69d49SMatthias Ringwald         printf("LC3 Frames: %4u - samples received %5u, played %5u, dropped %5u\n", le_audio_demo_sink_lc3_frames, samples_received, samples_played, samples_dropped);
434*24b69d49SMatthias Ringwald         samples_received = 0;
435*24b69d49SMatthias Ringwald         samples_dropped  =  0;
436*24b69d49SMatthias Ringwald         samples_played = 0;
437*24b69d49SMatthias Ringwald     }
438*24b69d49SMatthias Ringwald 
439*24b69d49SMatthias Ringwald     stream_last_packet_sequence[stream_index] = packet_sequence_number;
440*24b69d49SMatthias Ringwald }
441*24b69d49SMatthias Ringwald 
442*24b69d49SMatthias Ringwald /**
443*24b69d49SMatthias Ringwald  * @brief Close sink: close wav file, stop playback
444*24b69d49SMatthias Ringwald  */
445*24b69d49SMatthias Ringwald void le_audio_demo_util_sink_close(void){
446*24b69d49SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
447*24b69d49SMatthias Ringwald     printf("Close WAV file\n");
448*24b69d49SMatthias Ringwald     wav_writer_close();
449*24b69d49SMatthias Ringwald #endif
450*24b69d49SMatthias Ringwald     // stop playback
451*24b69d49SMatthias Ringwald     const btstack_audio_sink_t * sink = btstack_audio_sink_get_instance();
452*24b69d49SMatthias Ringwald     if (sink != NULL){
453*24b69d49SMatthias Ringwald         sink->stop_stream();
454*24b69d49SMatthias Ringwald     }
455*24b69d49SMatthias Ringwald     // stop timer
456*24b69d49SMatthias Ringwald     btstack_run_loop_remove_timer(&next_packet_timer);
457*24b69d49SMatthias Ringwald }