xref: /btstack/example/sco_demo_util.c (revision 2b89dbfc6bb27df2ec8d6a87caf9eeb8d3765ccd)
1f7c85330SMatthias Ringwald /*
2f7c85330SMatthias Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3f7c85330SMatthias Ringwald  *
4f7c85330SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5f7c85330SMatthias Ringwald  * modification, are permitted provided that the following conditions
6f7c85330SMatthias Ringwald  * are met:
7f7c85330SMatthias Ringwald  *
8f7c85330SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9f7c85330SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10f7c85330SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11f7c85330SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12f7c85330SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13f7c85330SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14f7c85330SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15f7c85330SMatthias Ringwald  *    from this software without specific prior written permission.
16f7c85330SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17f7c85330SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18f7c85330SMatthias Ringwald  *    monetary gain.
19f7c85330SMatthias Ringwald  *
20f7c85330SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21f7c85330SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22f7c85330SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23f7c85330SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24f7c85330SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25f7c85330SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26f7c85330SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27f7c85330SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28f7c85330SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29f7c85330SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30f7c85330SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31f7c85330SMatthias Ringwald  * SUCH DAMAGE.
32f7c85330SMatthias Ringwald  *
33f7c85330SMatthias Ringwald  * Please inquire about commercial licensing options at
34f7c85330SMatthias Ringwald  * [email protected]
35f7c85330SMatthias Ringwald  *
36f7c85330SMatthias Ringwald  */
37f7c85330SMatthias Ringwald 
38f7c85330SMatthias Ringwald /*
39f7c85330SMatthias Ringwald  * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo
40f7c85330SMatthias Ringwald  */
41f7c85330SMatthias Ringwald 
422ec72fbbSMilanka Ringwald #include <stdio.h>
432ec72fbbSMilanka Ringwald 
44f7c85330SMatthias Ringwald #include "sco_demo_util.h"
45fcb08cdbSMilanka Ringwald #include "btstack_debug.h"
4635fd3fb9SMatthias Ringwald #include "classic/btstack_sbc.h"
4735fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h"
4835fd3fb9SMatthias Ringwald #include "classic/hfp_msbc.h"
4935fd3fb9SMatthias Ringwald #include "classic/hfp.h"
50fcb08cdbSMilanka Ringwald 
5135fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
52fbc7c9f2SMilanka Ringwald #include "wav_util.h"
5335fd3fb9SMatthias Ringwald #endif
54fbc7c9f2SMilanka Ringwald 
55c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
56c4e666bcSMatthias Ringwald #include <portaudio.h>
57c4e666bcSMatthias Ringwald #include "btstack_ring_buffer.h"
58c4e666bcSMatthias Ringwald #endif
59c4e666bcSMatthias Ringwald 
60c4e666bcSMatthias Ringwald 
61c4e666bcSMatthias Ringwald // test modes
62f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		 0
63f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII		 1
64f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER	 2
651a919128SMatthias Ringwald #define SCO_DEMO_MODE_55         3
661a919128SMatthias Ringwald #define SCO_DEMO_MODE_00         4
67463c9c89SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 5
68f7c85330SMatthias Ringwald 
69f7c85330SMatthias Ringwald // SCO demo configuration
70fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_SINE
71c4e666bcSMatthias Ringwald 
72c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console
73f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD           100
74f7c85330SMatthias Ringwald 
75c4e666bcSMatthias Ringwald // length and name of wav file on disc
76c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
778b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
78c4e666bcSMatthias Ringwald 
79c4e666bcSMatthias Ringwald // name of sbc test files
80d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME       "sco_output.msbc"
812308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME        "sco_input.msbc"
82220eb563SMilanka Ringwald 
83c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
84c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS    50
85c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS    50
868b29cfc6SMatthias Ringwald 
87c4e666bcSMatthias Ringwald // constants
88c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
89c4e666bcSMatthias Ringwald #define CVSD_BYTES_PER_FRAME    (2*NUM_CHANNELS)
90c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE        8000
91c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE        16000
92c4e666bcSMatthias Ringwald #define MSBC_BYTES_PER_FRAME    (2*NUM_CHANNELS)
93f7c85330SMatthias Ringwald 
94*2b89dbfcSMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE || SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
95f7c85330SMatthias Ringwald #define USE_PORTAUDIO
96c4e666bcSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME)
97c4e666bcSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME)
98f7c85330SMatthias Ringwald #endif
99f7c85330SMatthias Ringwald 
100f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
101*2b89dbfcSMatthias Ringwald 
102*2b89dbfcSMatthias Ringwald // bidirectional audio stream
103*2b89dbfcSMatthias Ringwald static PaStream *            pa_stream;
104*2b89dbfcSMatthias Ringwald 
105*2b89dbfcSMatthias Ringwald // output
106463c9c89SMatthias Ringwald static int                   pa_output_started = 0;
107463c9c89SMatthias Ringwald static int                   pa_output_paused = 0;
108463c9c89SMatthias Ringwald static uint8_t               pa_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
109463c9c89SMatthias Ringwald static btstack_ring_buffer_t pa_output_ring_buffer;
110*2b89dbfcSMatthias Ringwald 
111*2b89dbfcSMatthias Ringwald // input
112*2b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
113*2b89dbfcSMatthias Ringwald #define USE_PORTAUDIO_INPUT
114*2b89dbfcSMatthias Ringwald static int                   pa_input_started = 0;
115*2b89dbfcSMatthias Ringwald static int                   pa_input_paused = 0;
116*2b89dbfcSMatthias Ringwald static uint8_t               pa_input_ring_buffer_storage[2*8000];  // full second input buffer
117*2b89dbfcSMatthias Ringwald static btstack_ring_buffer_t pa_input_ring_buffer;
118*2b89dbfcSMatthias Ringwald static int                   pa_input_counter;
119*2b89dbfcSMatthias Ringwald #endif
120*2b89dbfcSMatthias Ringwald 
121f7c85330SMatthias Ringwald #endif
122f7c85330SMatthias Ringwald 
123fcb08cdbSMilanka Ringwald static int dump_data = 1;
124fcb08cdbSMilanka Ringwald static int count_sent = 0;
125fcb08cdbSMilanka Ringwald static int count_received = 0;
126c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
127c4e666bcSMatthias Ringwald 
128*2b89dbfcSMatthias Ringwald btstack_sbc_decoder_state_t decoder_state;
129*2b89dbfcSMatthias Ringwald btstack_cvsd_plc_state_t cvsd_plc_state;
130fcb08cdbSMilanka Ringwald 
131d5e5f834SMatthias Ringwald FILE * msbc_file_in;
132d5e5f834SMatthias Ringwald FILE * msbc_file_out;
1337294d009SMatthias Ringwald 
134*2b89dbfcSMatthias Ringwald int num_samples_to_write;
135*2b89dbfcSMatthias Ringwald int num_audio_frames;
136*2b89dbfcSMatthias Ringwald int phase;
137*2b89dbfcSMatthias Ringwald 
138f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
139d6a06398SMatthias Ringwald 
14035fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz
141c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
14235fd3fb9SMatthias Ringwald      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
14335fd3fb9SMatthias Ringwald  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
14435fd3fb9SMatthias Ringwald  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
14535fd3fb9SMatthias Ringwald  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
14635fd3fb9SMatthias Ringwald  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
14735fd3fb9SMatthias Ringwald      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
14835fd3fb9SMatthias Ringwald -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
14935fd3fb9SMatthias Ringwald -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
15035fd3fb9SMatthias Ringwald -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
15135fd3fb9SMatthias Ringwald -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
15235fd3fb9SMatthias Ringwald };
15335fd3fb9SMatthias Ringwald 
154c4e666bcSMatthias Ringwald // ony use every second value from 16khz table
155c4e666bcSMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz(int num_samples, int16_t * data){
15635fd3fb9SMatthias Ringwald     int i;
15735fd3fb9SMatthias Ringwald     for (i=0; i < num_samples; i++){
158c4e666bcSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
15935fd3fb9SMatthias Ringwald         phase++;
160c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
16135fd3fb9SMatthias Ringwald             phase = 0;
16235fd3fb9SMatthias Ringwald         }
16335fd3fb9SMatthias Ringwald     }
16435fd3fb9SMatthias Ringwald }
16535fd3fb9SMatthias Ringwald 
16635fd3fb9SMatthias Ringwald static void sco_demo_fill_audio_frame(void){
16735fd3fb9SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
16835fd3fb9SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
16935fd3fb9SMatthias Ringwald     int16_t sample_buffer[num_samples];
170c4e666bcSMatthias Ringwald     sco_demo_sine_wave_int16_at_8000_hz(num_samples, sample_buffer);
17135fd3fb9SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
17235fd3fb9SMatthias Ringwald     num_audio_frames++;
17335fd3fb9SMatthias Ringwald }
174*2b89dbfcSMatthias Ringwald #endif
175dbb41bfeSMilanka Ringwald 
176dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
177c4e666bcSMatthias Ringwald static int portaudio_callback( const void *inputBuffer, void *outputBuffer,
178dbb41bfeSMilanka Ringwald                            unsigned long framesPerBuffer,
179dbb41bfeSMilanka Ringwald                            const PaStreamCallbackTimeInfo* timeInfo,
180dbb41bfeSMilanka Ringwald                            PaStreamCallbackFlags statusFlags,
181dbb41bfeSMilanka Ringwald                            void *userData ) {
182dbb41bfeSMilanka Ringwald     (void) timeInfo; /* Prevent unused variable warnings. */
183dbb41bfeSMilanka Ringwald     (void) statusFlags;
184dbb41bfeSMilanka Ringwald     (void) inputBuffer;
1853963d036SMatthias Ringwald     (void) userData;
186dbb41bfeSMilanka Ringwald 
187*2b89dbfcSMatthias Ringwald // output part
188*2b89dbfcSMatthias Ringwald 
189c4e666bcSMatthias Ringwald     // config based on codec
190c4e666bcSMatthias Ringwald     int bytes_to_copy;
191c4e666bcSMatthias Ringwald     int prebuffer_bytes;
192c4e666bcSMatthias Ringwald     switch (negotiated_codec){
193c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
194c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * MSBC_BYTES_PER_FRAME;
195c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
196c4e666bcSMatthias Ringwald             break;
197c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
198c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * CVSD_BYTES_PER_FRAME;
199c4e666bcSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
200c4e666bcSMatthias Ringwald             break;
201c4e666bcSMatthias Ringwald         default:
202c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * 2;  // assume 1 channel / 16 bit audio samples
203c4e666bcSMatthias Ringwald             prebuffer_bytes = 0xfffffff;
204c4e666bcSMatthias Ringwald             break;
205dbb41bfeSMilanka Ringwald     }
206dbb41bfeSMilanka Ringwald 
207c4e666bcSMatthias Ringwald     // fill with silence while paused
208463c9c89SMatthias Ringwald     if (pa_output_paused){
209463c9c89SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){
210c4e666bcSMatthias Ringwald             memset(outputBuffer, 0, bytes_to_copy);
211c4e666bcSMatthias Ringwald             return 0;
212dbb41bfeSMilanka Ringwald         } else {
213c4e666bcSMatthias Ringwald             // resume playback
214463c9c89SMatthias Ringwald             pa_output_paused = 0;
215dbb41bfeSMilanka Ringwald         }
216c4e666bcSMatthias Ringwald     }
217c4e666bcSMatthias Ringwald 
218c4e666bcSMatthias Ringwald     // get data from ringbuffer
219c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
220463c9c89SMatthias Ringwald     btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read);
221c4e666bcSMatthias Ringwald     bytes_to_copy -= bytes_read;
222c4e666bcSMatthias Ringwald 
223c4e666bcSMatthias Ringwald     // fill with 0 if not enough
224c4e666bcSMatthias Ringwald     if (bytes_to_copy){
225c4e666bcSMatthias Ringwald         memset(outputBuffer + bytes_read, 0, bytes_to_copy);
226463c9c89SMatthias Ringwald         pa_output_paused = 1;
227c4e666bcSMatthias Ringwald     }
228*2b89dbfcSMatthias Ringwald // end of output part
2298b29cfc6SMatthias Ringwald 
230*2b89dbfcSMatthias Ringwald // input part -- just store in ring buffer
231*2b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
232*2b89dbfcSMatthias Ringwald     btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2);
233*2b89dbfcSMatthias Ringwald     pa_input_counter += framesPerBuffer * 2;
234*2b89dbfcSMatthias Ringwald #endif
235*2b89dbfcSMatthias Ringwald 
236*2b89dbfcSMatthias Ringwald     return 0;
237c4e666bcSMatthias Ringwald }
238c4e666bcSMatthias Ringwald 
239c4e666bcSMatthias Ringwald // return 1 if ok
240c4e666bcSMatthias Ringwald static int portaudio_initialize(int sample_rate){
241c4e666bcSMatthias Ringwald     PaError err;
242c4e666bcSMatthias Ringwald 
243c4e666bcSMatthias Ringwald     /* -- initialize PortAudio -- */
244c4e666bcSMatthias Ringwald     printf("PortAudio: Initialize\n");
245c4e666bcSMatthias Ringwald     err = Pa_Initialize();
246c4e666bcSMatthias Ringwald     if( err != paNoError ) return 0;
247*2b89dbfcSMatthias Ringwald 
248c4e666bcSMatthias Ringwald     /* -- setup input and output -- */
249*2b89dbfcSMatthias Ringwald     const PaDeviceInfo *deviceInfo;
250*2b89dbfcSMatthias Ringwald     PaStreamParameters * inputParameters = NULL;
251*2b89dbfcSMatthias Ringwald     PaStreamParameters outputParameters;
252c4e666bcSMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
253c4e666bcSMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
254c4e666bcSMatthias Ringwald     outputParameters.sampleFormat = paInt16;
255c4e666bcSMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
256c4e666bcSMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
257*2b89dbfcSMatthias Ringwald     deviceInfo = Pa_GetDeviceInfo( outputParameters.device );
258*2b89dbfcSMatthias Ringwald     log_info("PortAudio: Output device: %s", deviceInfo->name);
259*2b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
260*2b89dbfcSMatthias Ringwald     PaStreamParameters theInputParameters;
261*2b89dbfcSMatthias Ringwald     theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
262*2b89dbfcSMatthias Ringwald     theInputParameters.channelCount = NUM_CHANNELS;
263*2b89dbfcSMatthias Ringwald     theInputParameters.sampleFormat = paInt16;
264*2b89dbfcSMatthias Ringwald     theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighOutputLatency;
265*2b89dbfcSMatthias Ringwald     theInputParameters.hostApiSpecificStreamInfo = NULL;
266*2b89dbfcSMatthias Ringwald     inputParameters = &theInputParameters;
267*2b89dbfcSMatthias Ringwald     deviceInfo = Pa_GetDeviceInfo( inputParameters->device );
268*2b89dbfcSMatthias Ringwald     log_info("PortAudio: Input device: %s", deviceInfo->name);
269*2b89dbfcSMatthias Ringwald #endif
270*2b89dbfcSMatthias Ringwald 
271*2b89dbfcSMatthias Ringwald     /* -- setup output stream -- */
272c4e666bcSMatthias Ringwald     printf("PortAudio: Open stream\n");
273c4e666bcSMatthias Ringwald     err = Pa_OpenStream(
274*2b89dbfcSMatthias Ringwald            &pa_stream,
275*2b89dbfcSMatthias Ringwald            inputParameters,
276c4e666bcSMatthias Ringwald            &outputParameters,
277c4e666bcSMatthias Ringwald            sample_rate,
278c4e666bcSMatthias Ringwald            0,
279c4e666bcSMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
280c4e666bcSMatthias Ringwald            portaudio_callback,
281c4e666bcSMatthias Ringwald            NULL );
282c4e666bcSMatthias Ringwald     if (err != paNoError){
283c4e666bcSMatthias Ringwald         printf("Error opening portaudio stream: \"%s\"\n",  Pa_GetErrorText(err));
284c4e666bcSMatthias Ringwald         return 0;
285c4e666bcSMatthias Ringwald     }
286463c9c89SMatthias Ringwald     memset(pa_output_ring_buffer_storage, 0, sizeof(pa_output_ring_buffer_storage));
287463c9c89SMatthias Ringwald     btstack_ring_buffer_init(&pa_output_ring_buffer, pa_output_ring_buffer_storage, sizeof(pa_output_ring_buffer_storage));
288*2b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
289*2b89dbfcSMatthias Ringwald     memset(pa_input_ring_buffer_storage, 0, sizeof(pa_input_ring_buffer_storage));
290*2b89dbfcSMatthias Ringwald     btstack_ring_buffer_init(&pa_input_ring_buffer, pa_input_ring_buffer_storage, sizeof(pa_input_ring_buffer_storage));
291*2b89dbfcSMatthias Ringwald     printf("PortAudio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&pa_input_ring_buffer));
292*2b89dbfcSMatthias Ringwald #endif
293*2b89dbfcSMatthias Ringwald 
294*2b89dbfcSMatthias Ringwald     /* -- start stream -- */
295*2b89dbfcSMatthias Ringwald     err = Pa_StartStream(pa_stream);
296*2b89dbfcSMatthias Ringwald     if (err != paNoError){
297*2b89dbfcSMatthias Ringwald         printf("Error starting the stream: \"%s\"\n",  Pa_GetErrorText(err));
298*2b89dbfcSMatthias Ringwald         return 0;
299*2b89dbfcSMatthias Ringwald     }
300*2b89dbfcSMatthias Ringwald     pa_output_started = 1;
301*2b89dbfcSMatthias Ringwald     pa_output_paused  = 1;
302*2b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
303*2b89dbfcSMatthias Ringwald     pa_input_started = 1;
304*2b89dbfcSMatthias Ringwald     pa_input_paused  = 1;
305*2b89dbfcSMatthias Ringwald #endif
306*2b89dbfcSMatthias Ringwald 
307c4e666bcSMatthias Ringwald     return 1;
308c4e666bcSMatthias Ringwald }
309*2b89dbfcSMatthias Ringwald 
310*2b89dbfcSMatthias Ringwald static void portaudio_terminate(void){
311*2b89dbfcSMatthias Ringwald     if (!pa_stream) return;
312*2b89dbfcSMatthias Ringwald 
313*2b89dbfcSMatthias Ringwald     PaError err;
314*2b89dbfcSMatthias Ringwald     printf("PortAudio: Stop Stream\n");
315*2b89dbfcSMatthias Ringwald     err = Pa_StopStream(pa_stream);
316*2b89dbfcSMatthias Ringwald     if (err != paNoError){
317*2b89dbfcSMatthias Ringwald         printf("Error stopping the stream: \"%s\"\n",  Pa_GetErrorText(err));
318*2b89dbfcSMatthias Ringwald         return;
319*2b89dbfcSMatthias Ringwald     }
320*2b89dbfcSMatthias Ringwald     printf("PortAudio: Close Stream\n");
321*2b89dbfcSMatthias Ringwald     err = Pa_CloseStream(pa_stream);
322*2b89dbfcSMatthias Ringwald     if (err != paNoError){
323*2b89dbfcSMatthias Ringwald         printf("Error closing the stream: \"%s\"\n",  Pa_GetErrorText(err));
324*2b89dbfcSMatthias Ringwald         return;
325*2b89dbfcSMatthias Ringwald     }
326*2b89dbfcSMatthias Ringwald     pa_stream = NULL;
327*2b89dbfcSMatthias Ringwald     printf("PortAudio: Terminate\n");
328*2b89dbfcSMatthias Ringwald     err = Pa_Terminate();
329*2b89dbfcSMatthias Ringwald     if (err != paNoError){
330*2b89dbfcSMatthias Ringwald         printf("Error terminating portaudio: \"%s\"\n",  Pa_GetErrorText(err));
331*2b89dbfcSMatthias Ringwald         return;
332*2b89dbfcSMatthias Ringwald     }
333*2b89dbfcSMatthias Ringwald }
334c4e666bcSMatthias Ringwald #endif
335c4e666bcSMatthias Ringwald 
336c4e666bcSMatthias Ringwald 
337c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
338c4e666bcSMatthias Ringwald     UNUSED(context);
339c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
340c4e666bcSMatthias Ringwald 
341c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
342c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
343463c9c89SMatthias Ringwald     btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
3449ec2630cSMatthias Ringwald #else
3459ec2630cSMatthias Ringwald     UNUSED(num_channels);
346dbb41bfeSMilanka Ringwald #endif
347dbb41bfeSMilanka Ringwald 
348fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
349fcb08cdbSMilanka Ringwald 
350fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
351fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
352fcb08cdbSMilanka Ringwald 
353fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
354fcb08cdbSMilanka Ringwald 
355fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
356fcb08cdbSMilanka Ringwald         sco_demo_close();
357fcb08cdbSMilanka Ringwald     }
358fcb08cdbSMilanka Ringwald }
359fcb08cdbSMilanka Ringwald 
360fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
361c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
362c4e666bcSMatthias Ringwald 
363c4e666bcSMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
364fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
365fcb08cdbSMilanka Ringwald 
366c4e666bcSMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
367220eb563SMilanka Ringwald 
368220eb563SMilanka Ringwald     hfp_msbc_init();
369*2b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
370220eb563SMilanka Ringwald     sco_demo_fill_audio_frame();
371*2b89dbfcSMatthias Ringwald #endif
372973d7173SMatthias Ringwald 
373d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
374d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
375d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
376d5e5f834SMatthias Ringwald #endif
377*2b89dbfcSMatthias Ringwald 
3787294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
379d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
380d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
3817294d009SMatthias Ringwald #endif
382dbb41bfeSMilanka Ringwald 
383dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
384c4e666bcSMatthias Ringwald     portaudio_initialize(MSBC_SAMPLE_RATE);
385dbb41bfeSMilanka Ringwald #endif
386fcb08cdbSMilanka Ringwald }
387fcb08cdbSMilanka Ringwald 
388fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
389fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
390d5e5f834SMatthias Ringwald         if (msbc_file_in){
391d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
392d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
393d5e5f834SMatthias Ringwald         }
394fcb08cdbSMilanka Ringwald     }
395dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
396fcb08cdbSMilanka Ringwald }
397fcb08cdbSMilanka Ringwald 
398fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
399c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
400c4e666bcSMatthias Ringwald 
401c4e666bcSMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
402fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
403c4e666bcSMatthias Ringwald 
404c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
405dbb41bfeSMilanka Ringwald 
406dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
407c4e666bcSMatthias Ringwald     portaudio_initialize(CVSD_SAMPLE_RATE);
408dbb41bfeSMilanka Ringwald #endif
409fbc7c9f2SMilanka Ringwald }
410fbc7c9f2SMilanka Ringwald 
411fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
412dbb41bfeSMilanka Ringwald     if (!num_samples_to_write) return;
413c4e666bcSMatthias Ringwald     int16_t audio_frame_out[255];    //
4141f8694ccSMatthias Ringwald 
4151f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
4161f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
4171f8694ccSMatthias Ringwald         return;
4181f8694ccSMatthias Ringwald     }
419c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
420c4e666bcSMatthias Ringwald     const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME;
421fcb08cdbSMilanka Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
422379d044eSMilanka Ringwald 
423c4e666bcSMatthias Ringwald #if 0
424fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, (int8_t *)(packet+3), num_samples, audio_frame_out);
425c4e666bcSMatthias Ringwald #else
426c4e666bcSMatthias Ringwald     memcpy(audio_frame_out, packet+3, audio_bytes_read);
427c4e666bcSMatthias Ringwald #endif
428379d044eSMilanka Ringwald 
429c4e666bcSMatthias Ringwald     wav_writer_write_int16(samples_to_write, audio_frame_out);
430fcb08cdbSMilanka Ringwald     num_samples_to_write -= samples_to_write;
431fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
432fcb08cdbSMilanka Ringwald         sco_demo_close();
433fcb08cdbSMilanka Ringwald     }
434dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
435463c9c89SMatthias Ringwald     btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
436dbb41bfeSMilanka Ringwald #endif
437fcb08cdbSMilanka Ringwald }
438fcb08cdbSMilanka Ringwald 
439fcb08cdbSMilanka Ringwald void sco_demo_close(void){
440c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
441*2b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
442*2b89dbfcSMatthias Ringwald 
44326463303SMilanka Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
444fbc7c9f2SMilanka Ringwald     wav_writer_close();
445*2b89dbfcSMatthias Ringwald #endif
44626463303SMilanka Ringwald     printf("SCO demo statistics: ");
44726463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
44826463303SMilanka Ringwald         printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr);
44926463303SMilanka Ringwald     } else {
45026463303SMilanka Ringwald         printf("Used CVSD with PLC, number of proccesed frames: \n - %d good frames, \n - %d bad frames.", cvsd_plc_state.good_frames_nr, cvsd_plc_state.bad_frames_nr);
45126463303SMilanka Ringwald     }
45226463303SMilanka Ringwald 
453dbb41bfeSMilanka Ringwald #ifdef HAVE_PORTAUDIO
454*2b89dbfcSMatthias Ringwald     portaudio_terminate();
455dbb41bfeSMilanka Ringwald #endif
456fcb08cdbSMilanka Ringwald 
457c4e666bcSMatthias Ringwald #ifdef SCO_WAV_FILENAME
458613518d1SMilanka Ringwald #if 0
459fcb08cdbSMilanka Ringwald     printf("SCO Demo: closing wav file\n");
460220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4616e046a36SMatthias Ringwald         wav_writer_state_t * writer_state = &wav_writer_state;
462fcb08cdbSMilanka Ringwald         if (!writer_state->wav_file) return;
463fcb08cdbSMilanka Ringwald         rewind(writer_state->wav_file);
4642afeea7fSMilanka Ringwald         write_wav_header(writer_state->wav_file, writer_state->total_num_samples, btstack_sbc_decoder_num_channels(&decoder_state), btstack_sbc_decoder_sample_rate(&decoder_state),2);
465fcb08cdbSMilanka Ringwald         fclose(writer_state->wav_file);
466fcb08cdbSMilanka Ringwald         writer_state->wav_file = NULL;
467fcb08cdbSMilanka Ringwald     }
468613518d1SMilanka Ringwald #endif
469fcb08cdbSMilanka Ringwald #endif
470c4e666bcSMatthias Ringwald 
471c4e666bcSMatthias Ringwald     negotiated_codec = -1;
472c4e666bcSMatthias Ringwald 
473fcb08cdbSMilanka Ringwald #endif
474fcb08cdbSMilanka Ringwald }
475fcb08cdbSMilanka Ringwald 
476fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
477fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
478fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
479*2b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
48017cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
481220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
482fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
483fcb08cdbSMilanka Ringwald     } else {
484fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
485fcb08cdbSMilanka Ringwald     }
486fcb08cdbSMilanka Ringwald #endif
487fcb08cdbSMilanka Ringwald #endif
488fcb08cdbSMilanka Ringwald }
489fcb08cdbSMilanka Ringwald 
490f7c85330SMatthias Ringwald void sco_demo_init(void){
491f7c85330SMatthias Ringwald 	// status
492*2b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
493*2b89dbfcSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via portaudio.\n");
494*2b89dbfcSMatthias Ringwald #endif
495f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
496f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
497f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
498f7c85330SMatthias Ringwald #else
499f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
500f7c85330SMatthias Ringwald #endif
501f7c85330SMatthias Ringwald #endif
502f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
503f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
504f7c85330SMatthias Ringwald #endif
505f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
506f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
507f7c85330SMatthias Ringwald #endif
508f7c85330SMatthias Ringwald 
509*2b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
510c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
511c4e666bcSMatthias Ringwald #else
512f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
5137294d009SMatthias Ringwald #endif
514f7c85330SMatthias Ringwald 
515f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
516f7c85330SMatthias Ringwald     phase = 'a';
517f7c85330SMatthias Ringwald #endif
518f7c85330SMatthias Ringwald }
519f7c85330SMatthias Ringwald 
5201a919128SMatthias Ringwald void sco_report(void);
5211a919128SMatthias Ringwald void sco_report(void){
5224a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
5234a96141eSMatthias Ringwald }
524f7c85330SMatthias Ringwald 
525f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
526f7c85330SMatthias Ringwald 
527f7c85330SMatthias Ringwald     if (!sco_handle) return;
528f7c85330SMatthias Ringwald 
529c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
530c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
531f7c85330SMatthias Ringwald 
532f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
533f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
534f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
535220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
536c4e666bcSMatthias Ringwald         // overwrite
537c4e666bcSMatthias Ringwald         sco_payload_length = 24;
538c4e666bcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
539c4e666bcSMatthias Ringwald 
540220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
541220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
542220eb563SMilanka Ringwald         }
543220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
544d5e5f834SMatthias Ringwald         if (msbc_file_out){
545d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
546d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
547d76591efSMatthias Ringwald         }
5487294d009SMatthias Ringwald 
549220eb563SMilanka Ringwald         sco_demo_fill_audio_frame();
550220eb563SMilanka Ringwald     } else {
551c4e666bcSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME;
552c4e666bcSMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz(audio_samples_per_packet, (int16_t *) (sco_packet+3));
553220eb563SMilanka Ringwald     }
5541a919128SMatthias Ringwald #endif
555*2b89dbfcSMatthias Ringwald 
556*2b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
557*2b89dbfcSMatthias Ringwald 
558*2b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
559*2b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
560*2b89dbfcSMatthias Ringwald #if 1
561*2b89dbfcSMatthias Ringwald         log_error("Microphone not supported with mSBC yet");
562*2b89dbfcSMatthias Ringwald #else
563*2b89dbfcSMatthias Ringwald         // MSBC
564*2b89dbfcSMatthias Ringwald 
565*2b89dbfcSMatthias Ringwald         // overwrite
566*2b89dbfcSMatthias Ringwald         sco_payload_length = 24;
567*2b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
568*2b89dbfcSMatthias Ringwald 
569*2b89dbfcSMatthias Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
570*2b89dbfcSMatthias Ringwald             log_error("mSBC stream is empty.");
571*2b89dbfcSMatthias Ringwald         }
572*2b89dbfcSMatthias Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
573*2b89dbfcSMatthias Ringwald         if (msbc_file_out){
574*2b89dbfcSMatthias Ringwald             // log outgoing mSBC data for testing
575*2b89dbfcSMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
576*2b89dbfcSMatthias Ringwald         }
577*2b89dbfcSMatthias Ringwald 
578*2b89dbfcSMatthias Ringwald         // TODO:
579*2b89dbfcSMatthias Ringwald         sco_demo_fill_audio_frame();
580*2b89dbfcSMatthias Ringwald #endif
581*2b89dbfcSMatthias Ringwald     } else {
582*2b89dbfcSMatthias Ringwald         // CVSD
583*2b89dbfcSMatthias Ringwald 
584*2b89dbfcSMatthias Ringwald         log_info("send: bytes avail %u, free %u, counter %u", btstack_ring_buffer_bytes_available(&pa_input_ring_buffer), btstack_ring_buffer_bytes_free(&pa_input_ring_buffer), pa_input_counter);
585*2b89dbfcSMatthias Ringwald         // fill with silence while paused
586*2b89dbfcSMatthias Ringwald         int bytes_to_copy = sco_payload_length;
587*2b89dbfcSMatthias Ringwald         if (pa_input_paused){
588*2b89dbfcSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
589*2b89dbfcSMatthias Ringwald                 // resume sending
590*2b89dbfcSMatthias Ringwald                 pa_input_paused = 0;
591*2b89dbfcSMatthias Ringwald             }
592*2b89dbfcSMatthias Ringwald         }
593*2b89dbfcSMatthias Ringwald 
594*2b89dbfcSMatthias Ringwald         // get data from ringbuffer
595*2b89dbfcSMatthias Ringwald         uint16_t pos = 0;
596*2b89dbfcSMatthias Ringwald         if (!pa_input_paused){
597*2b89dbfcSMatthias Ringwald             uint32_t bytes_read = 0;
598*2b89dbfcSMatthias Ringwald             btstack_ring_buffer_read(&pa_input_ring_buffer, sco_packet + 3, bytes_to_copy, &bytes_read);
599*2b89dbfcSMatthias Ringwald             bytes_to_copy -= bytes_read;
600*2b89dbfcSMatthias Ringwald             pos           += bytes_read;
601*2b89dbfcSMatthias Ringwald         }
602*2b89dbfcSMatthias Ringwald 
603*2b89dbfcSMatthias Ringwald         // fill with 0 if not enough
604*2b89dbfcSMatthias Ringwald         if (bytes_to_copy){
605*2b89dbfcSMatthias Ringwald             memset(sco_packet + 3 + pos, 0, bytes_to_copy);
606*2b89dbfcSMatthias Ringwald             pa_input_paused = 1;
607*2b89dbfcSMatthias Ringwald         }
608*2b89dbfcSMatthias Ringwald     }
609*2b89dbfcSMatthias Ringwald #else
610*2b89dbfcSMatthias Ringwald     // just send '0's
611*2b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
612*2b89dbfcSMatthias Ringwald         sco_payload_length = 24;
613*2b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
614*2b89dbfcSMatthias Ringwald     }
615*2b89dbfcSMatthias Ringwald     memset(sco_packet + 3, 0, sco_payload_length);
616*2b89dbfcSMatthias Ringwald #endif
617*2b89dbfcSMatthias Ringwald #endif
618*2b89dbfcSMatthias Ringwald 
619f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
620c4e666bcSMatthias Ringwald     memset(&sco_packet[3], phase++, sco_payload_length);
621f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
6221a919128SMatthias Ringwald #endif
6231a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
62438b2eaafSMatthias Ringwald     int j;
625c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
62638b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
627f7c85330SMatthias Ringwald     }
628f7c85330SMatthias Ringwald #endif
6291a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
6301a919128SMatthias Ringwald     int j;
631c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6321a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
6331a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
6341a919128SMatthias Ringwald     }
6351a919128SMatthias Ringwald #endif
6361a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
6371a919128SMatthias Ringwald     int j;
638c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6391a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
6401a919128SMatthias Ringwald     }
6411a919128SMatthias Ringwald     // additional hack
6421a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
6431a919128SMatthias Ringwald     (void) phase;
644f7c85330SMatthias Ringwald #endif
645220eb563SMilanka Ringwald 
646*2b89dbfcSMatthias Ringwald     // test silence
647*2b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
648*2b89dbfcSMatthias Ringwald 
649c4e666bcSMatthias Ringwald     // set handle + flags
650c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
651c4e666bcSMatthias Ringwald     // set len
652c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
653c4e666bcSMatthias Ringwald     // finally send packet
654f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
655f7c85330SMatthias Ringwald 
656f7c85330SMatthias Ringwald     // request another send event
657f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
658f7c85330SMatthias Ringwald 
6594a96141eSMatthias Ringwald     count_sent++;
6601a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
6614a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
6621a919128SMatthias Ringwald #endif
663f7c85330SMatthias Ringwald }
664f7c85330SMatthias Ringwald 
665f7c85330SMatthias Ringwald /**
666f7c85330SMatthias Ringwald  * @brief Process received data
667f7c85330SMatthias Ringwald  */
6681a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
6691a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
6701a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
6711a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
6721a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
6731a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
6741a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
6751a919128SMatthias Ringwald 
676f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
677f7c85330SMatthias Ringwald 
678fcb08cdbSMilanka Ringwald     dump_data = 1;
6798b29cfc6SMatthias Ringwald 
6804a96141eSMatthias Ringwald     count_received++;
6811a919128SMatthias Ringwald     static uint32_t packets = 0;
6821a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
6831a919128SMatthias Ringwald     static uint32_t data_received = 0;
6841a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
6854a96141eSMatthias Ringwald 
6861a919128SMatthias Ringwald     data_received += size - 3;
6871a919128SMatthias Ringwald     packets++;
6881a919128SMatthias Ringwald     if (data_received > 100000){
6891a919128SMatthias Ringwald         printf("Summary: data %07u, packets %04u, packet with crc errors %0u, byte errors %04u\n", data_received, packets, crc_errors, byte_errors);
6901a919128SMatthias Ringwald         crc_errors = 0;
6911a919128SMatthias Ringwald         byte_errors = 0;
6921a919128SMatthias Ringwald         data_received = 0;
6931a919128SMatthias Ringwald         packets = 0;
6941a919128SMatthias Ringwald     }
6954a96141eSMatthias Ringwald 
696*2b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
697c4e666bcSMatthias Ringwald     switch (negotiated_codec){
698c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
699fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
700c4e666bcSMatthias Ringwald             break;
701c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
702fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
703c4e666bcSMatthias Ringwald             break;
704c4e666bcSMatthias Ringwald         default:
705c4e666bcSMatthias Ringwald             break;
7068b29cfc6SMatthias Ringwald     }
707dbb41bfeSMilanka Ringwald     dump_data = 0;
7088b29cfc6SMatthias Ringwald #endif
7098b29cfc6SMatthias Ringwald 
710b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
7111a919128SMatthias Ringwald         crc_errors++;
7121a919128SMatthias Ringwald         // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
7131a919128SMatthias Ringwald         // printf_hexdump(&packet[3], size-3);
714f7c85330SMatthias Ringwald         return;
715f7c85330SMatthias Ringwald     }
7168b29cfc6SMatthias Ringwald     if (dump_data){
717f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
7181a919128SMatthias Ringwald         printf("data: ");
719f7c85330SMatthias Ringwald         int i;
720f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
721f7c85330SMatthias Ringwald             printf("%c", packet[i]);
722f7c85330SMatthias Ringwald         }
723f7c85330SMatthias Ringwald         printf("\n");
7248b29cfc6SMatthias Ringwald         dump_data = 0;
7251a919128SMatthias Ringwald #endif
7261a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
7271a919128SMatthias Ringwald         // colored hexdump with expected
7281a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
7291a919128SMatthias Ringwald         int i;
7301a919128SMatthias Ringwald         printf("data: ");
7311a919128SMatthias Ringwald         for (i=3;i<size;i++){
7321a919128SMatthias Ringwald             if (packet[i] != expected_byte){
7331a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7341a919128SMatthias Ringwald             } else {
7351a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7361a919128SMatthias Ringwald             }
7371a919128SMatthias Ringwald             expected_byte = packet[i]+1;
7381a919128SMatthias Ringwald         }
7391a919128SMatthias Ringwald         printf("\n");
7401a919128SMatthias Ringwald #endif
741a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
7421a919128SMatthias Ringwald         int i;
7431a919128SMatthias Ringwald         int contains_error = 0;
7441a919128SMatthias Ringwald         for (i=3;i<size;i++){
7451a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7461a919128SMatthias Ringwald                 contains_error = 1;
7471a919128SMatthias Ringwald                 byte_errors++;
7481a919128SMatthias Ringwald             }
7491a919128SMatthias Ringwald         }
7501a919128SMatthias Ringwald         if (contains_error){
7511a919128SMatthias Ringwald             printf("data: ");
7521a919128SMatthias Ringwald             for (i=0;i<3;i++){
7531a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7541a919128SMatthias Ringwald             }
7551a919128SMatthias Ringwald             for (i=3;i<size;i++){
7561a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7571a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7581a919128SMatthias Ringwald                 } else {
7591a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
7601a919128SMatthias Ringwald                 }
7611a919128SMatthias Ringwald             }
7621a919128SMatthias Ringwald             printf("\n");
7631a919128SMatthias Ringwald         }
764f7c85330SMatthias Ringwald #endif
7658b29cfc6SMatthias Ringwald     }
766f7c85330SMatthias Ringwald }
767