xref: /btstack/example/sco_demo_util.c (revision 1bbecc2b4973bbb4d11761d0d68c397fe5d59946)
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 
75d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
762c7ae6e1SMatthias Ringwald // length and name of wav file on disk
77c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
788b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
79d4f907a6SMatthias Ringwald #endif
80c4e666bcSMatthias Ringwald 
81c4e666bcSMatthias Ringwald // name of sbc test files
82d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME       "sco_output.msbc"
832308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME        "sco_input.msbc"
84220eb563SMilanka Ringwald 
85c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
86c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS    50
87c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS    50
888b29cfc6SMatthias Ringwald 
89c4e666bcSMatthias Ringwald // constants
90c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
91c4e666bcSMatthias Ringwald #define CVSD_BYTES_PER_FRAME    (2*NUM_CHANNELS)
92c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE        8000
93c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE        16000
94c4e666bcSMatthias Ringwald #define MSBC_BYTES_PER_FRAME    (2*NUM_CHANNELS)
95f7c85330SMatthias Ringwald 
962b89dbfcSMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE || SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
97f7c85330SMatthias Ringwald #define USE_PORTAUDIO
98c4e666bcSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME)
99c4e666bcSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME)
100f7c85330SMatthias Ringwald #endif
101f7c85330SMatthias Ringwald 
102f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
1032b89dbfcSMatthias Ringwald 
1042b89dbfcSMatthias Ringwald // bidirectional audio stream
1052b89dbfcSMatthias Ringwald static PaStream *            pa_stream;
1062b89dbfcSMatthias Ringwald 
1072b89dbfcSMatthias Ringwald // output
108463c9c89SMatthias Ringwald static int                   pa_output_started = 0;
109463c9c89SMatthias Ringwald static int                   pa_output_paused = 0;
110463c9c89SMatthias Ringwald static uint8_t               pa_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
111463c9c89SMatthias Ringwald static btstack_ring_buffer_t pa_output_ring_buffer;
1122b89dbfcSMatthias Ringwald 
1132b89dbfcSMatthias Ringwald // input
1142b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
1152b89dbfcSMatthias Ringwald #define USE_PORTAUDIO_INPUT
1162b89dbfcSMatthias Ringwald static int                   pa_input_started = 0;
1172b89dbfcSMatthias Ringwald static int                   pa_input_paused = 0;
1182b89dbfcSMatthias Ringwald static uint8_t               pa_input_ring_buffer_storage[2*8000];  // full second input buffer
1192b89dbfcSMatthias Ringwald static btstack_ring_buffer_t pa_input_ring_buffer;
1202b89dbfcSMatthias Ringwald static int                   pa_input_counter;
1212b89dbfcSMatthias Ringwald #endif
1222b89dbfcSMatthias Ringwald 
123f7c85330SMatthias Ringwald #endif
124f7c85330SMatthias Ringwald 
125fcb08cdbSMilanka Ringwald static int dump_data = 1;
126fcb08cdbSMilanka Ringwald static int count_sent = 0;
127fcb08cdbSMilanka Ringwald static int count_received = 0;
128c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
129c4e666bcSMatthias Ringwald 
130*1bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
1312b89dbfcSMatthias Ringwald btstack_sbc_decoder_state_t decoder_state;
132*1bbecc2bSMatthias Ringwald #endif
133*1bbecc2bSMatthias Ringwald 
1342b89dbfcSMatthias Ringwald btstack_cvsd_plc_state_t cvsd_plc_state;
135fcb08cdbSMilanka Ringwald 
136*1bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
137d5e5f834SMatthias Ringwald FILE * msbc_file_in;
138d5e5f834SMatthias Ringwald FILE * msbc_file_out;
139*1bbecc2bSMatthias Ringwald #endif
1407294d009SMatthias Ringwald 
1412b89dbfcSMatthias Ringwald int num_samples_to_write;
1422b89dbfcSMatthias Ringwald int num_audio_frames;
1432b89dbfcSMatthias Ringwald int phase;
1442b89dbfcSMatthias Ringwald 
145f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
146d6a06398SMatthias Ringwald 
14735fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz
148c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
14935fd3fb9SMatthias Ringwald      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
15035fd3fb9SMatthias Ringwald  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
15135fd3fb9SMatthias Ringwald  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
15235fd3fb9SMatthias Ringwald  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
15335fd3fb9SMatthias Ringwald  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
15435fd3fb9SMatthias Ringwald      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
15535fd3fb9SMatthias Ringwald -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
15635fd3fb9SMatthias Ringwald -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
15735fd3fb9SMatthias Ringwald -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
15835fd3fb9SMatthias Ringwald -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
15935fd3fb9SMatthias Ringwald };
16035fd3fb9SMatthias Ringwald 
16159c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
16259c97ae1SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(int num_samples, int16_t * data){
16359c97ae1SMatthias Ringwald     int i;
16459c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
16559c97ae1SMatthias Ringwald         int16_t sample = sine_int16_at_16000hz[phase];
16659c97ae1SMatthias Ringwald         little_endian_store_16((uint8_t *) data, i * 2, sample);
16759c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
16859c97ae1SMatthias Ringwald         phase += 2;
169c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
17035fd3fb9SMatthias Ringwald             phase = 0;
17135fd3fb9SMatthias Ringwald         }
17235fd3fb9SMatthias Ringwald     }
17335fd3fb9SMatthias Ringwald }
17435fd3fb9SMatthias Ringwald 
175*1bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
176*1bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
177*1bbecc2bSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(int num_samples, int16_t * data){
178*1bbecc2bSMatthias Ringwald     int i;
179*1bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
180*1bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
181*1bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
182*1bbecc2bSMatthias Ringwald             phase = 0;
183*1bbecc2bSMatthias Ringwald         }
184*1bbecc2bSMatthias Ringwald     }
185*1bbecc2bSMatthias Ringwald }
186*1bbecc2bSMatthias Ringwald 
187b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){
18835fd3fb9SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
18935fd3fb9SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
19035fd3fb9SMatthias Ringwald     int16_t sample_buffer[num_samples];
19159c97ae1SMatthias Ringwald     sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer);
19235fd3fb9SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
19335fd3fb9SMatthias Ringwald     num_audio_frames++;
19435fd3fb9SMatthias Ringwald }
1952b89dbfcSMatthias Ringwald #endif
196*1bbecc2bSMatthias Ringwald #endif
197dbb41bfeSMilanka Ringwald 
198dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
199c4e666bcSMatthias Ringwald static int portaudio_callback( const void *inputBuffer, void *outputBuffer,
200dbb41bfeSMilanka Ringwald                            unsigned long framesPerBuffer,
201dbb41bfeSMilanka Ringwald                            const PaStreamCallbackTimeInfo* timeInfo,
202dbb41bfeSMilanka Ringwald                            PaStreamCallbackFlags statusFlags,
203dbb41bfeSMilanka Ringwald                            void *userData ) {
204dbb41bfeSMilanka Ringwald     (void) timeInfo; /* Prevent unused variable warnings. */
205dbb41bfeSMilanka Ringwald     (void) statusFlags;
206dbb41bfeSMilanka Ringwald     (void) inputBuffer;
2073963d036SMatthias Ringwald     (void) userData;
208dbb41bfeSMilanka Ringwald 
2092b89dbfcSMatthias Ringwald // output part
2102b89dbfcSMatthias Ringwald 
211c4e666bcSMatthias Ringwald     // config based on codec
212c4e666bcSMatthias Ringwald     int bytes_to_copy;
213c4e666bcSMatthias Ringwald     int prebuffer_bytes;
214c4e666bcSMatthias Ringwald     switch (negotiated_codec){
215c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
216c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * MSBC_BYTES_PER_FRAME;
217c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
218c4e666bcSMatthias Ringwald             break;
219c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
220c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * CVSD_BYTES_PER_FRAME;
221c4e666bcSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
222c4e666bcSMatthias Ringwald             break;
223c4e666bcSMatthias Ringwald         default:
224c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * 2;  // assume 1 channel / 16 bit audio samples
225c4e666bcSMatthias Ringwald             prebuffer_bytes = 0xfffffff;
226c4e666bcSMatthias Ringwald             break;
227dbb41bfeSMilanka Ringwald     }
228dbb41bfeSMilanka Ringwald 
229c4e666bcSMatthias Ringwald     // fill with silence while paused
230463c9c89SMatthias Ringwald     if (pa_output_paused){
231463c9c89SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){
232c4e666bcSMatthias Ringwald             memset(outputBuffer, 0, bytes_to_copy);
233c4e666bcSMatthias Ringwald             return 0;
234dbb41bfeSMilanka Ringwald         } else {
235c4e666bcSMatthias Ringwald             // resume playback
236463c9c89SMatthias Ringwald             pa_output_paused = 0;
237dbb41bfeSMilanka Ringwald         }
238c4e666bcSMatthias Ringwald     }
239c4e666bcSMatthias Ringwald 
240c4e666bcSMatthias Ringwald     // get data from ringbuffer
241c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
242463c9c89SMatthias Ringwald     btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read);
243c4e666bcSMatthias Ringwald     bytes_to_copy -= bytes_read;
244c4e666bcSMatthias Ringwald 
245c4e666bcSMatthias Ringwald     // fill with 0 if not enough
246c4e666bcSMatthias Ringwald     if (bytes_to_copy){
247c4e666bcSMatthias Ringwald         memset(outputBuffer + bytes_read, 0, bytes_to_copy);
248463c9c89SMatthias Ringwald         pa_output_paused = 1;
249c4e666bcSMatthias Ringwald     }
2502b89dbfcSMatthias Ringwald // end of output part
2518b29cfc6SMatthias Ringwald 
2522b89dbfcSMatthias Ringwald // input part -- just store in ring buffer
2532b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
2542b89dbfcSMatthias Ringwald     btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2);
2552b89dbfcSMatthias Ringwald     pa_input_counter += framesPerBuffer * 2;
2562b89dbfcSMatthias Ringwald #endif
2572b89dbfcSMatthias Ringwald 
2582b89dbfcSMatthias Ringwald     return 0;
259c4e666bcSMatthias Ringwald }
260c4e666bcSMatthias Ringwald 
261c4e666bcSMatthias Ringwald // return 1 if ok
262c4e666bcSMatthias Ringwald static int portaudio_initialize(int sample_rate){
263c4e666bcSMatthias Ringwald     PaError err;
264c4e666bcSMatthias Ringwald 
265c4e666bcSMatthias Ringwald     /* -- initialize PortAudio -- */
266c4e666bcSMatthias Ringwald     printf("PortAudio: Initialize\n");
267c4e666bcSMatthias Ringwald     err = Pa_Initialize();
268c4e666bcSMatthias Ringwald     if( err != paNoError ) return 0;
2692b89dbfcSMatthias Ringwald 
270c4e666bcSMatthias Ringwald     /* -- setup input and output -- */
2712b89dbfcSMatthias Ringwald     const PaDeviceInfo *deviceInfo;
2722b89dbfcSMatthias Ringwald     PaStreamParameters * inputParameters = NULL;
2732b89dbfcSMatthias Ringwald     PaStreamParameters outputParameters;
274c4e666bcSMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
275c4e666bcSMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
276c4e666bcSMatthias Ringwald     outputParameters.sampleFormat = paInt16;
277c4e666bcSMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
278c4e666bcSMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
2792b89dbfcSMatthias Ringwald     deviceInfo = Pa_GetDeviceInfo( outputParameters.device );
2802b89dbfcSMatthias Ringwald     log_info("PortAudio: Output device: %s", deviceInfo->name);
2812b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
2822b89dbfcSMatthias Ringwald     PaStreamParameters theInputParameters;
2832b89dbfcSMatthias Ringwald     theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
2842b89dbfcSMatthias Ringwald     theInputParameters.channelCount = NUM_CHANNELS;
2852b89dbfcSMatthias Ringwald     theInputParameters.sampleFormat = paInt16;
2862b89dbfcSMatthias Ringwald     theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighOutputLatency;
2872b89dbfcSMatthias Ringwald     theInputParameters.hostApiSpecificStreamInfo = NULL;
2882b89dbfcSMatthias Ringwald     inputParameters = &theInputParameters;
2892b89dbfcSMatthias Ringwald     deviceInfo = Pa_GetDeviceInfo( inputParameters->device );
2902b89dbfcSMatthias Ringwald     log_info("PortAudio: Input device: %s", deviceInfo->name);
2912b89dbfcSMatthias Ringwald #endif
2922b89dbfcSMatthias Ringwald 
2932b89dbfcSMatthias Ringwald     /* -- setup output stream -- */
294c4e666bcSMatthias Ringwald     printf("PortAudio: Open stream\n");
295c4e666bcSMatthias Ringwald     err = Pa_OpenStream(
2962b89dbfcSMatthias Ringwald            &pa_stream,
2972b89dbfcSMatthias Ringwald            inputParameters,
298c4e666bcSMatthias Ringwald            &outputParameters,
299c4e666bcSMatthias Ringwald            sample_rate,
300c4e666bcSMatthias Ringwald            0,
301c4e666bcSMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
302c4e666bcSMatthias Ringwald            portaudio_callback,
303c4e666bcSMatthias Ringwald            NULL );
304c4e666bcSMatthias Ringwald     if (err != paNoError){
305c4e666bcSMatthias Ringwald         printf("Error opening portaudio stream: \"%s\"\n",  Pa_GetErrorText(err));
306c4e666bcSMatthias Ringwald         return 0;
307c4e666bcSMatthias Ringwald     }
308463c9c89SMatthias Ringwald     memset(pa_output_ring_buffer_storage, 0, sizeof(pa_output_ring_buffer_storage));
309463c9c89SMatthias Ringwald     btstack_ring_buffer_init(&pa_output_ring_buffer, pa_output_ring_buffer_storage, sizeof(pa_output_ring_buffer_storage));
3102b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
3112b89dbfcSMatthias Ringwald     memset(pa_input_ring_buffer_storage, 0, sizeof(pa_input_ring_buffer_storage));
3122b89dbfcSMatthias Ringwald     btstack_ring_buffer_init(&pa_input_ring_buffer, pa_input_ring_buffer_storage, sizeof(pa_input_ring_buffer_storage));
3132b89dbfcSMatthias Ringwald     printf("PortAudio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&pa_input_ring_buffer));
3142b89dbfcSMatthias Ringwald #endif
3152b89dbfcSMatthias Ringwald 
3162b89dbfcSMatthias Ringwald     /* -- start stream -- */
3172b89dbfcSMatthias Ringwald     err = Pa_StartStream(pa_stream);
3182b89dbfcSMatthias Ringwald     if (err != paNoError){
3192b89dbfcSMatthias Ringwald         printf("Error starting the stream: \"%s\"\n",  Pa_GetErrorText(err));
3202b89dbfcSMatthias Ringwald         return 0;
3212b89dbfcSMatthias Ringwald     }
3222b89dbfcSMatthias Ringwald     pa_output_started = 1;
3232b89dbfcSMatthias Ringwald     pa_output_paused  = 1;
3242b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
3252b89dbfcSMatthias Ringwald     pa_input_started = 1;
3262b89dbfcSMatthias Ringwald     pa_input_paused  = 1;
3272b89dbfcSMatthias Ringwald #endif
3282b89dbfcSMatthias Ringwald 
329c4e666bcSMatthias Ringwald     return 1;
330c4e666bcSMatthias Ringwald }
3312b89dbfcSMatthias Ringwald 
3322b89dbfcSMatthias Ringwald static void portaudio_terminate(void){
3332b89dbfcSMatthias Ringwald     if (!pa_stream) return;
3342b89dbfcSMatthias Ringwald 
3352b89dbfcSMatthias Ringwald     PaError err;
3362b89dbfcSMatthias Ringwald     printf("PortAudio: Stop Stream\n");
3372b89dbfcSMatthias Ringwald     err = Pa_StopStream(pa_stream);
3382b89dbfcSMatthias Ringwald     if (err != paNoError){
3392b89dbfcSMatthias Ringwald         printf("Error stopping the stream: \"%s\"\n",  Pa_GetErrorText(err));
3402b89dbfcSMatthias Ringwald         return;
3412b89dbfcSMatthias Ringwald     }
3422b89dbfcSMatthias Ringwald     printf("PortAudio: Close Stream\n");
3432b89dbfcSMatthias Ringwald     err = Pa_CloseStream(pa_stream);
3442b89dbfcSMatthias Ringwald     if (err != paNoError){
3452b89dbfcSMatthias Ringwald         printf("Error closing the stream: \"%s\"\n",  Pa_GetErrorText(err));
3462b89dbfcSMatthias Ringwald         return;
3472b89dbfcSMatthias Ringwald     }
3482b89dbfcSMatthias Ringwald     pa_stream = NULL;
3492b89dbfcSMatthias Ringwald     printf("PortAudio: Terminate\n");
3502b89dbfcSMatthias Ringwald     err = Pa_Terminate();
3512b89dbfcSMatthias Ringwald     if (err != paNoError){
3522b89dbfcSMatthias Ringwald         printf("Error terminating portaudio: \"%s\"\n",  Pa_GetErrorText(err));
3532b89dbfcSMatthias Ringwald         return;
3542b89dbfcSMatthias Ringwald     }
3552b89dbfcSMatthias Ringwald }
356c4e666bcSMatthias Ringwald #endif
357c4e666bcSMatthias Ringwald 
3582c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
359c4e666bcSMatthias Ringwald 
360*1bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
361c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
362c4e666bcSMatthias Ringwald     UNUSED(context);
363c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
3642c7ae6e1SMatthias Ringwald     UNUSED(data);
3652c7ae6e1SMatthias Ringwald     UNUSED(num_samples);
3662c7ae6e1SMatthias Ringwald     UNUSED(num_channels);
3672c7ae6e1SMatthias Ringwald 
3682c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
369c4e666bcSMatthias Ringwald 
370c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
371c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
3725303ddeeSMatthias Ringwald     // samples in callback in host endianess, ready for PortAudio playback
373463c9c89SMatthias Ringwald     btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
374*1bbecc2bSMatthias Ringwald #endif /* HAVE_PORTAUDIO */
375dbb41bfeSMilanka Ringwald 
3762c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
377fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
378fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
379fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
380fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
381fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
3822c7ae6e1SMatthias Ringwald         wav_writer_close();
383fcb08cdbSMilanka Ringwald     }
384*1bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3852c7ae6e1SMatthias Ringwald 
386*1bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */
387fcb08cdbSMilanka Ringwald }
388*1bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
389*1bbecc2bSMatthias Ringwald 
390*1bbecc2bSMatthias Ringwald 
391*1bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
392fcb08cdbSMilanka Ringwald 
393fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
394c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
395c4e666bcSMatthias Ringwald 
396fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
397220eb563SMilanka Ringwald     hfp_msbc_init();
3982c7ae6e1SMatthias Ringwald 
3992c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
4002c7ae6e1SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
4012c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
4022c7ae6e1SMatthias Ringwald #endif
4032c7ae6e1SMatthias Ringwald 
4042b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
405b025eb5fSMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
4062b89dbfcSMatthias Ringwald #endif
407973d7173SMatthias Ringwald 
408d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
409d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
410d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
411d5e5f834SMatthias Ringwald #endif
4122b89dbfcSMatthias Ringwald 
4137294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
414d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
415d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
4167294d009SMatthias Ringwald #endif
417dbb41bfeSMilanka Ringwald 
418dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
419c4e666bcSMatthias Ringwald     portaudio_initialize(MSBC_SAMPLE_RATE);
420dbb41bfeSMilanka Ringwald #endif
421fcb08cdbSMilanka Ringwald }
422fcb08cdbSMilanka Ringwald 
423fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
424fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
425d5e5f834SMatthias Ringwald         if (msbc_file_in){
426d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
427d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
428d5e5f834SMatthias Ringwald         }
429fcb08cdbSMilanka Ringwald     }
430dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
431fcb08cdbSMilanka Ringwald }
432*1bbecc2bSMatthias Ringwald #endif
433fcb08cdbSMilanka Ringwald 
434fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
435c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
436c4e666bcSMatthias Ringwald 
437d4f907a6SMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO)
438fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
439d4f907a6SMatthias Ringwald #endif
440c4e666bcSMatthias Ringwald 
4412c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
442c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
4432c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
4442c7ae6e1SMatthias Ringwald #endif
445dbb41bfeSMilanka Ringwald 
446dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
447c4e666bcSMatthias Ringwald     portaudio_initialize(CVSD_SAMPLE_RATE);
448dbb41bfeSMilanka Ringwald #endif
449fbc7c9f2SMilanka Ringwald }
450fbc7c9f2SMilanka Ringwald 
451fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
452dbb41bfeSMilanka Ringwald     if (!num_samples_to_write) return;
4532c7ae6e1SMatthias Ringwald 
4545303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
4551f8694ccSMatthias Ringwald 
4561f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
4571f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
4581f8694ccSMatthias Ringwald         return;
4591f8694ccSMatthias Ringwald     }
4602c7ae6e1SMatthias Ringwald 
461c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
462c4e666bcSMatthias Ringwald     const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME;
4635303ddeeSMatthias Ringwald 
4645303ddeeSMatthias Ringwald     // convert into host endian
4655303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
4665303ddeeSMatthias Ringwald     int i;
4675303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
4685303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
4695303ddeeSMatthias Ringwald     }
4705303ddeeSMatthias Ringwald 
471d4f907a6SMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO)
472e36764ddSMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out);
473d4f907a6SMatthias Ringwald #endif
4745303ddeeSMatthias Ringwald 
4752c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
4762c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
4772c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
4782c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
4792c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
4802c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
4812c7ae6e1SMatthias Ringwald         wav_writer_close();
4822c7ae6e1SMatthias Ringwald     }
4832c7ae6e1SMatthias Ringwald #endif
4842c7ae6e1SMatthias Ringwald 
485dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
486463c9c89SMatthias Ringwald     btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
487dbb41bfeSMilanka Ringwald #endif
488fcb08cdbSMilanka Ringwald }
489fcb08cdbSMilanka Ringwald 
4902c7ae6e1SMatthias Ringwald #endif
4912c7ae6e1SMatthias Ringwald 
4922c7ae6e1SMatthias Ringwald 
493fcb08cdbSMilanka Ringwald void sco_demo_close(void){
494c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
4952b89dbfcSMatthias Ringwald 
49626463303SMilanka Ringwald     printf("SCO demo statistics: ");
497*1bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
49826463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4992c7ae6e1SMatthias Ringwald         printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.\n", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr);
500*1bbecc2bSMatthias Ringwald     } else
501*1bbecc2bSMatthias Ringwald #endif
502*1bbecc2bSMatthias Ringwald     {
5032c7ae6e1SMatthias Ringwald         printf("Used CVSD with PLC, number of proccesed frames: \n - %d good frames, \n - %d bad frames.\n", cvsd_plc_state.good_frames_nr, cvsd_plc_state.bad_frames_nr);
50426463303SMilanka Ringwald     }
50526463303SMilanka Ringwald 
5062c7ae6e1SMatthias Ringwald     negotiated_codec = -1;
5072c7ae6e1SMatthias Ringwald 
5082c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
5092c7ae6e1SMatthias Ringwald 
5102c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
5112c7ae6e1SMatthias Ringwald     wav_writer_close();
5122c7ae6e1SMatthias Ringwald #endif
5132c7ae6e1SMatthias Ringwald 
514dbb41bfeSMilanka Ringwald #ifdef HAVE_PORTAUDIO
5152b89dbfcSMatthias Ringwald     portaudio_terminate();
516dbb41bfeSMilanka Ringwald #endif
517fcb08cdbSMilanka Ringwald 
518fcb08cdbSMilanka Ringwald #endif
519fcb08cdbSMilanka Ringwald }
520fcb08cdbSMilanka Ringwald 
521fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
522fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
523fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
5242c7ae6e1SMatthias Ringwald 
5252b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
526220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
527*1bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
528fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
529*1bbecc2bSMatthias Ringwald #endif
530fcb08cdbSMilanka Ringwald     } else {
531fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
532fcb08cdbSMilanka Ringwald     }
533fcb08cdbSMilanka Ringwald #endif
534fcb08cdbSMilanka Ringwald }
535fcb08cdbSMilanka Ringwald 
536f7c85330SMatthias Ringwald void sco_demo_init(void){
537f7c85330SMatthias Ringwald 	// status
5382b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5392b89dbfcSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via portaudio.\n");
5402b89dbfcSMatthias Ringwald #endif
541f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
542f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
543f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
544f7c85330SMatthias Ringwald #else
545f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
546f7c85330SMatthias Ringwald #endif
547f7c85330SMatthias Ringwald #endif
548f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
549f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
550f7c85330SMatthias Ringwald #endif
551f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
552f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
553f7c85330SMatthias Ringwald #endif
554f7c85330SMatthias Ringwald 
5552b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
556c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
557c4e666bcSMatthias Ringwald #else
558f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
5597294d009SMatthias Ringwald #endif
560f7c85330SMatthias Ringwald 
561f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
562f7c85330SMatthias Ringwald     phase = 'a';
563f7c85330SMatthias Ringwald #endif
564f7c85330SMatthias Ringwald }
565f7c85330SMatthias Ringwald 
5661a919128SMatthias Ringwald void sco_report(void);
5671a919128SMatthias Ringwald void sco_report(void){
5684a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
5694a96141eSMatthias Ringwald }
570f7c85330SMatthias Ringwald 
571f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
572f7c85330SMatthias Ringwald 
573f7c85330SMatthias Ringwald     if (!sco_handle) return;
574f7c85330SMatthias Ringwald 
575c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
576c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
577f7c85330SMatthias Ringwald 
578f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
579f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
580f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
581*1bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
582220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
583c4e666bcSMatthias Ringwald         // overwrite
584c4e666bcSMatthias Ringwald         sco_payload_length = 24;
585c4e666bcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
586c4e666bcSMatthias Ringwald 
587220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
588220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
589220eb563SMilanka Ringwald         }
590220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
591d5e5f834SMatthias Ringwald         if (msbc_file_out){
592d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
593d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
594d76591efSMatthias Ringwald         }
5957294d009SMatthias Ringwald 
596b025eb5fSMatthias Ringwald         sco_demo_msbc_fill_sine_audio_frame();
597*1bbecc2bSMatthias Ringwald     } else
598*1bbecc2bSMatthias Ringwald #endif
599*1bbecc2bSMatthias Ringwald     {
600c4e666bcSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME;
60159c97ae1SMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, (int16_t *) (sco_packet+3));
602220eb563SMilanka Ringwald     }
6031a919128SMatthias Ringwald #endif
6042b89dbfcSMatthias Ringwald 
6052b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
6062b89dbfcSMatthias Ringwald 
6072b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
6082b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
6092b89dbfcSMatthias Ringwald         // MSBC
6102b89dbfcSMatthias Ringwald 
6112b89dbfcSMatthias Ringwald         // overwrite
6122b89dbfcSMatthias Ringwald         sco_payload_length = 24;
6132b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
6142b89dbfcSMatthias Ringwald 
615b025eb5fSMatthias Ringwald         if (pa_input_paused){
616b025eb5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
617b025eb5fSMatthias Ringwald                 // resume sending
618b025eb5fSMatthias Ringwald                 pa_input_paused = 0;
6192b89dbfcSMatthias Ringwald             }
620b025eb5fSMatthias Ringwald         }
621b025eb5fSMatthias Ringwald 
622b025eb5fSMatthias Ringwald         if (!pa_input_paused){
623b025eb5fSMatthias Ringwald             int num_samples = hfp_msbc_num_audio_samples_per_frame();
624b025eb5fSMatthias Ringwald             if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){
625b025eb5fSMatthias Ringwald                 int16_t sample_buffer[num_samples];
626b025eb5fSMatthias Ringwald                 uint32_t bytes_read;
627b025eb5fSMatthias Ringwald                 btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read);
628b025eb5fSMatthias Ringwald                 hfp_msbc_encode_audio_frame(sample_buffer);
629b025eb5fSMatthias Ringwald                 num_audio_frames++;
630b025eb5fSMatthias Ringwald             }
631b025eb5fSMatthias Ringwald         }
632b025eb5fSMatthias Ringwald 
633b025eb5fSMatthias Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
634b025eb5fSMatthias Ringwald             log_error("mSBC stream should not be empty.");
635b025eb5fSMatthias Ringwald             memset(sco_packet + 3, 0, sco_payload_length);
636b025eb5fSMatthias Ringwald             pa_input_paused = 1;
637b025eb5fSMatthias Ringwald         } else {
6382b89dbfcSMatthias Ringwald             hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
6392b89dbfcSMatthias Ringwald             if (msbc_file_out){
6402b89dbfcSMatthias Ringwald                 // log outgoing mSBC data for testing
6412b89dbfcSMatthias Ringwald                 fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
6422b89dbfcSMatthias Ringwald             }
643b025eb5fSMatthias Ringwald         }
6442b89dbfcSMatthias Ringwald 
6452b89dbfcSMatthias Ringwald     } else {
6462b89dbfcSMatthias Ringwald         // CVSD
6472b89dbfcSMatthias Ringwald 
6482b89dbfcSMatthias 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);
6492b89dbfcSMatthias Ringwald         // fill with silence while paused
6502b89dbfcSMatthias Ringwald         int bytes_to_copy = sco_payload_length;
6512b89dbfcSMatthias Ringwald         if (pa_input_paused){
6522b89dbfcSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
6532b89dbfcSMatthias Ringwald                 // resume sending
6542b89dbfcSMatthias Ringwald                 pa_input_paused = 0;
6552b89dbfcSMatthias Ringwald             }
6562b89dbfcSMatthias Ringwald         }
6572b89dbfcSMatthias Ringwald 
6582b89dbfcSMatthias Ringwald         // get data from ringbuffer
6592b89dbfcSMatthias Ringwald         uint16_t pos = 0;
6608fd6902dSMatthias Ringwald         uint8_t * sample_data = &sco_packet[3];
6612b89dbfcSMatthias Ringwald         if (!pa_input_paused){
6622b89dbfcSMatthias Ringwald             uint32_t bytes_read = 0;
6638fd6902dSMatthias Ringwald             btstack_ring_buffer_read(&pa_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
6648fd6902dSMatthias Ringwald             // flip 16 on big endian systems
6658fd6902dSMatthias Ringwald             // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
6668fd6902dSMatthias Ringwald             if (btstack_is_big_endian()){
6678fd6902dSMatthias Ringwald                 int i;
6688fd6902dSMatthias Ringwald                 for (i=0;i<bytes_read;i+=2){
6698fd6902dSMatthias Ringwald                     uint8_t tmp        = sample_data[i*2];
6708fd6902dSMatthias Ringwald                     sample_data[i*2]   = sample_data[i*2+1];
6718fd6902dSMatthias Ringwald                     sample_data[i*2+1] = tmp;
6728fd6902dSMatthias Ringwald                 }
6738fd6902dSMatthias Ringwald             }
6742b89dbfcSMatthias Ringwald             bytes_to_copy -= bytes_read;
6752b89dbfcSMatthias Ringwald             pos           += bytes_read;
6762b89dbfcSMatthias Ringwald         }
6772b89dbfcSMatthias Ringwald 
6782b89dbfcSMatthias Ringwald         // fill with 0 if not enough
6792b89dbfcSMatthias Ringwald         if (bytes_to_copy){
6808fd6902dSMatthias Ringwald             memset(sample_data + pos, 0, bytes_to_copy);
6812b89dbfcSMatthias Ringwald             pa_input_paused = 1;
6822b89dbfcSMatthias Ringwald         }
6832b89dbfcSMatthias Ringwald     }
6842b89dbfcSMatthias Ringwald #else
6852b89dbfcSMatthias Ringwald     // just send '0's
6862b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
6872b89dbfcSMatthias Ringwald         sco_payload_length = 24;
6882b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
6892b89dbfcSMatthias Ringwald     }
6902b89dbfcSMatthias Ringwald     memset(sco_packet + 3, 0, sco_payload_length);
6912b89dbfcSMatthias Ringwald #endif
6922b89dbfcSMatthias Ringwald #endif
6932b89dbfcSMatthias Ringwald 
694f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
695c4e666bcSMatthias Ringwald     memset(&sco_packet[3], phase++, sco_payload_length);
696f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
6971a919128SMatthias Ringwald #endif
6981a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
69938b2eaafSMatthias Ringwald     int j;
700c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
70138b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
702f7c85330SMatthias Ringwald     }
703f7c85330SMatthias Ringwald #endif
7041a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
7051a919128SMatthias Ringwald     int j;
706c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
7071a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
7081a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
7091a919128SMatthias Ringwald     }
7101a919128SMatthias Ringwald #endif
7111a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
7121a919128SMatthias Ringwald     int j;
713c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
7141a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
7151a919128SMatthias Ringwald     }
7161a919128SMatthias Ringwald     // additional hack
7171a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
7181a919128SMatthias Ringwald     (void) phase;
719f7c85330SMatthias Ringwald #endif
720220eb563SMilanka Ringwald 
7212b89dbfcSMatthias Ringwald     // test silence
7222b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
7232b89dbfcSMatthias Ringwald 
724c4e666bcSMatthias Ringwald     // set handle + flags
725c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
726c4e666bcSMatthias Ringwald     // set len
727c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
728c4e666bcSMatthias Ringwald     // finally send packet
729f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
730f7c85330SMatthias Ringwald 
731f7c85330SMatthias Ringwald     // request another send event
732f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
733f7c85330SMatthias Ringwald 
7344a96141eSMatthias Ringwald     count_sent++;
7351a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
7364a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
7371a919128SMatthias Ringwald #endif
738f7c85330SMatthias Ringwald }
739f7c85330SMatthias Ringwald 
740f7c85330SMatthias Ringwald /**
741f7c85330SMatthias Ringwald  * @brief Process received data
742f7c85330SMatthias Ringwald  */
7431a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
7441a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
7451a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
7461a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
7471a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
7481a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
7491a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
7501a919128SMatthias Ringwald 
751f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
752f7c85330SMatthias Ringwald 
753fcb08cdbSMilanka Ringwald     dump_data = 1;
7548b29cfc6SMatthias Ringwald 
7554a96141eSMatthias Ringwald     count_received++;
7561a919128SMatthias Ringwald     static uint32_t packets = 0;
7571a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
7581a919128SMatthias Ringwald     static uint32_t data_received = 0;
7591a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
7604a96141eSMatthias Ringwald 
7611a919128SMatthias Ringwald     data_received += size - 3;
7621a919128SMatthias Ringwald     packets++;
7631a919128SMatthias Ringwald     if (data_received > 100000){
764d4f907a6SMatthias Ringwald         printf("Summary: data %07u, packets %04u, packet with crc errors %0u, byte errors %04u\n",  (unsigned int) data_received,  (unsigned int) packets, (unsigned int) crc_errors, (unsigned int) byte_errors);
7651a919128SMatthias Ringwald         crc_errors = 0;
7661a919128SMatthias Ringwald         byte_errors = 0;
7671a919128SMatthias Ringwald         data_received = 0;
7681a919128SMatthias Ringwald         packets = 0;
7691a919128SMatthias Ringwald     }
7704a96141eSMatthias Ringwald 
7712b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
772c4e666bcSMatthias Ringwald     switch (negotiated_codec){
773*1bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
774c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
775fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
776c4e666bcSMatthias Ringwald             break;
777*1bbecc2bSMatthias Ringwald #endif
778c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
779fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
780c4e666bcSMatthias Ringwald             break;
781c4e666bcSMatthias Ringwald         default:
782c4e666bcSMatthias Ringwald             break;
7838b29cfc6SMatthias Ringwald     }
784dbb41bfeSMilanka Ringwald     dump_data = 0;
7858b29cfc6SMatthias Ringwald #endif
7868b29cfc6SMatthias Ringwald 
787b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
7881a919128SMatthias Ringwald         crc_errors++;
7891a919128SMatthias Ringwald         // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
7901a919128SMatthias Ringwald         // printf_hexdump(&packet[3], size-3);
791f7c85330SMatthias Ringwald         return;
792f7c85330SMatthias Ringwald     }
7938b29cfc6SMatthias Ringwald     if (dump_data){
794f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
7951a919128SMatthias Ringwald         printf("data: ");
796f7c85330SMatthias Ringwald         int i;
797f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
798f7c85330SMatthias Ringwald             printf("%c", packet[i]);
799f7c85330SMatthias Ringwald         }
800f7c85330SMatthias Ringwald         printf("\n");
8018b29cfc6SMatthias Ringwald         dump_data = 0;
8021a919128SMatthias Ringwald #endif
8031a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
8041a919128SMatthias Ringwald         // colored hexdump with expected
8051a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
8061a919128SMatthias Ringwald         int i;
8071a919128SMatthias Ringwald         printf("data: ");
8081a919128SMatthias Ringwald         for (i=3;i<size;i++){
8091a919128SMatthias Ringwald             if (packet[i] != expected_byte){
8101a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
8111a919128SMatthias Ringwald             } else {
8121a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
8131a919128SMatthias Ringwald             }
8141a919128SMatthias Ringwald             expected_byte = packet[i]+1;
8151a919128SMatthias Ringwald         }
8161a919128SMatthias Ringwald         printf("\n");
8171a919128SMatthias Ringwald #endif
818a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
8191a919128SMatthias Ringwald         int i;
8201a919128SMatthias Ringwald         int contains_error = 0;
8211a919128SMatthias Ringwald         for (i=3;i<size;i++){
8221a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
8231a919128SMatthias Ringwald                 contains_error = 1;
8241a919128SMatthias Ringwald                 byte_errors++;
8251a919128SMatthias Ringwald             }
8261a919128SMatthias Ringwald         }
8271a919128SMatthias Ringwald         if (contains_error){
8281a919128SMatthias Ringwald             printf("data: ");
8291a919128SMatthias Ringwald             for (i=0;i<3;i++){
8301a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
8311a919128SMatthias Ringwald             }
8321a919128SMatthias Ringwald             for (i=3;i<size;i++){
8331a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
8341a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
8351a919128SMatthias Ringwald                 } else {
8361a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
8371a919128SMatthias Ringwald                 }
8381a919128SMatthias Ringwald             }
8391a919128SMatthias Ringwald             printf("\n");
8401a919128SMatthias Ringwald         }
841f7c85330SMatthias Ringwald #endif
8428b29cfc6SMatthias Ringwald     }
843f7c85330SMatthias Ringwald }
844