xref: /btstack/example/sco_demo_util.c (revision 8d3be4021b818c9e251a05f9a935265087471e43)
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  */
37ab2c6ae4SMatthias Ringwald 
38ab2c6ae4SMatthias Ringwald #define __BTSTACK_FILE__ "sco_demo_util.c"
39f7c85330SMatthias Ringwald 
40f7c85330SMatthias Ringwald /*
41f7c85330SMatthias Ringwald  * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo
42f7c85330SMatthias Ringwald  */
43f7c85330SMatthias Ringwald 
442ec72fbbSMilanka Ringwald #include <stdio.h>
452ec72fbbSMilanka Ringwald 
46f7c85330SMatthias Ringwald #include "sco_demo_util.h"
47fcb08cdbSMilanka Ringwald #include "btstack_debug.h"
4835fd3fb9SMatthias Ringwald #include "classic/btstack_sbc.h"
4935fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h"
5035fd3fb9SMatthias Ringwald #include "classic/hfp_msbc.h"
5135fd3fb9SMatthias Ringwald #include "classic/hfp.h"
52fcb08cdbSMilanka Ringwald 
5335fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
54fbc7c9f2SMilanka Ringwald #include "wav_util.h"
5535fd3fb9SMatthias Ringwald #endif
56fbc7c9f2SMilanka Ringwald 
57c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
58c4e666bcSMatthias Ringwald #include <portaudio.h>
59c4e666bcSMatthias Ringwald #include "btstack_ring_buffer.h"
60c4e666bcSMatthias Ringwald #endif
61c4e666bcSMatthias Ringwald 
62c4e666bcSMatthias Ringwald 
63c4e666bcSMatthias Ringwald // test modes
64f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		 0
65f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII		 1
66f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER	 2
671a919128SMatthias Ringwald #define SCO_DEMO_MODE_55         3
681a919128SMatthias Ringwald #define SCO_DEMO_MODE_00         4
69463c9c89SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 5
70f7c85330SMatthias Ringwald 
71f7c85330SMatthias Ringwald // SCO demo configuration
72fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_SINE
73c4e666bcSMatthias Ringwald 
74c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console
75f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD           100
76f7c85330SMatthias Ringwald 
77d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
782c7ae6e1SMatthias Ringwald // length and name of wav file on disk
79c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
808b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
81d4f907a6SMatthias Ringwald #endif
82c4e666bcSMatthias Ringwald 
83c4e666bcSMatthias Ringwald // name of sbc test files
84d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME       "sco_output.msbc"
852308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME        "sco_input.msbc"
86220eb563SMilanka Ringwald 
87c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
88c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS    50
89c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS    50
908b29cfc6SMatthias Ringwald 
91c4e666bcSMatthias Ringwald // constants
92c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
93c4e666bcSMatthias Ringwald #define CVSD_BYTES_PER_FRAME    (2*NUM_CHANNELS)
94c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE        8000
95c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE        16000
96c4e666bcSMatthias Ringwald #define MSBC_BYTES_PER_FRAME    (2*NUM_CHANNELS)
97f7c85330SMatthias Ringwald 
982b89dbfcSMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE || SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
99f7c85330SMatthias Ringwald #define USE_PORTAUDIO
100c4e666bcSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME)
101c4e666bcSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME)
102f7c85330SMatthias Ringwald #endif
103f7c85330SMatthias Ringwald 
104f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
1052b89dbfcSMatthias Ringwald 
1062b89dbfcSMatthias Ringwald // bidirectional audio stream
1072b89dbfcSMatthias Ringwald static PaStream *            pa_stream;
1082b89dbfcSMatthias Ringwald 
1092b89dbfcSMatthias Ringwald // output
110463c9c89SMatthias Ringwald static int                   pa_output_started = 0;
111463c9c89SMatthias Ringwald static int                   pa_output_paused = 0;
112463c9c89SMatthias Ringwald static uint8_t               pa_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
113463c9c89SMatthias Ringwald static btstack_ring_buffer_t pa_output_ring_buffer;
1142b89dbfcSMatthias Ringwald 
1152b89dbfcSMatthias Ringwald // input
1162b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
1172b89dbfcSMatthias Ringwald #define USE_PORTAUDIO_INPUT
1182b89dbfcSMatthias Ringwald static int                   pa_input_started = 0;
1192b89dbfcSMatthias Ringwald static int                   pa_input_paused = 0;
1202b89dbfcSMatthias Ringwald static uint8_t               pa_input_ring_buffer_storage[2*8000];  // full second input buffer
1212b89dbfcSMatthias Ringwald static btstack_ring_buffer_t pa_input_ring_buffer;
1222b89dbfcSMatthias Ringwald static int                   pa_input_counter;
1232b89dbfcSMatthias Ringwald #endif
1242b89dbfcSMatthias Ringwald 
125f7c85330SMatthias Ringwald #endif
126f7c85330SMatthias Ringwald 
127fcb08cdbSMilanka Ringwald static int dump_data = 1;
128fcb08cdbSMilanka Ringwald static int count_sent = 0;
129fcb08cdbSMilanka Ringwald static int count_received = 0;
130c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
131c4e666bcSMatthias Ringwald 
1321bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
1332b89dbfcSMatthias Ringwald btstack_sbc_decoder_state_t decoder_state;
1341bbecc2bSMatthias Ringwald #endif
1351bbecc2bSMatthias Ringwald 
1362b89dbfcSMatthias Ringwald btstack_cvsd_plc_state_t cvsd_plc_state;
137fcb08cdbSMilanka Ringwald 
1381bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
139d5e5f834SMatthias Ringwald FILE * msbc_file_in;
140d5e5f834SMatthias Ringwald FILE * msbc_file_out;
1411bbecc2bSMatthias Ringwald #endif
1427294d009SMatthias Ringwald 
1432b89dbfcSMatthias Ringwald int num_samples_to_write;
1442b89dbfcSMatthias Ringwald int num_audio_frames;
145249d94cfSMatthias Ringwald unsigned int phase;
1462b89dbfcSMatthias Ringwald 
147f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
148d6a06398SMatthias Ringwald 
14935fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz
150c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
15135fd3fb9SMatthias Ringwald      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
15235fd3fb9SMatthias Ringwald  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
15335fd3fb9SMatthias Ringwald  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
15435fd3fb9SMatthias Ringwald  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
15535fd3fb9SMatthias Ringwald  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
15635fd3fb9SMatthias Ringwald      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
15735fd3fb9SMatthias Ringwald -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
15835fd3fb9SMatthias Ringwald -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
15935fd3fb9SMatthias Ringwald -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
16035fd3fb9SMatthias Ringwald -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
16135fd3fb9SMatthias Ringwald };
16235fd3fb9SMatthias Ringwald 
16359c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
164adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){
165249d94cfSMatthias Ringwald     unsigned int i;
16659c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
16759c97ae1SMatthias Ringwald         int16_t sample = sine_int16_at_16000hz[phase];
168adaba9f3SMatthias Ringwald         little_endian_store_16(data, i * 2, sample);
16959c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
17059c97ae1SMatthias Ringwald         phase += 2;
171c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
17235fd3fb9SMatthias Ringwald             phase = 0;
17335fd3fb9SMatthias Ringwald         }
17435fd3fb9SMatthias Ringwald     }
17535fd3fb9SMatthias Ringwald }
17635fd3fb9SMatthias Ringwald 
1771bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
1781bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
179249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){
180249d94cfSMatthias Ringwald     unsigned int i;
1811bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
1821bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
1831bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1841bbecc2bSMatthias Ringwald             phase = 0;
1851bbecc2bSMatthias Ringwald         }
1861bbecc2bSMatthias Ringwald     }
1871bbecc2bSMatthias Ringwald }
1881bbecc2bSMatthias Ringwald 
189b63d04abSMatthias Ringwald #define MAX_NUM_SAMPLES (16*8)
190b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){
19135fd3fb9SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
19235fd3fb9SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
193b63d04abSMatthias Ringwald     if (num_samples > MAX_NUM_SAMPLES) return;
194b63d04abSMatthias Ringwald     int16_t sample_buffer[MAX_NUM_SAMPLES];
19559c97ae1SMatthias Ringwald     sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer);
19635fd3fb9SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
19735fd3fb9SMatthias Ringwald     num_audio_frames++;
19835fd3fb9SMatthias Ringwald }
1992b89dbfcSMatthias Ringwald #endif
2001bbecc2bSMatthias Ringwald #endif
201dbb41bfeSMilanka Ringwald 
202dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
203c4e666bcSMatthias Ringwald static int portaudio_callback( const void *inputBuffer, void *outputBuffer,
204dbb41bfeSMilanka Ringwald                            unsigned long framesPerBuffer,
205dbb41bfeSMilanka Ringwald                            const PaStreamCallbackTimeInfo* timeInfo,
206dbb41bfeSMilanka Ringwald                            PaStreamCallbackFlags statusFlags,
207dbb41bfeSMilanka Ringwald                            void *userData ) {
208dbb41bfeSMilanka Ringwald     (void) timeInfo; /* Prevent unused variable warnings. */
209dbb41bfeSMilanka Ringwald     (void) statusFlags;
210dbb41bfeSMilanka Ringwald     (void) inputBuffer;
2113963d036SMatthias Ringwald     (void) userData;
212dbb41bfeSMilanka Ringwald 
2132b89dbfcSMatthias Ringwald // output part
2142b89dbfcSMatthias Ringwald 
215c4e666bcSMatthias Ringwald     // config based on codec
216c4e666bcSMatthias Ringwald     int bytes_to_copy;
217be030f50SMilanka Ringwald     uint32_t prebuffer_bytes;
218c4e666bcSMatthias Ringwald     switch (negotiated_codec){
219c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
220c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * MSBC_BYTES_PER_FRAME;
221c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
222c4e666bcSMatthias Ringwald             break;
223c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
224c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * CVSD_BYTES_PER_FRAME;
225c4e666bcSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
226c4e666bcSMatthias Ringwald             break;
227c4e666bcSMatthias Ringwald         default:
228c4e666bcSMatthias Ringwald             bytes_to_copy   = framesPerBuffer * 2;  // assume 1 channel / 16 bit audio samples
229c4e666bcSMatthias Ringwald             prebuffer_bytes = 0xfffffff;
230c4e666bcSMatthias Ringwald             break;
231dbb41bfeSMilanka Ringwald     }
232dbb41bfeSMilanka Ringwald 
233c4e666bcSMatthias Ringwald     // fill with silence while paused
234463c9c89SMatthias Ringwald     if (pa_output_paused){
235463c9c89SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){
236c4e666bcSMatthias Ringwald             memset(outputBuffer, 0, bytes_to_copy);
237c4e666bcSMatthias Ringwald             return 0;
238dbb41bfeSMilanka Ringwald         } else {
239c4e666bcSMatthias Ringwald             // resume playback
240463c9c89SMatthias Ringwald             pa_output_paused = 0;
241dbb41bfeSMilanka Ringwald         }
242c4e666bcSMatthias Ringwald     }
243c4e666bcSMatthias Ringwald 
244c4e666bcSMatthias Ringwald     // get data from ringbuffer
245c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
246463c9c89SMatthias Ringwald     btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read);
247c4e666bcSMatthias Ringwald     bytes_to_copy -= bytes_read;
248c4e666bcSMatthias Ringwald 
249c4e666bcSMatthias Ringwald     // fill with 0 if not enough
250c4e666bcSMatthias Ringwald     if (bytes_to_copy){
251c4e666bcSMatthias Ringwald         memset(outputBuffer + bytes_read, 0, bytes_to_copy);
252463c9c89SMatthias Ringwald         pa_output_paused = 1;
253c4e666bcSMatthias Ringwald     }
2542b89dbfcSMatthias Ringwald // end of output part
2558b29cfc6SMatthias Ringwald 
2562b89dbfcSMatthias Ringwald // input part -- just store in ring buffer
2572b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
2582b89dbfcSMatthias Ringwald     btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2);
2592b89dbfcSMatthias Ringwald     pa_input_counter += framesPerBuffer * 2;
2602b89dbfcSMatthias Ringwald #endif
2612b89dbfcSMatthias Ringwald     return 0;
262c4e666bcSMatthias Ringwald }
263c4e666bcSMatthias Ringwald 
264c4e666bcSMatthias Ringwald // return 1 if ok
265c4e666bcSMatthias Ringwald static int portaudio_initialize(int sample_rate){
266c4e666bcSMatthias Ringwald     PaError err;
267c4e666bcSMatthias Ringwald 
268c4e666bcSMatthias Ringwald     /* -- initialize PortAudio -- */
269c4e666bcSMatthias Ringwald     printf("PortAudio: Initialize\n");
270c4e666bcSMatthias Ringwald     err = Pa_Initialize();
271c4e666bcSMatthias Ringwald     if( err != paNoError ) return 0;
2722b89dbfcSMatthias Ringwald 
273c4e666bcSMatthias Ringwald     /* -- setup input and output -- */
2742b89dbfcSMatthias Ringwald     const PaDeviceInfo *deviceInfo;
2752b89dbfcSMatthias Ringwald     PaStreamParameters * inputParameters = NULL;
2762b89dbfcSMatthias Ringwald     PaStreamParameters outputParameters;
277c4e666bcSMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
278c4e666bcSMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
279c4e666bcSMatthias Ringwald     outputParameters.sampleFormat = paInt16;
280c4e666bcSMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
281c4e666bcSMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
2822b89dbfcSMatthias Ringwald     deviceInfo = Pa_GetDeviceInfo( outputParameters.device );
2832b89dbfcSMatthias Ringwald     log_info("PortAudio: Output device: %s", deviceInfo->name);
2842b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
2852b89dbfcSMatthias Ringwald     PaStreamParameters theInputParameters;
2862b89dbfcSMatthias Ringwald     theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
2872b89dbfcSMatthias Ringwald     theInputParameters.channelCount = NUM_CHANNELS;
2882b89dbfcSMatthias Ringwald     theInputParameters.sampleFormat = paInt16;
2892b89dbfcSMatthias Ringwald     theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighOutputLatency;
2902b89dbfcSMatthias Ringwald     theInputParameters.hostApiSpecificStreamInfo = NULL;
2912b89dbfcSMatthias Ringwald     inputParameters = &theInputParameters;
2922b89dbfcSMatthias Ringwald     deviceInfo = Pa_GetDeviceInfo( inputParameters->device );
2932b89dbfcSMatthias Ringwald     log_info("PortAudio: Input device: %s", deviceInfo->name);
2942b89dbfcSMatthias Ringwald #endif
2952b89dbfcSMatthias Ringwald 
2962b89dbfcSMatthias Ringwald     /* -- setup output stream -- */
297c4e666bcSMatthias Ringwald     printf("PortAudio: Open stream\n");
298c4e666bcSMatthias Ringwald     err = Pa_OpenStream(
2992b89dbfcSMatthias Ringwald            &pa_stream,
3002b89dbfcSMatthias Ringwald            inputParameters,
301c4e666bcSMatthias Ringwald            &outputParameters,
302c4e666bcSMatthias Ringwald            sample_rate,
303c4e666bcSMatthias Ringwald            0,
304c4e666bcSMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
305c4e666bcSMatthias Ringwald            portaudio_callback,
306c4e666bcSMatthias Ringwald            NULL );
307c4e666bcSMatthias Ringwald     if (err != paNoError){
308c4e666bcSMatthias Ringwald         printf("Error opening portaudio stream: \"%s\"\n",  Pa_GetErrorText(err));
309c4e666bcSMatthias Ringwald         return 0;
310c4e666bcSMatthias Ringwald     }
311463c9c89SMatthias Ringwald     memset(pa_output_ring_buffer_storage, 0, sizeof(pa_output_ring_buffer_storage));
312463c9c89SMatthias Ringwald     btstack_ring_buffer_init(&pa_output_ring_buffer, pa_output_ring_buffer_storage, sizeof(pa_output_ring_buffer_storage));
3132b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
3142b89dbfcSMatthias Ringwald     memset(pa_input_ring_buffer_storage, 0, sizeof(pa_input_ring_buffer_storage));
3152b89dbfcSMatthias Ringwald     btstack_ring_buffer_init(&pa_input_ring_buffer, pa_input_ring_buffer_storage, sizeof(pa_input_ring_buffer_storage));
3162b89dbfcSMatthias Ringwald     printf("PortAudio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&pa_input_ring_buffer));
3172b89dbfcSMatthias Ringwald #endif
3182b89dbfcSMatthias Ringwald 
3192b89dbfcSMatthias Ringwald     /* -- start stream -- */
3202b89dbfcSMatthias Ringwald     err = Pa_StartStream(pa_stream);
3212b89dbfcSMatthias Ringwald     if (err != paNoError){
3222b89dbfcSMatthias Ringwald         printf("Error starting the stream: \"%s\"\n",  Pa_GetErrorText(err));
3232b89dbfcSMatthias Ringwald         return 0;
3242b89dbfcSMatthias Ringwald     }
3252b89dbfcSMatthias Ringwald     pa_output_started = 1;
3262b89dbfcSMatthias Ringwald     pa_output_paused  = 1;
3272b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT
3282b89dbfcSMatthias Ringwald     pa_input_started = 1;
3292b89dbfcSMatthias Ringwald     pa_input_paused  = 1;
3302b89dbfcSMatthias Ringwald #endif
3312b89dbfcSMatthias Ringwald 
332c4e666bcSMatthias Ringwald     return 1;
333c4e666bcSMatthias Ringwald }
3342b89dbfcSMatthias Ringwald 
3352b89dbfcSMatthias Ringwald static void portaudio_terminate(void){
3362b89dbfcSMatthias Ringwald     if (!pa_stream) return;
3372b89dbfcSMatthias Ringwald 
3382b89dbfcSMatthias Ringwald     PaError err;
3392b89dbfcSMatthias Ringwald     printf("PortAudio: Stop Stream\n");
3402b89dbfcSMatthias Ringwald     err = Pa_StopStream(pa_stream);
3412b89dbfcSMatthias Ringwald     if (err != paNoError){
3422b89dbfcSMatthias Ringwald         printf("Error stopping the stream: \"%s\"\n",  Pa_GetErrorText(err));
3432b89dbfcSMatthias Ringwald         return;
3442b89dbfcSMatthias Ringwald     }
3452b89dbfcSMatthias Ringwald     printf("PortAudio: Close Stream\n");
3462b89dbfcSMatthias Ringwald     err = Pa_CloseStream(pa_stream);
3472b89dbfcSMatthias Ringwald     if (err != paNoError){
3482b89dbfcSMatthias Ringwald         printf("Error closing the stream: \"%s\"\n",  Pa_GetErrorText(err));
3492b89dbfcSMatthias Ringwald         return;
3502b89dbfcSMatthias Ringwald     }
3512b89dbfcSMatthias Ringwald     pa_stream = NULL;
3522b89dbfcSMatthias Ringwald     printf("PortAudio: Terminate\n");
3532b89dbfcSMatthias Ringwald     err = Pa_Terminate();
3542b89dbfcSMatthias Ringwald     if (err != paNoError){
3552b89dbfcSMatthias Ringwald         printf("Error terminating portaudio: \"%s\"\n",  Pa_GetErrorText(err));
3562b89dbfcSMatthias Ringwald         return;
3572b89dbfcSMatthias Ringwald     }
3582b89dbfcSMatthias Ringwald }
359c4e666bcSMatthias Ringwald #endif
360c4e666bcSMatthias Ringwald 
3612c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
362c4e666bcSMatthias Ringwald 
3631bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
364c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
365c4e666bcSMatthias Ringwald     UNUSED(context);
366c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
3672c7ae6e1SMatthias Ringwald     UNUSED(data);
3682c7ae6e1SMatthias Ringwald     UNUSED(num_samples);
3692c7ae6e1SMatthias Ringwald     UNUSED(num_channels);
3702c7ae6e1SMatthias Ringwald 
3712c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
372c4e666bcSMatthias Ringwald 
373c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
374c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
3755303ddeeSMatthias Ringwald     // samples in callback in host endianess, ready for PortAudio playback
376463c9c89SMatthias Ringwald     btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
3771bbecc2bSMatthias Ringwald #endif /* HAVE_PORTAUDIO */
378dbb41bfeSMilanka Ringwald 
3792c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
380fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
381fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
382fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
383fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
384fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
3852c7ae6e1SMatthias Ringwald         wav_writer_close();
386fcb08cdbSMilanka Ringwald     }
3871bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3882c7ae6e1SMatthias Ringwald 
3891bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */
390fcb08cdbSMilanka Ringwald }
3911bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
3921bbecc2bSMatthias Ringwald 
3931bbecc2bSMatthias Ringwald 
3941bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
395fcb08cdbSMilanka Ringwald 
396fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
397c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
398c4e666bcSMatthias Ringwald 
399fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
400220eb563SMilanka Ringwald     hfp_msbc_init();
4012c7ae6e1SMatthias Ringwald 
4022c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
4032c7ae6e1SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
4042c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
4052c7ae6e1SMatthias Ringwald #endif
4062c7ae6e1SMatthias Ringwald 
4072b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
408b025eb5fSMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
4092b89dbfcSMatthias Ringwald #endif
410973d7173SMatthias Ringwald 
411d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
412d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
413d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
414d5e5f834SMatthias Ringwald #endif
4152b89dbfcSMatthias Ringwald 
4167294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
417d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
418d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
4197294d009SMatthias Ringwald #endif
420dbb41bfeSMilanka Ringwald 
421dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
422c4e666bcSMatthias Ringwald     portaudio_initialize(MSBC_SAMPLE_RATE);
423dbb41bfeSMilanka Ringwald #endif
424fcb08cdbSMilanka Ringwald }
425fcb08cdbSMilanka Ringwald 
426fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
427fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
428d5e5f834SMatthias Ringwald         if (msbc_file_in){
429d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
430d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
431d5e5f834SMatthias Ringwald         }
432fcb08cdbSMilanka Ringwald     }
433dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
434fcb08cdbSMilanka Ringwald }
4351bbecc2bSMatthias Ringwald #endif
436fcb08cdbSMilanka Ringwald 
437fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
438c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
439c4e666bcSMatthias Ringwald 
440d4f907a6SMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO)
441fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
442d4f907a6SMatthias Ringwald #endif
443c4e666bcSMatthias Ringwald 
4442c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
445c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
4462c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
4472c7ae6e1SMatthias Ringwald #endif
448dbb41bfeSMilanka Ringwald 
449dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
450c4e666bcSMatthias Ringwald     portaudio_initialize(CVSD_SAMPLE_RATE);
451dbb41bfeSMilanka Ringwald #endif
452fbc7c9f2SMilanka Ringwald }
453fbc7c9f2SMilanka Ringwald 
454fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
455dbb41bfeSMilanka Ringwald     if (!num_samples_to_write) return;
4562c7ae6e1SMatthias Ringwald 
4575303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
4581f8694ccSMatthias Ringwald 
4591f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
4601f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
4611f8694ccSMatthias Ringwald         return;
4621f8694ccSMatthias Ringwald     }
4632c7ae6e1SMatthias Ringwald 
4646211b0c0SMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO)
465c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
466c4e666bcSMatthias Ringwald     const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME;
4675303ddeeSMatthias Ringwald 
4685303ddeeSMatthias Ringwald     // convert into host endian
4695303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
4705303ddeeSMatthias Ringwald     int i;
4715303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
4725303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
4735303ddeeSMatthias Ringwald     }
4745303ddeeSMatthias Ringwald 
475e36764ddSMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out);
476d4f907a6SMatthias Ringwald #endif
4775303ddeeSMatthias Ringwald 
4782c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
4792c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
4802c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
4812c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
4822c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
4832c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
4842c7ae6e1SMatthias Ringwald         wav_writer_close();
4852c7ae6e1SMatthias Ringwald     }
4862c7ae6e1SMatthias Ringwald #endif
4872c7ae6e1SMatthias Ringwald 
488dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO
489463c9c89SMatthias Ringwald     btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
490dbb41bfeSMilanka Ringwald #endif
491fcb08cdbSMilanka Ringwald }
492fcb08cdbSMilanka Ringwald 
4932c7ae6e1SMatthias Ringwald #endif
4942c7ae6e1SMatthias Ringwald 
4952c7ae6e1SMatthias Ringwald 
496fcb08cdbSMilanka Ringwald void sco_demo_close(void){
497c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
4982b89dbfcSMatthias Ringwald 
49926463303SMilanka Ringwald     printf("SCO demo statistics: ");
5001bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
50126463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
5022c7ae6e1SMatthias 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);
5031bbecc2bSMatthias Ringwald     } else
5041bbecc2bSMatthias Ringwald #endif
5051bbecc2bSMatthias Ringwald     {
5062c7ae6e1SMatthias 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);
50726463303SMilanka Ringwald     }
50826463303SMilanka Ringwald 
5092c7ae6e1SMatthias Ringwald     negotiated_codec = -1;
5102c7ae6e1SMatthias Ringwald 
5112c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
5122c7ae6e1SMatthias Ringwald 
5132c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
5142c7ae6e1SMatthias Ringwald     wav_writer_close();
5152c7ae6e1SMatthias Ringwald #endif
5162c7ae6e1SMatthias Ringwald 
517dbb41bfeSMilanka Ringwald #ifdef HAVE_PORTAUDIO
5182b89dbfcSMatthias Ringwald     portaudio_terminate();
519dbb41bfeSMilanka Ringwald #endif
520fcb08cdbSMilanka Ringwald 
521fcb08cdbSMilanka Ringwald #endif
522fcb08cdbSMilanka Ringwald }
523fcb08cdbSMilanka Ringwald 
524fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
525fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
526fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
5272c7ae6e1SMatthias Ringwald 
5282b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
529220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
5301bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
531fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
5321bbecc2bSMatthias Ringwald #endif
533fcb08cdbSMilanka Ringwald     } else {
534fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
535fcb08cdbSMilanka Ringwald     }
536fcb08cdbSMilanka Ringwald #endif
537fcb08cdbSMilanka Ringwald }
538fcb08cdbSMilanka Ringwald 
539f7c85330SMatthias Ringwald void sco_demo_init(void){
540f7c85330SMatthias Ringwald 	// status
5412b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5422b89dbfcSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via portaudio.\n");
5432b89dbfcSMatthias Ringwald #endif
544f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
545f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
546f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
547f7c85330SMatthias Ringwald #else
548f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
549f7c85330SMatthias Ringwald #endif
550f7c85330SMatthias Ringwald #endif
551f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
552f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
553f7c85330SMatthias Ringwald #endif
554f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
555f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
556f7c85330SMatthias Ringwald #endif
557f7c85330SMatthias Ringwald 
5582b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
559c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
560c4e666bcSMatthias Ringwald #else
561f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
5627294d009SMatthias Ringwald #endif
563f7c85330SMatthias Ringwald 
564f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
565f7c85330SMatthias Ringwald     phase = 'a';
566f7c85330SMatthias Ringwald #endif
567f7c85330SMatthias Ringwald }
568f7c85330SMatthias Ringwald 
5691a919128SMatthias Ringwald void sco_report(void);
5701a919128SMatthias Ringwald void sco_report(void){
5714a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
5724a96141eSMatthias Ringwald }
573f7c85330SMatthias Ringwald 
574f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
575f7c85330SMatthias Ringwald 
576f7c85330SMatthias Ringwald     if (!sco_handle) return;
577f7c85330SMatthias Ringwald 
578c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
579c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
580f7c85330SMatthias Ringwald 
581f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
582f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
583f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
5841bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
585220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
586c4e666bcSMatthias Ringwald         // overwrite
587c4e666bcSMatthias Ringwald         sco_payload_length = 24;
588c4e666bcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
589c4e666bcSMatthias Ringwald 
590220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
591220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
592220eb563SMilanka Ringwald         }
593220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
594d5e5f834SMatthias Ringwald         if (msbc_file_out){
595d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
596d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
597d76591efSMatthias Ringwald         }
5987294d009SMatthias Ringwald 
599b025eb5fSMatthias Ringwald         sco_demo_msbc_fill_sine_audio_frame();
6001bbecc2bSMatthias Ringwald     } else
6011bbecc2bSMatthias Ringwald #endif
6021bbecc2bSMatthias Ringwald     {
603c4e666bcSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME;
604adaba9f3SMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]);
605220eb563SMilanka Ringwald     }
6061a919128SMatthias Ringwald #endif
6072b89dbfcSMatthias Ringwald 
6082b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
6092b89dbfcSMatthias Ringwald 
6102b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
6112b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
6122b89dbfcSMatthias Ringwald         // MSBC
6132b89dbfcSMatthias Ringwald 
6142b89dbfcSMatthias Ringwald         // overwrite
6152b89dbfcSMatthias Ringwald         sco_payload_length = 24;
6162b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
6172b89dbfcSMatthias Ringwald 
618b025eb5fSMatthias Ringwald         if (pa_input_paused){
619b025eb5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
620b025eb5fSMatthias Ringwald                 // resume sending
621b025eb5fSMatthias Ringwald                 pa_input_paused = 0;
6222b89dbfcSMatthias Ringwald             }
623b025eb5fSMatthias Ringwald         }
624b025eb5fSMatthias Ringwald 
625b025eb5fSMatthias Ringwald         if (!pa_input_paused){
626b025eb5fSMatthias Ringwald             int num_samples = hfp_msbc_num_audio_samples_per_frame();
627*8d3be402SMatthias Ringwald             if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (unsigned int)(num_samples * MSBC_BYTES_PER_FRAME)){
628b025eb5fSMatthias Ringwald                 int16_t sample_buffer[num_samples];
629b025eb5fSMatthias Ringwald                 uint32_t bytes_read;
630b025eb5fSMatthias Ringwald                 btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read);
631b025eb5fSMatthias Ringwald                 hfp_msbc_encode_audio_frame(sample_buffer);
632b025eb5fSMatthias Ringwald                 num_audio_frames++;
633b025eb5fSMatthias Ringwald             }
634b025eb5fSMatthias Ringwald         }
635b025eb5fSMatthias Ringwald 
636b025eb5fSMatthias Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
637b025eb5fSMatthias Ringwald             log_error("mSBC stream should not be empty.");
638b025eb5fSMatthias Ringwald             memset(sco_packet + 3, 0, sco_payload_length);
639b025eb5fSMatthias Ringwald             pa_input_paused = 1;
640b025eb5fSMatthias Ringwald         } else {
6412b89dbfcSMatthias Ringwald             hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
6422b89dbfcSMatthias Ringwald             if (msbc_file_out){
6432b89dbfcSMatthias Ringwald                 // log outgoing mSBC data for testing
6442b89dbfcSMatthias Ringwald                 fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
6452b89dbfcSMatthias Ringwald             }
646b025eb5fSMatthias Ringwald         }
6472b89dbfcSMatthias Ringwald 
6482b89dbfcSMatthias Ringwald     } else {
6492b89dbfcSMatthias Ringwald         // CVSD
6502b89dbfcSMatthias Ringwald 
6512b89dbfcSMatthias 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);
6522b89dbfcSMatthias Ringwald         // fill with silence while paused
6532b89dbfcSMatthias Ringwald         int bytes_to_copy = sco_payload_length;
6542b89dbfcSMatthias Ringwald         if (pa_input_paused){
6552b89dbfcSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
6562b89dbfcSMatthias Ringwald                 // resume sending
6572b89dbfcSMatthias Ringwald                 pa_input_paused = 0;
6582b89dbfcSMatthias Ringwald             }
6592b89dbfcSMatthias Ringwald         }
6602b89dbfcSMatthias Ringwald 
6612b89dbfcSMatthias Ringwald         // get data from ringbuffer
6622b89dbfcSMatthias Ringwald         uint16_t pos = 0;
6638fd6902dSMatthias Ringwald         uint8_t * sample_data = &sco_packet[3];
6642b89dbfcSMatthias Ringwald         if (!pa_input_paused){
6652b89dbfcSMatthias Ringwald             uint32_t bytes_read = 0;
6668fd6902dSMatthias Ringwald             btstack_ring_buffer_read(&pa_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
6678fd6902dSMatthias Ringwald             // flip 16 on big endian systems
6688fd6902dSMatthias Ringwald             // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
6698fd6902dSMatthias Ringwald             if (btstack_is_big_endian()){
670*8d3be402SMatthias Ringwald                 unsigned int i;
6718fd6902dSMatthias Ringwald                 for (i=0;i<bytes_read;i+=2){
6728fd6902dSMatthias Ringwald                     uint8_t tmp        = sample_data[i*2];
6738fd6902dSMatthias Ringwald                     sample_data[i*2]   = sample_data[i*2+1];
6748fd6902dSMatthias Ringwald                     sample_data[i*2+1] = tmp;
6758fd6902dSMatthias Ringwald                 }
6768fd6902dSMatthias Ringwald             }
6772b89dbfcSMatthias Ringwald             bytes_to_copy -= bytes_read;
6782b89dbfcSMatthias Ringwald             pos           += bytes_read;
6792b89dbfcSMatthias Ringwald         }
6802b89dbfcSMatthias Ringwald 
6812b89dbfcSMatthias Ringwald         // fill with 0 if not enough
6822b89dbfcSMatthias Ringwald         if (bytes_to_copy){
6838fd6902dSMatthias Ringwald             memset(sample_data + pos, 0, bytes_to_copy);
6842b89dbfcSMatthias Ringwald             pa_input_paused = 1;
6852b89dbfcSMatthias Ringwald         }
6862b89dbfcSMatthias Ringwald     }
6872b89dbfcSMatthias Ringwald #else
6882b89dbfcSMatthias Ringwald     // just send '0's
6892b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
6902b89dbfcSMatthias Ringwald         sco_payload_length = 24;
6912b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
6922b89dbfcSMatthias Ringwald     }
6932b89dbfcSMatthias Ringwald     memset(sco_packet + 3, 0, sco_payload_length);
6942b89dbfcSMatthias Ringwald #endif
6952b89dbfcSMatthias Ringwald #endif
6962b89dbfcSMatthias Ringwald 
697f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
698c4e666bcSMatthias Ringwald     memset(&sco_packet[3], phase++, sco_payload_length);
699f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
7001a919128SMatthias Ringwald #endif
7011a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
70238b2eaafSMatthias Ringwald     int j;
703c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
70438b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
705f7c85330SMatthias Ringwald     }
706f7c85330SMatthias Ringwald #endif
7071a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
7081a919128SMatthias Ringwald     int j;
709c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
7101a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
7111a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
7121a919128SMatthias Ringwald     }
7131a919128SMatthias Ringwald #endif
7141a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
7151a919128SMatthias Ringwald     int j;
716c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
7171a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
7181a919128SMatthias Ringwald     }
7191a919128SMatthias Ringwald     // additional hack
7201a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
7211a919128SMatthias Ringwald     (void) phase;
722f7c85330SMatthias Ringwald #endif
723220eb563SMilanka Ringwald 
7242b89dbfcSMatthias Ringwald     // test silence
7252b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
7262b89dbfcSMatthias Ringwald 
727c4e666bcSMatthias Ringwald     // set handle + flags
728c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
729c4e666bcSMatthias Ringwald     // set len
730c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
731c4e666bcSMatthias Ringwald     // finally send packet
732f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
733f7c85330SMatthias Ringwald 
734f7c85330SMatthias Ringwald     // request another send event
735f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
736f7c85330SMatthias Ringwald 
7374a96141eSMatthias Ringwald     count_sent++;
7381a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
7394a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
7401a919128SMatthias Ringwald #endif
741f7c85330SMatthias Ringwald }
742f7c85330SMatthias Ringwald 
743f7c85330SMatthias Ringwald /**
744f7c85330SMatthias Ringwald  * @brief Process received data
745f7c85330SMatthias Ringwald  */
7461a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
7471a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
7481a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
7491a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
7501a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
7511a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
7521a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
7531a919128SMatthias Ringwald 
754f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
755f7c85330SMatthias Ringwald 
756fcb08cdbSMilanka Ringwald     dump_data = 1;
7578b29cfc6SMatthias Ringwald 
7584a96141eSMatthias Ringwald     count_received++;
7591a919128SMatthias Ringwald     static uint32_t packets = 0;
7601a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
7611a919128SMatthias Ringwald     static uint32_t data_received = 0;
7621a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
7634a96141eSMatthias Ringwald 
7641a919128SMatthias Ringwald     data_received += size - 3;
7651a919128SMatthias Ringwald     packets++;
7661a919128SMatthias Ringwald     if (data_received > 100000){
767d4f907a6SMatthias 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);
7681a919128SMatthias Ringwald         crc_errors = 0;
7691a919128SMatthias Ringwald         byte_errors = 0;
7701a919128SMatthias Ringwald         data_received = 0;
7711a919128SMatthias Ringwald         packets = 0;
7721a919128SMatthias Ringwald     }
7734a96141eSMatthias Ringwald 
7742b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
775c4e666bcSMatthias Ringwald     switch (negotiated_codec){
7761bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
777c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
778fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
779c4e666bcSMatthias Ringwald             break;
7801bbecc2bSMatthias Ringwald #endif
781c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
782fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
783c4e666bcSMatthias Ringwald             break;
784c4e666bcSMatthias Ringwald         default:
785c4e666bcSMatthias Ringwald             break;
7868b29cfc6SMatthias Ringwald     }
787dbb41bfeSMilanka Ringwald     dump_data = 0;
7888b29cfc6SMatthias Ringwald #endif
7898b29cfc6SMatthias Ringwald 
790b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
7911a919128SMatthias Ringwald         crc_errors++;
7921a919128SMatthias Ringwald         // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
7931a919128SMatthias Ringwald         // printf_hexdump(&packet[3], size-3);
794f7c85330SMatthias Ringwald         return;
795f7c85330SMatthias Ringwald     }
7968b29cfc6SMatthias Ringwald     if (dump_data){
797f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
7981a919128SMatthias Ringwald         printf("data: ");
799f7c85330SMatthias Ringwald         int i;
800f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
801f7c85330SMatthias Ringwald             printf("%c", packet[i]);
802f7c85330SMatthias Ringwald         }
803f7c85330SMatthias Ringwald         printf("\n");
8048b29cfc6SMatthias Ringwald         dump_data = 0;
8051a919128SMatthias Ringwald #endif
8061a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
8071a919128SMatthias Ringwald         // colored hexdump with expected
8081a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
8091a919128SMatthias Ringwald         int i;
8101a919128SMatthias Ringwald         printf("data: ");
8111a919128SMatthias Ringwald         for (i=3;i<size;i++){
8121a919128SMatthias Ringwald             if (packet[i] != expected_byte){
8131a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
8141a919128SMatthias Ringwald             } else {
8151a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
8161a919128SMatthias Ringwald             }
8171a919128SMatthias Ringwald             expected_byte = packet[i]+1;
8181a919128SMatthias Ringwald         }
8191a919128SMatthias Ringwald         printf("\n");
8201a919128SMatthias Ringwald #endif
821a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
8221a919128SMatthias Ringwald         int i;
8231a919128SMatthias Ringwald         int contains_error = 0;
8241a919128SMatthias Ringwald         for (i=3;i<size;i++){
8251a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
8261a919128SMatthias Ringwald                 contains_error = 1;
8271a919128SMatthias Ringwald                 byte_errors++;
8281a919128SMatthias Ringwald             }
8291a919128SMatthias Ringwald         }
8301a919128SMatthias Ringwald         if (contains_error){
8311a919128SMatthias Ringwald             printf("data: ");
8321a919128SMatthias Ringwald             for (i=0;i<3;i++){
8331a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
8341a919128SMatthias Ringwald             }
8351a919128SMatthias Ringwald             for (i=3;i<size;i++){
8361a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
8371a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
8381a919128SMatthias Ringwald                 } else {
8391a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
8401a919128SMatthias Ringwald                 }
8411a919128SMatthias Ringwald             }
8421a919128SMatthias Ringwald             printf("\n");
8431a919128SMatthias Ringwald         }
844f7c85330SMatthias Ringwald #endif
8458b29cfc6SMatthias Ringwald     }
846f7c85330SMatthias Ringwald }
847