xref: /btstack/example/sco_demo_util.c (revision 8fd6902d670874c6f082a1b1da8ab1cdfdf6b628)
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 
942b89dbfcSMatthias 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
1012b89dbfcSMatthias Ringwald 
1022b89dbfcSMatthias Ringwald // bidirectional audio stream
1032b89dbfcSMatthias Ringwald static PaStream *            pa_stream;
1042b89dbfcSMatthias Ringwald 
1052b89dbfcSMatthias 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;
1102b89dbfcSMatthias Ringwald 
1112b89dbfcSMatthias Ringwald // input
1122b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
1132b89dbfcSMatthias Ringwald #define USE_PORTAUDIO_INPUT
1142b89dbfcSMatthias Ringwald static int                   pa_input_started = 0;
1152b89dbfcSMatthias Ringwald static int                   pa_input_paused = 0;
1162b89dbfcSMatthias Ringwald static uint8_t               pa_input_ring_buffer_storage[2*8000];  // full second input buffer
1172b89dbfcSMatthias Ringwald static btstack_ring_buffer_t pa_input_ring_buffer;
1182b89dbfcSMatthias Ringwald static int                   pa_input_counter;
1192b89dbfcSMatthias Ringwald #endif
1202b89dbfcSMatthias 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 
1282b89dbfcSMatthias Ringwald btstack_sbc_decoder_state_t decoder_state;
1292b89dbfcSMatthias 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 
1342b89dbfcSMatthias Ringwald int num_samples_to_write;
1352b89dbfcSMatthias Ringwald int num_audio_frames;
1362b89dbfcSMatthias Ringwald int phase;
1372b89dbfcSMatthias 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 
15459c97ae1SMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
15559c97ae1SMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(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++];
15959c97ae1SMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
16059c97ae1SMatthias Ringwald             phase = 0;
16159c97ae1SMatthias Ringwald         }
16259c97ae1SMatthias Ringwald     }
16359c97ae1SMatthias Ringwald }
16459c97ae1SMatthias Ringwald 
16559c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
16659c97ae1SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(int num_samples, int16_t * data){
16759c97ae1SMatthias Ringwald     int i;
16859c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
16959c97ae1SMatthias Ringwald         int16_t sample = sine_int16_at_16000hz[phase];
17059c97ae1SMatthias Ringwald         little_endian_store_16((uint8_t *) data, i * 2, sample);
17159c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
17259c97ae1SMatthias Ringwald         phase += 2;
173c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
17435fd3fb9SMatthias Ringwald             phase = 0;
17535fd3fb9SMatthias Ringwald         }
17635fd3fb9SMatthias Ringwald     }
17735fd3fb9SMatthias Ringwald }
17835fd3fb9SMatthias Ringwald 
179b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){
18035fd3fb9SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
18135fd3fb9SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
18235fd3fb9SMatthias Ringwald     int16_t sample_buffer[num_samples];
18359c97ae1SMatthias Ringwald     sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer);
18435fd3fb9SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
18535fd3fb9SMatthias Ringwald     num_audio_frames++;
18635fd3fb9SMatthias Ringwald }
1872b89dbfcSMatthias Ringwald #endif
188dbb41bfeSMilanka Ringwald 
189dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
190c4e666bcSMatthias Ringwald static int portaudio_callback( const void *inputBuffer, void *outputBuffer,
191dbb41bfeSMilanka Ringwald                            unsigned long framesPerBuffer,
192dbb41bfeSMilanka Ringwald                            const PaStreamCallbackTimeInfo* timeInfo,
193dbb41bfeSMilanka Ringwald                            PaStreamCallbackFlags statusFlags,
194dbb41bfeSMilanka Ringwald                            void *userData ) {
195dbb41bfeSMilanka Ringwald     (void) timeInfo; /* Prevent unused variable warnings. */
196dbb41bfeSMilanka Ringwald     (void) statusFlags;
197dbb41bfeSMilanka Ringwald     (void) inputBuffer;
1983963d036SMatthias Ringwald     (void) userData;
199dbb41bfeSMilanka Ringwald 
2002b89dbfcSMatthias Ringwald // output part
2012b89dbfcSMatthias Ringwald 
202c4e666bcSMatthias Ringwald     // config based on codec
203c4e666bcSMatthias Ringwald     int bytes_to_copy;
204c4e666bcSMatthias Ringwald     int prebuffer_bytes;
205c4e666bcSMatthias Ringwald     switch (negotiated_codec){
206c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
207c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * MSBC_BYTES_PER_FRAME;
208c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
209c4e666bcSMatthias Ringwald             break;
210c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
211c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * CVSD_BYTES_PER_FRAME;
212c4e666bcSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
213c4e666bcSMatthias Ringwald             break;
214c4e666bcSMatthias Ringwald         default:
215c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * 2;  // assume 1 channel / 16 bit audio samples
216c4e666bcSMatthias Ringwald             prebuffer_bytes = 0xfffffff;
217c4e666bcSMatthias Ringwald             break;
218dbb41bfeSMilanka Ringwald     }
219dbb41bfeSMilanka Ringwald 
220c4e666bcSMatthias Ringwald     // fill with silence while paused
221463c9c89SMatthias Ringwald     if (pa_output_paused){
222463c9c89SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){
223c4e666bcSMatthias Ringwald             memset(outputBuffer, 0, bytes_to_copy);
224c4e666bcSMatthias Ringwald             return 0;
225dbb41bfeSMilanka Ringwald         } else {
226c4e666bcSMatthias Ringwald             // resume playback
227463c9c89SMatthias Ringwald             pa_output_paused = 0;
228dbb41bfeSMilanka Ringwald         }
229c4e666bcSMatthias Ringwald     }
230c4e666bcSMatthias Ringwald 
231c4e666bcSMatthias Ringwald     // get data from ringbuffer
232c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
233463c9c89SMatthias Ringwald     btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read);
234c4e666bcSMatthias Ringwald     bytes_to_copy -= bytes_read;
235c4e666bcSMatthias Ringwald 
236c4e666bcSMatthias Ringwald     // fill with 0 if not enough
237c4e666bcSMatthias Ringwald     if (bytes_to_copy){
238c4e666bcSMatthias Ringwald         memset(outputBuffer + bytes_read, 0, bytes_to_copy);
239463c9c89SMatthias Ringwald         pa_output_paused = 1;
240c4e666bcSMatthias Ringwald     }
2412b89dbfcSMatthias Ringwald // end of output part
2428b29cfc6SMatthias Ringwald 
2432b89dbfcSMatthias Ringwald // input part -- just store in ring buffer
2442b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
2452b89dbfcSMatthias Ringwald     btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2);
2462b89dbfcSMatthias Ringwald     pa_input_counter += framesPerBuffer * 2;
2472b89dbfcSMatthias Ringwald #endif
2482b89dbfcSMatthias Ringwald 
2492b89dbfcSMatthias Ringwald     return 0;
250c4e666bcSMatthias Ringwald }
251c4e666bcSMatthias Ringwald 
252c4e666bcSMatthias Ringwald // return 1 if ok
253c4e666bcSMatthias Ringwald static int portaudio_initialize(int sample_rate){
254c4e666bcSMatthias Ringwald     PaError err;
255c4e666bcSMatthias Ringwald 
256c4e666bcSMatthias Ringwald     /* -- initialize PortAudio -- */
257c4e666bcSMatthias Ringwald     printf("PortAudio: Initialize\n");
258c4e666bcSMatthias Ringwald     err = Pa_Initialize();
259c4e666bcSMatthias Ringwald     if( err != paNoError ) return 0;
2602b89dbfcSMatthias Ringwald 
261c4e666bcSMatthias Ringwald     /* -- setup input and output -- */
2622b89dbfcSMatthias Ringwald     const PaDeviceInfo *deviceInfo;
2632b89dbfcSMatthias Ringwald     PaStreamParameters * inputParameters = NULL;
2642b89dbfcSMatthias Ringwald     PaStreamParameters outputParameters;
265c4e666bcSMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
266c4e666bcSMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
267c4e666bcSMatthias Ringwald     outputParameters.sampleFormat = paInt16;
268c4e666bcSMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
269c4e666bcSMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
2702b89dbfcSMatthias Ringwald     deviceInfo = Pa_GetDeviceInfo( outputParameters.device );
2712b89dbfcSMatthias Ringwald     log_info("PortAudio: Output device: %s", deviceInfo->name);
2722b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
2732b89dbfcSMatthias Ringwald     PaStreamParameters theInputParameters;
2742b89dbfcSMatthias Ringwald     theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
2752b89dbfcSMatthias Ringwald     theInputParameters.channelCount = NUM_CHANNELS;
2762b89dbfcSMatthias Ringwald     theInputParameters.sampleFormat = paInt16;
2772b89dbfcSMatthias Ringwald     theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighOutputLatency;
2782b89dbfcSMatthias Ringwald     theInputParameters.hostApiSpecificStreamInfo = NULL;
2792b89dbfcSMatthias Ringwald     inputParameters = &theInputParameters;
2802b89dbfcSMatthias Ringwald     deviceInfo = Pa_GetDeviceInfo( inputParameters->device );
2812b89dbfcSMatthias Ringwald     log_info("PortAudio: Input device: %s", deviceInfo->name);
2822b89dbfcSMatthias Ringwald #endif
2832b89dbfcSMatthias Ringwald 
2842b89dbfcSMatthias Ringwald     /* -- setup output stream -- */
285c4e666bcSMatthias Ringwald     printf("PortAudio: Open stream\n");
286c4e666bcSMatthias Ringwald     err = Pa_OpenStream(
2872b89dbfcSMatthias Ringwald            &pa_stream,
2882b89dbfcSMatthias Ringwald            inputParameters,
289c4e666bcSMatthias Ringwald            &outputParameters,
290c4e666bcSMatthias Ringwald            sample_rate,
291c4e666bcSMatthias Ringwald            0,
292c4e666bcSMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
293c4e666bcSMatthias Ringwald            portaudio_callback,
294c4e666bcSMatthias Ringwald            NULL );
295c4e666bcSMatthias Ringwald     if (err != paNoError){
296c4e666bcSMatthias Ringwald         printf("Error opening portaudio stream: \"%s\"\n",  Pa_GetErrorText(err));
297c4e666bcSMatthias Ringwald         return 0;
298c4e666bcSMatthias Ringwald     }
299463c9c89SMatthias Ringwald     memset(pa_output_ring_buffer_storage, 0, sizeof(pa_output_ring_buffer_storage));
300463c9c89SMatthias Ringwald     btstack_ring_buffer_init(&pa_output_ring_buffer, pa_output_ring_buffer_storage, sizeof(pa_output_ring_buffer_storage));
3012b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
3022b89dbfcSMatthias Ringwald     memset(pa_input_ring_buffer_storage, 0, sizeof(pa_input_ring_buffer_storage));
3032b89dbfcSMatthias Ringwald     btstack_ring_buffer_init(&pa_input_ring_buffer, pa_input_ring_buffer_storage, sizeof(pa_input_ring_buffer_storage));
3042b89dbfcSMatthias Ringwald     printf("PortAudio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&pa_input_ring_buffer));
3052b89dbfcSMatthias Ringwald #endif
3062b89dbfcSMatthias Ringwald 
3072b89dbfcSMatthias Ringwald     /* -- start stream -- */
3082b89dbfcSMatthias Ringwald     err = Pa_StartStream(pa_stream);
3092b89dbfcSMatthias Ringwald     if (err != paNoError){
3102b89dbfcSMatthias Ringwald         printf("Error starting the stream: \"%s\"\n",  Pa_GetErrorText(err));
3112b89dbfcSMatthias Ringwald         return 0;
3122b89dbfcSMatthias Ringwald     }
3132b89dbfcSMatthias Ringwald     pa_output_started = 1;
3142b89dbfcSMatthias Ringwald     pa_output_paused  = 1;
3152b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
3162b89dbfcSMatthias Ringwald     pa_input_started = 1;
3172b89dbfcSMatthias Ringwald     pa_input_paused  = 1;
3182b89dbfcSMatthias Ringwald #endif
3192b89dbfcSMatthias Ringwald 
320c4e666bcSMatthias Ringwald     return 1;
321c4e666bcSMatthias Ringwald }
3222b89dbfcSMatthias Ringwald 
3232b89dbfcSMatthias Ringwald static void portaudio_terminate(void){
3242b89dbfcSMatthias Ringwald     if (!pa_stream) return;
3252b89dbfcSMatthias Ringwald 
3262b89dbfcSMatthias Ringwald     PaError err;
3272b89dbfcSMatthias Ringwald     printf("PortAudio: Stop Stream\n");
3282b89dbfcSMatthias Ringwald     err = Pa_StopStream(pa_stream);
3292b89dbfcSMatthias Ringwald     if (err != paNoError){
3302b89dbfcSMatthias Ringwald         printf("Error stopping the stream: \"%s\"\n",  Pa_GetErrorText(err));
3312b89dbfcSMatthias Ringwald         return;
3322b89dbfcSMatthias Ringwald     }
3332b89dbfcSMatthias Ringwald     printf("PortAudio: Close Stream\n");
3342b89dbfcSMatthias Ringwald     err = Pa_CloseStream(pa_stream);
3352b89dbfcSMatthias Ringwald     if (err != paNoError){
3362b89dbfcSMatthias Ringwald         printf("Error closing the stream: \"%s\"\n",  Pa_GetErrorText(err));
3372b89dbfcSMatthias Ringwald         return;
3382b89dbfcSMatthias Ringwald     }
3392b89dbfcSMatthias Ringwald     pa_stream = NULL;
3402b89dbfcSMatthias Ringwald     printf("PortAudio: Terminate\n");
3412b89dbfcSMatthias Ringwald     err = Pa_Terminate();
3422b89dbfcSMatthias Ringwald     if (err != paNoError){
3432b89dbfcSMatthias Ringwald         printf("Error terminating portaudio: \"%s\"\n",  Pa_GetErrorText(err));
3442b89dbfcSMatthias Ringwald         return;
3452b89dbfcSMatthias Ringwald     }
3462b89dbfcSMatthias Ringwald }
347c4e666bcSMatthias Ringwald #endif
348c4e666bcSMatthias Ringwald 
349c4e666bcSMatthias Ringwald 
350c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
351c4e666bcSMatthias Ringwald     UNUSED(context);
352c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
353c4e666bcSMatthias Ringwald 
354c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
355c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
3565303ddeeSMatthias Ringwald     // samples in callback in host endianess, ready for PortAudio playback
357463c9c89SMatthias Ringwald     btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
3589ec2630cSMatthias Ringwald #else
3599ec2630cSMatthias Ringwald     UNUSED(num_channels);
360dbb41bfeSMilanka Ringwald #endif
361dbb41bfeSMilanka Ringwald 
362fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
363fcb08cdbSMilanka Ringwald 
364fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
365fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
366fcb08cdbSMilanka Ringwald 
367fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
368fcb08cdbSMilanka Ringwald 
369fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
370fcb08cdbSMilanka Ringwald         sco_demo_close();
371fcb08cdbSMilanka Ringwald     }
372fcb08cdbSMilanka Ringwald }
373fcb08cdbSMilanka Ringwald 
374fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
375c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
376c4e666bcSMatthias Ringwald 
377c4e666bcSMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
378fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
379fcb08cdbSMilanka Ringwald 
380c4e666bcSMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
381220eb563SMilanka Ringwald 
382220eb563SMilanka Ringwald     hfp_msbc_init();
3832b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
384b025eb5fSMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
3852b89dbfcSMatthias Ringwald #endif
386973d7173SMatthias Ringwald 
387d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
388d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
389d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
390d5e5f834SMatthias Ringwald #endif
3912b89dbfcSMatthias Ringwald 
3927294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
393d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
394d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
3957294d009SMatthias Ringwald #endif
396dbb41bfeSMilanka Ringwald 
397dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
398c4e666bcSMatthias Ringwald     portaudio_initialize(MSBC_SAMPLE_RATE);
399dbb41bfeSMilanka Ringwald #endif
400fcb08cdbSMilanka Ringwald }
401fcb08cdbSMilanka Ringwald 
402fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
403fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
404d5e5f834SMatthias Ringwald         if (msbc_file_in){
405d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
406d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
407d5e5f834SMatthias Ringwald         }
408fcb08cdbSMilanka Ringwald     }
409dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
410fcb08cdbSMilanka Ringwald }
411fcb08cdbSMilanka Ringwald 
412fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
413c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
414c4e666bcSMatthias Ringwald 
415c4e666bcSMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
416fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
417c4e666bcSMatthias Ringwald 
418c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
419dbb41bfeSMilanka Ringwald 
420dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
421c4e666bcSMatthias Ringwald     portaudio_initialize(CVSD_SAMPLE_RATE);
422dbb41bfeSMilanka Ringwald #endif
423fbc7c9f2SMilanka Ringwald }
424fbc7c9f2SMilanka Ringwald 
425fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
426dbb41bfeSMilanka Ringwald     if (!num_samples_to_write) return;
4275303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
4281f8694ccSMatthias Ringwald 
4291f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
4301f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
4311f8694ccSMatthias Ringwald         return;
4321f8694ccSMatthias Ringwald     }
433c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
434c4e666bcSMatthias Ringwald     const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME;
435fcb08cdbSMilanka Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
436379d044eSMilanka Ringwald 
4375303ddeeSMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
4385303ddeeSMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
439fcb08cdbSMilanka Ringwald     num_samples_to_write -= samples_to_write;
440fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
441fcb08cdbSMilanka Ringwald         sco_demo_close();
442fcb08cdbSMilanka Ringwald     }
4435303ddeeSMatthias Ringwald 
4445303ddeeSMatthias Ringwald     // convert into host endian
4455303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
4465303ddeeSMatthias Ringwald     int i;
4475303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
4485303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
4495303ddeeSMatthias Ringwald     }
4505303ddeeSMatthias Ringwald 
4515303ddeeSMatthias Ringwald #if 0
4525303ddeeSMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, (int8_t *) audio_frame_in, num_samples, audio_frame_out);
4535303ddeeSMatthias Ringwald #else
4545303ddeeSMatthias Ringwald     memcpy(audio_frame_out, audio_frame_in, audio_bytes_read);
4555303ddeeSMatthias Ringwald #endif
4565303ddeeSMatthias Ringwald 
457dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
458463c9c89SMatthias Ringwald     btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
459dbb41bfeSMilanka Ringwald #endif
460fcb08cdbSMilanka Ringwald }
461fcb08cdbSMilanka Ringwald 
462fcb08cdbSMilanka Ringwald void sco_demo_close(void){
463c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
4642b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
4652b89dbfcSMatthias Ringwald 
46626463303SMilanka Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
467fbc7c9f2SMilanka Ringwald     wav_writer_close();
4682b89dbfcSMatthias Ringwald #endif
46926463303SMilanka Ringwald     printf("SCO demo statistics: ");
47026463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
47126463303SMilanka 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);
47226463303SMilanka Ringwald     } else {
47326463303SMilanka 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);
47426463303SMilanka Ringwald     }
47526463303SMilanka Ringwald 
476dbb41bfeSMilanka Ringwald #ifdef HAVE_PORTAUDIO
4772b89dbfcSMatthias Ringwald     portaudio_terminate();
478dbb41bfeSMilanka Ringwald #endif
479fcb08cdbSMilanka Ringwald 
480c4e666bcSMatthias Ringwald #ifdef SCO_WAV_FILENAME
481613518d1SMilanka Ringwald #if 0
482fcb08cdbSMilanka Ringwald     printf("SCO Demo: closing wav file\n");
483220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4846e046a36SMatthias Ringwald         wav_writer_state_t * writer_state = &wav_writer_state;
485fcb08cdbSMilanka Ringwald         if (!writer_state->wav_file) return;
486fcb08cdbSMilanka Ringwald         rewind(writer_state->wav_file);
4872afeea7fSMilanka 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);
488fcb08cdbSMilanka Ringwald         fclose(writer_state->wav_file);
489fcb08cdbSMilanka Ringwald         writer_state->wav_file = NULL;
490fcb08cdbSMilanka Ringwald     }
491613518d1SMilanka Ringwald #endif
492fcb08cdbSMilanka Ringwald #endif
493c4e666bcSMatthias Ringwald 
494c4e666bcSMatthias Ringwald     negotiated_codec = -1;
495c4e666bcSMatthias Ringwald 
496fcb08cdbSMilanka Ringwald #endif
497fcb08cdbSMilanka Ringwald }
498fcb08cdbSMilanka Ringwald 
499fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
500fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
501fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
5022b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
50317cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
504220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
505fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
506fcb08cdbSMilanka Ringwald     } else {
507fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
508fcb08cdbSMilanka Ringwald     }
509fcb08cdbSMilanka Ringwald #endif
510fcb08cdbSMilanka Ringwald #endif
511fcb08cdbSMilanka Ringwald }
512fcb08cdbSMilanka Ringwald 
513f7c85330SMatthias Ringwald void sco_demo_init(void){
514f7c85330SMatthias Ringwald 	// status
5152b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5162b89dbfcSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via portaudio.\n");
5172b89dbfcSMatthias Ringwald #endif
518f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
519f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
520f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
521f7c85330SMatthias Ringwald #else
522f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
523f7c85330SMatthias Ringwald #endif
524f7c85330SMatthias Ringwald #endif
525f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
526f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
527f7c85330SMatthias Ringwald #endif
528f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
529f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
530f7c85330SMatthias Ringwald #endif
531f7c85330SMatthias Ringwald 
5322b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
533c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
534c4e666bcSMatthias Ringwald #else
535f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
5367294d009SMatthias Ringwald #endif
537f7c85330SMatthias Ringwald 
538f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
539f7c85330SMatthias Ringwald     phase = 'a';
540f7c85330SMatthias Ringwald #endif
541f7c85330SMatthias Ringwald }
542f7c85330SMatthias Ringwald 
5431a919128SMatthias Ringwald void sco_report(void);
5441a919128SMatthias Ringwald void sco_report(void){
5454a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
5464a96141eSMatthias Ringwald }
547f7c85330SMatthias Ringwald 
548f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
549f7c85330SMatthias Ringwald 
550f7c85330SMatthias Ringwald     if (!sco_handle) return;
551f7c85330SMatthias Ringwald 
552c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
553c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
554f7c85330SMatthias Ringwald 
555f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
556f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
557f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
558220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
559c4e666bcSMatthias Ringwald         // overwrite
560c4e666bcSMatthias Ringwald         sco_payload_length = 24;
561c4e666bcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
562c4e666bcSMatthias Ringwald 
563220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
564220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
565220eb563SMilanka Ringwald         }
566220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
567d5e5f834SMatthias Ringwald         if (msbc_file_out){
568d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
569d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
570d76591efSMatthias Ringwald         }
5717294d009SMatthias Ringwald 
572b025eb5fSMatthias Ringwald         sco_demo_msbc_fill_sine_audio_frame();
573220eb563SMilanka Ringwald     } else {
574c4e666bcSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME;
57559c97ae1SMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, (int16_t *) (sco_packet+3));
576220eb563SMilanka Ringwald     }
5771a919128SMatthias Ringwald #endif
5782b89dbfcSMatthias Ringwald 
5792b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5802b89dbfcSMatthias Ringwald 
5812b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
5822b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
5832b89dbfcSMatthias Ringwald         // MSBC
5842b89dbfcSMatthias Ringwald 
5852b89dbfcSMatthias Ringwald         // overwrite
5862b89dbfcSMatthias Ringwald         sco_payload_length = 24;
5872b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
5882b89dbfcSMatthias Ringwald 
589b025eb5fSMatthias Ringwald         if (pa_input_paused){
590b025eb5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
591b025eb5fSMatthias Ringwald                 // resume sending
592b025eb5fSMatthias Ringwald                 pa_input_paused = 0;
5932b89dbfcSMatthias Ringwald             }
594b025eb5fSMatthias Ringwald         }
595b025eb5fSMatthias Ringwald 
596b025eb5fSMatthias Ringwald         if (!pa_input_paused){
597b025eb5fSMatthias Ringwald             int num_samples = hfp_msbc_num_audio_samples_per_frame();
598b025eb5fSMatthias Ringwald             if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){
599b025eb5fSMatthias Ringwald                 int16_t sample_buffer[num_samples];
600b025eb5fSMatthias Ringwald                 uint32_t bytes_read;
601b025eb5fSMatthias Ringwald                 btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read);
602b025eb5fSMatthias Ringwald                 hfp_msbc_encode_audio_frame(sample_buffer);
603b025eb5fSMatthias Ringwald                 num_audio_frames++;
604b025eb5fSMatthias Ringwald             }
605b025eb5fSMatthias Ringwald         }
606b025eb5fSMatthias Ringwald 
607b025eb5fSMatthias Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
608b025eb5fSMatthias Ringwald             log_error("mSBC stream should not be empty.");
609b025eb5fSMatthias Ringwald             memset(sco_packet + 3, 0, sco_payload_length);
610b025eb5fSMatthias Ringwald             pa_input_paused = 1;
611b025eb5fSMatthias Ringwald         } else {
6122b89dbfcSMatthias Ringwald             hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
6132b89dbfcSMatthias Ringwald             if (msbc_file_out){
6142b89dbfcSMatthias Ringwald                 // log outgoing mSBC data for testing
6152b89dbfcSMatthias Ringwald                 fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
6162b89dbfcSMatthias Ringwald             }
617b025eb5fSMatthias Ringwald         }
6182b89dbfcSMatthias Ringwald 
6192b89dbfcSMatthias Ringwald     } else {
6202b89dbfcSMatthias Ringwald         // CVSD
6212b89dbfcSMatthias Ringwald 
6222b89dbfcSMatthias 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);
6232b89dbfcSMatthias Ringwald         // fill with silence while paused
6242b89dbfcSMatthias Ringwald         int bytes_to_copy = sco_payload_length;
6252b89dbfcSMatthias Ringwald         if (pa_input_paused){
6262b89dbfcSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
6272b89dbfcSMatthias Ringwald                 // resume sending
6282b89dbfcSMatthias Ringwald                 pa_input_paused = 0;
6292b89dbfcSMatthias Ringwald             }
6302b89dbfcSMatthias Ringwald         }
6312b89dbfcSMatthias Ringwald 
6322b89dbfcSMatthias Ringwald         // get data from ringbuffer
6332b89dbfcSMatthias Ringwald         uint16_t pos = 0;
634*8fd6902dSMatthias Ringwald         uint8_t * sample_data = &sco_packet[3];
6352b89dbfcSMatthias Ringwald         if (!pa_input_paused){
6362b89dbfcSMatthias Ringwald             uint32_t bytes_read = 0;
637*8fd6902dSMatthias Ringwald             btstack_ring_buffer_read(&pa_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
638*8fd6902dSMatthias Ringwald             // flip 16 on big endian systems
639*8fd6902dSMatthias Ringwald             // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
640*8fd6902dSMatthias Ringwald             if (btstack_is_big_endian()){
641*8fd6902dSMatthias Ringwald                 int i;
642*8fd6902dSMatthias Ringwald                 for (i=0;i<bytes_read;i+=2){
643*8fd6902dSMatthias Ringwald                     uint8_t tmp        = sample_data[i*2];
644*8fd6902dSMatthias Ringwald                     sample_data[i*2]   = sample_data[i*2+1];
645*8fd6902dSMatthias Ringwald                     sample_data[i*2+1] = tmp;
646*8fd6902dSMatthias Ringwald                 }
647*8fd6902dSMatthias Ringwald             }
6482b89dbfcSMatthias Ringwald             bytes_to_copy -= bytes_read;
6492b89dbfcSMatthias Ringwald             pos           += bytes_read;
6502b89dbfcSMatthias Ringwald         }
6512b89dbfcSMatthias Ringwald 
6522b89dbfcSMatthias Ringwald         // fill with 0 if not enough
6532b89dbfcSMatthias Ringwald         if (bytes_to_copy){
654*8fd6902dSMatthias Ringwald             memset(sample_data + pos, 0, bytes_to_copy);
6552b89dbfcSMatthias Ringwald             pa_input_paused = 1;
6562b89dbfcSMatthias Ringwald         }
6572b89dbfcSMatthias Ringwald     }
6582b89dbfcSMatthias Ringwald #else
6592b89dbfcSMatthias Ringwald     // just send '0's
6602b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
6612b89dbfcSMatthias Ringwald         sco_payload_length = 24;
6622b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
6632b89dbfcSMatthias Ringwald     }
6642b89dbfcSMatthias Ringwald     memset(sco_packet + 3, 0, sco_payload_length);
6652b89dbfcSMatthias Ringwald #endif
6662b89dbfcSMatthias Ringwald #endif
6672b89dbfcSMatthias Ringwald 
668f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
669c4e666bcSMatthias Ringwald     memset(&sco_packet[3], phase++, sco_payload_length);
670f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
6711a919128SMatthias Ringwald #endif
6721a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
67338b2eaafSMatthias Ringwald     int j;
674c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
67538b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
676f7c85330SMatthias Ringwald     }
677f7c85330SMatthias Ringwald #endif
6781a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
6791a919128SMatthias Ringwald     int j;
680c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6811a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
6821a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
6831a919128SMatthias Ringwald     }
6841a919128SMatthias Ringwald #endif
6851a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
6861a919128SMatthias Ringwald     int j;
687c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6881a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
6891a919128SMatthias Ringwald     }
6901a919128SMatthias Ringwald     // additional hack
6911a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
6921a919128SMatthias Ringwald     (void) phase;
693f7c85330SMatthias Ringwald #endif
694220eb563SMilanka Ringwald 
6952b89dbfcSMatthias Ringwald     // test silence
6962b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
6972b89dbfcSMatthias Ringwald 
698c4e666bcSMatthias Ringwald     // set handle + flags
699c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
700c4e666bcSMatthias Ringwald     // set len
701c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
702c4e666bcSMatthias Ringwald     // finally send packet
703f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
704f7c85330SMatthias Ringwald 
705f7c85330SMatthias Ringwald     // request another send event
706f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
707f7c85330SMatthias Ringwald 
7084a96141eSMatthias Ringwald     count_sent++;
7091a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
7104a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
7111a919128SMatthias Ringwald #endif
712f7c85330SMatthias Ringwald }
713f7c85330SMatthias Ringwald 
714f7c85330SMatthias Ringwald /**
715f7c85330SMatthias Ringwald  * @brief Process received data
716f7c85330SMatthias Ringwald  */
7171a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
7181a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
7191a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
7201a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
7211a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
7221a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
7231a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
7241a919128SMatthias Ringwald 
725f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
726f7c85330SMatthias Ringwald 
727fcb08cdbSMilanka Ringwald     dump_data = 1;
7288b29cfc6SMatthias Ringwald 
7294a96141eSMatthias Ringwald     count_received++;
7301a919128SMatthias Ringwald     static uint32_t packets = 0;
7311a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
7321a919128SMatthias Ringwald     static uint32_t data_received = 0;
7331a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
7344a96141eSMatthias Ringwald 
7351a919128SMatthias Ringwald     data_received += size - 3;
7361a919128SMatthias Ringwald     packets++;
7371a919128SMatthias Ringwald     if (data_received > 100000){
7381a919128SMatthias Ringwald         printf("Summary: data %07u, packets %04u, packet with crc errors %0u, byte errors %04u\n", data_received, packets, crc_errors, byte_errors);
7391a919128SMatthias Ringwald         crc_errors = 0;
7401a919128SMatthias Ringwald         byte_errors = 0;
7411a919128SMatthias Ringwald         data_received = 0;
7421a919128SMatthias Ringwald         packets = 0;
7431a919128SMatthias Ringwald     }
7444a96141eSMatthias Ringwald 
7452b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
746c4e666bcSMatthias Ringwald     switch (negotiated_codec){
747c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
748fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
749c4e666bcSMatthias Ringwald             break;
750c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
751fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
752c4e666bcSMatthias Ringwald             break;
753c4e666bcSMatthias Ringwald         default:
754c4e666bcSMatthias Ringwald             break;
7558b29cfc6SMatthias Ringwald     }
756dbb41bfeSMilanka Ringwald     dump_data = 0;
7578b29cfc6SMatthias Ringwald #endif
7588b29cfc6SMatthias Ringwald 
759b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
7601a919128SMatthias Ringwald         crc_errors++;
7611a919128SMatthias Ringwald         // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
7621a919128SMatthias Ringwald         // printf_hexdump(&packet[3], size-3);
763f7c85330SMatthias Ringwald         return;
764f7c85330SMatthias Ringwald     }
7658b29cfc6SMatthias Ringwald     if (dump_data){
766f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
7671a919128SMatthias Ringwald         printf("data: ");
768f7c85330SMatthias Ringwald         int i;
769f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
770f7c85330SMatthias Ringwald             printf("%c", packet[i]);
771f7c85330SMatthias Ringwald         }
772f7c85330SMatthias Ringwald         printf("\n");
7738b29cfc6SMatthias Ringwald         dump_data = 0;
7741a919128SMatthias Ringwald #endif
7751a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
7761a919128SMatthias Ringwald         // colored hexdump with expected
7771a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
7781a919128SMatthias Ringwald         int i;
7791a919128SMatthias Ringwald         printf("data: ");
7801a919128SMatthias Ringwald         for (i=3;i<size;i++){
7811a919128SMatthias Ringwald             if (packet[i] != expected_byte){
7821a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7831a919128SMatthias Ringwald             } else {
7841a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7851a919128SMatthias Ringwald             }
7861a919128SMatthias Ringwald             expected_byte = packet[i]+1;
7871a919128SMatthias Ringwald         }
7881a919128SMatthias Ringwald         printf("\n");
7891a919128SMatthias Ringwald #endif
790a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
7911a919128SMatthias Ringwald         int i;
7921a919128SMatthias Ringwald         int contains_error = 0;
7931a919128SMatthias Ringwald         for (i=3;i<size;i++){
7941a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7951a919128SMatthias Ringwald                 contains_error = 1;
7961a919128SMatthias Ringwald                 byte_errors++;
7971a919128SMatthias Ringwald             }
7981a919128SMatthias Ringwald         }
7991a919128SMatthias Ringwald         if (contains_error){
8001a919128SMatthias Ringwald             printf("data: ");
8011a919128SMatthias Ringwald             for (i=0;i<3;i++){
8021a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
8031a919128SMatthias Ringwald             }
8041a919128SMatthias Ringwald             for (i=3;i<size;i++){
8051a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
8061a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
8071a919128SMatthias Ringwald                 } else {
8081a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
8091a919128SMatthias Ringwald                 }
8101a919128SMatthias Ringwald             }
8111a919128SMatthias Ringwald             printf("\n");
8121a919128SMatthias Ringwald         }
813f7c85330SMatthias Ringwald #endif
8148b29cfc6SMatthias Ringwald     }
815f7c85330SMatthias Ringwald }
816