xref: /btstack/example/sco_demo_util.c (revision 379c5f5f0f6d28a956a436491f0adc4f8db10bd9)
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"
47*379c5f5fSMatthias Ringwald 
48*379c5f5fSMatthias Ringwald #include "btstack_audio.h"
49fcb08cdbSMilanka Ringwald #include "btstack_debug.h"
50*379c5f5fSMatthias Ringwald #include "btstack_ring_buffer.h"
5135fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h"
52*379c5f5fSMatthias Ringwald #include "classic/btstack_sbc.h"
5335fd3fb9SMatthias Ringwald #include "classic/hfp.h"
54*379c5f5fSMatthias Ringwald #include "classic/hfp_msbc.h"
55fcb08cdbSMilanka Ringwald 
5635fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
57fbc7c9f2SMilanka Ringwald #include "wav_util.h"
5835fd3fb9SMatthias Ringwald #endif
59fbc7c9f2SMilanka Ringwald 
60c4e666bcSMatthias Ringwald // test modes
61f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		 0
62f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII		 1
63f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER	 2
641a919128SMatthias Ringwald #define SCO_DEMO_MODE_55         3
651a919128SMatthias Ringwald #define SCO_DEMO_MODE_00         4
66463c9c89SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 5
67f7c85330SMatthias Ringwald 
68f7c85330SMatthias Ringwald // SCO demo configuration
69fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_SINE
70c4e666bcSMatthias Ringwald 
71c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console
72f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD           100
73f7c85330SMatthias Ringwald 
74d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
752c7ae6e1SMatthias Ringwald // length and name of wav file on disk
76c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
778b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
78d4f907a6SMatthias Ringwald #endif
79c4e666bcSMatthias Ringwald 
80c4e666bcSMatthias Ringwald // name of sbc test files
81d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME       "sco_output.msbc"
822308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME        "sco_input.msbc"
83220eb563SMilanka Ringwald 
84c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
85c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS    50
86c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS    50
878b29cfc6SMatthias Ringwald 
88c4e666bcSMatthias Ringwald // constants
89c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
90c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE        8000
91c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE        16000
92*379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
93f7c85330SMatthias Ringwald 
94*379c5f5fSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE || SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
95*379c5f5fSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
96*379c5f5fSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
97f7c85330SMatthias Ringwald #endif
98f7c85330SMatthias Ringwald 
992b89dbfcSMatthias Ringwald // output
100*379c5f5fSMatthias Ringwald static int                   audio_output_paused  = 0;
101*379c5f5fSMatthias Ringwald 
102*379c5f5fSMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
103*379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
1042b89dbfcSMatthias Ringwald 
1052b89dbfcSMatthias Ringwald // input
1062b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
107*379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
108*379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
109*379c5f5fSMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2*8000];  // full second input buffer
110*379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
111f7c85330SMatthias Ringwald #endif
112f7c85330SMatthias Ringwald 
113fcb08cdbSMilanka Ringwald static int dump_data = 1;
114fcb08cdbSMilanka Ringwald static int count_sent = 0;
115fcb08cdbSMilanka Ringwald static int count_received = 0;
116c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
117c4e666bcSMatthias Ringwald 
1181bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
119*379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
1201bbecc2bSMatthias Ringwald #endif
1211bbecc2bSMatthias Ringwald 
122*379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
123*379c5f5fSMatthias Ringwald 
124*379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8)
125fcb08cdbSMilanka Ringwald 
1261bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
127d5e5f834SMatthias Ringwald FILE * msbc_file_in;
128d5e5f834SMatthias Ringwald FILE * msbc_file_out;
1291bbecc2bSMatthias Ringwald #endif
1307294d009SMatthias Ringwald 
1312b89dbfcSMatthias Ringwald int num_samples_to_write;
1322b89dbfcSMatthias Ringwald int num_audio_frames;
133249d94cfSMatthias Ringwald unsigned int phase;
1342b89dbfcSMatthias Ringwald 
135f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
136d6a06398SMatthias Ringwald 
13735fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz
138c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
13935fd3fb9SMatthias Ringwald      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
14035fd3fb9SMatthias Ringwald  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
14135fd3fb9SMatthias Ringwald  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
14235fd3fb9SMatthias Ringwald  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
14335fd3fb9SMatthias Ringwald  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
14435fd3fb9SMatthias Ringwald      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
14535fd3fb9SMatthias Ringwald -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
14635fd3fb9SMatthias Ringwald -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
14735fd3fb9SMatthias Ringwald -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
14835fd3fb9SMatthias Ringwald -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
14935fd3fb9SMatthias Ringwald };
15035fd3fb9SMatthias Ringwald 
15159c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
152adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){
153249d94cfSMatthias Ringwald     unsigned int i;
15459c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
15559c97ae1SMatthias Ringwald         int16_t sample = sine_int16_at_16000hz[phase];
156adaba9f3SMatthias Ringwald         little_endian_store_16(data, i * 2, sample);
15759c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
15859c97ae1SMatthias Ringwald         phase += 2;
159c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
16035fd3fb9SMatthias Ringwald             phase = 0;
16135fd3fb9SMatthias Ringwald         }
16235fd3fb9SMatthias Ringwald     }
16335fd3fb9SMatthias Ringwald }
16435fd3fb9SMatthias Ringwald 
1651bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
1661bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
167249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){
168249d94cfSMatthias Ringwald     unsigned int i;
1691bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
1701bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
1711bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1721bbecc2bSMatthias Ringwald             phase = 0;
1731bbecc2bSMatthias Ringwald         }
1741bbecc2bSMatthias Ringwald     }
1751bbecc2bSMatthias Ringwald }
1761bbecc2bSMatthias Ringwald 
177b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){
17835fd3fb9SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
17935fd3fb9SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
180*379c5f5fSMatthias Ringwald     if (num_samples > MAX_NUM_MSBC_SAMPLES) return;
181*379c5f5fSMatthias Ringwald     int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
18259c97ae1SMatthias Ringwald     sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer);
18335fd3fb9SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
18435fd3fb9SMatthias Ringwald     num_audio_frames++;
18535fd3fb9SMatthias Ringwald }
1862b89dbfcSMatthias Ringwald #endif
1871bbecc2bSMatthias Ringwald #endif
188dbb41bfeSMilanka Ringwald 
189*379c5f5fSMatthias Ringwald static void playback_callback(int16_t * buffer, uint16_t num_samples){
1902b89dbfcSMatthias Ringwald 
191c4e666bcSMatthias Ringwald     // config based on codec
192*379c5f5fSMatthias Ringwald     int bytes_to_copy   = num_samples * BYTES_PER_FRAME;
193be030f50SMilanka Ringwald     uint32_t prebuffer_bytes;
194c4e666bcSMatthias Ringwald     switch (negotiated_codec){
195c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
196c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
197c4e666bcSMatthias Ringwald             break;
198c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
199c4e666bcSMatthias Ringwald         default:
200*379c5f5fSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
201c4e666bcSMatthias Ringwald             break;
202dbb41bfeSMilanka Ringwald     }
203dbb41bfeSMilanka Ringwald 
204c4e666bcSMatthias Ringwald     // fill with silence while paused
205*379c5f5fSMatthias Ringwald     if (audio_output_paused){
206*379c5f5fSMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){
207*379c5f5fSMatthias Ringwald             memset(buffer, 0, bytes_to_copy);
208*379c5f5fSMatthias Ringwald             return;
209dbb41bfeSMilanka Ringwald         } else {
210c4e666bcSMatthias Ringwald             // resume playback
211*379c5f5fSMatthias Ringwald             audio_output_paused = 0;
212dbb41bfeSMilanka Ringwald         }
213c4e666bcSMatthias Ringwald     }
214c4e666bcSMatthias Ringwald 
215c4e666bcSMatthias Ringwald     // get data from ringbuffer
216c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
217*379c5f5fSMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, bytes_to_copy, &bytes_read);
218c4e666bcSMatthias Ringwald     bytes_to_copy -= bytes_read;
219c4e666bcSMatthias Ringwald 
220c4e666bcSMatthias Ringwald     // fill with 0 if not enough
221c4e666bcSMatthias Ringwald     if (bytes_to_copy){
222*379c5f5fSMatthias Ringwald         memset(buffer + bytes_read, 0, bytes_to_copy);
223*379c5f5fSMatthias Ringwald         audio_output_paused = 1;
224c4e666bcSMatthias Ringwald     }
225*379c5f5fSMatthias Ringwald }
2268b29cfc6SMatthias Ringwald 
227*379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
228*379c5f5fSMatthias Ringwald static void recording_callback(const int16_t * buffer, uint16_t num_samples){
229*379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
230c4e666bcSMatthias Ringwald }
231*379c5f5fSMatthias Ringwald #endif
232c4e666bcSMatthias Ringwald 
233c4e666bcSMatthias Ringwald // return 1 if ok
234*379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
235c4e666bcSMatthias Ringwald 
236*379c5f5fSMatthias Ringwald     // init buffers
237*379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
238*379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
239*379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
240*379c5f5fSMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
241*379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
242*379c5f5fSMatthias Ringwald     printf("Audio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&audio_input_ring_buffer));
2432b89dbfcSMatthias Ringwald #endif
2442b89dbfcSMatthias Ringwald 
245*379c5f5fSMatthias Ringwald     // config and setup audio playback/recording
246*379c5f5fSMatthias Ringwald     const btstack_audio_t * audio = btstack_audio_get_instance();
247*379c5f5fSMatthias Ringwald     if (!audio) return 0;
2482b89dbfcSMatthias Ringwald 
249*379c5f5fSMatthias Ringwald     void (*recording)(const int16_t * buffer, uint16_t num_samples) = NULL;
250*379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
251*379c5f5fSMatthias Ringwald     recording = &recording_callback;
252*379c5f5fSMatthias Ringwald #endif
253*379c5f5fSMatthias Ringwald     audio->init(1, sample_rate, &playback_callback, recording);
254*379c5f5fSMatthias Ringwald     audio->start_stream();
255*379c5f5fSMatthias Ringwald 
256*379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
257*379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
258*379c5f5fSMatthias Ringwald     audio_input_paused  = 1;
2592b89dbfcSMatthias Ringwald #endif
2602b89dbfcSMatthias Ringwald 
261c4e666bcSMatthias Ringwald     return 1;
262c4e666bcSMatthias Ringwald }
2632b89dbfcSMatthias Ringwald 
264*379c5f5fSMatthias Ringwald static void audio_terminate(void){
265*379c5f5fSMatthias Ringwald     const btstack_audio_t * audio = btstack_audio_get_instance();
266*379c5f5fSMatthias Ringwald     if (!audio) return;
267*379c5f5fSMatthias Ringwald     audio->close();
2682b89dbfcSMatthias Ringwald }
269c4e666bcSMatthias Ringwald 
2702c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
271c4e666bcSMatthias Ringwald 
2721bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
273c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
274c4e666bcSMatthias Ringwald     UNUSED(context);
275c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
2762c7ae6e1SMatthias Ringwald     UNUSED(data);
2772c7ae6e1SMatthias Ringwald     UNUSED(num_samples);
2782c7ae6e1SMatthias Ringwald     UNUSED(num_channels);
2792c7ae6e1SMatthias Ringwald 
2802c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
281c4e666bcSMatthias Ringwald 
282c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
283*379c5f5fSMatthias Ringwald 
284*379c5f5fSMatthias Ringwald     // samples in callback in host endianess, ready for playback
285*379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
286dbb41bfeSMilanka Ringwald 
2872c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
288fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
289fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
290fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
291fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
292fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
2932c7ae6e1SMatthias Ringwald         wav_writer_close();
294fcb08cdbSMilanka Ringwald     }
2951bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */
2962c7ae6e1SMatthias Ringwald 
2971bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */
298fcb08cdbSMilanka Ringwald }
2991bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
3001bbecc2bSMatthias Ringwald 
3011bbecc2bSMatthias Ringwald 
3021bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
303fcb08cdbSMilanka Ringwald 
304fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
305c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
306c4e666bcSMatthias Ringwald 
307fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
308220eb563SMilanka Ringwald     hfp_msbc_init();
3092c7ae6e1SMatthias Ringwald 
3102c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3112c7ae6e1SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3122c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
3132c7ae6e1SMatthias Ringwald #endif
3142c7ae6e1SMatthias Ringwald 
3152b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
316b025eb5fSMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
3172b89dbfcSMatthias Ringwald #endif
318973d7173SMatthias Ringwald 
319d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
320d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
321d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
322d5e5f834SMatthias Ringwald #endif
3232b89dbfcSMatthias Ringwald 
3247294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
325d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
326d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
3277294d009SMatthias Ringwald #endif
328dbb41bfeSMilanka Ringwald 
329*379c5f5fSMatthias Ringwald     audio_initialize(MSBC_SAMPLE_RATE);
330fcb08cdbSMilanka Ringwald }
331fcb08cdbSMilanka Ringwald 
332fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
333fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
334d5e5f834SMatthias Ringwald         if (msbc_file_in){
335d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
336d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
337d5e5f834SMatthias Ringwald         }
338fcb08cdbSMilanka Ringwald     }
339dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
340fcb08cdbSMilanka Ringwald }
3411bbecc2bSMatthias Ringwald #endif
342fcb08cdbSMilanka Ringwald 
343fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
344c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
345c4e666bcSMatthias Ringwald 
346fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
347c4e666bcSMatthias Ringwald 
3482c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
349c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3502c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
3512c7ae6e1SMatthias Ringwald #endif
352dbb41bfeSMilanka Ringwald 
353*379c5f5fSMatthias Ringwald     audio_initialize(CVSD_SAMPLE_RATE);
354fbc7c9f2SMilanka Ringwald }
355fbc7c9f2SMilanka Ringwald 
356fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
357dbb41bfeSMilanka Ringwald     if (!num_samples_to_write) return;
3582c7ae6e1SMatthias Ringwald 
3595303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
3601f8694ccSMatthias Ringwald 
3611f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
3621f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
3631f8694ccSMatthias Ringwald         return;
3641f8694ccSMatthias Ringwald     }
3652c7ae6e1SMatthias Ringwald 
366c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
367*379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
3685303ddeeSMatthias Ringwald 
3695303ddeeSMatthias Ringwald     // convert into host endian
3705303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
3715303ddeeSMatthias Ringwald     int i;
3725303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
3735303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
3745303ddeeSMatthias Ringwald     }
3755303ddeeSMatthias Ringwald 
376e36764ddSMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out);
3775303ddeeSMatthias Ringwald 
3782c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3792c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3802c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3812c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3822c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3832c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3842c7ae6e1SMatthias Ringwald         wav_writer_close();
3852c7ae6e1SMatthias Ringwald     }
3862c7ae6e1SMatthias Ringwald #endif
3872c7ae6e1SMatthias Ringwald 
388*379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
389fcb08cdbSMilanka Ringwald }
390fcb08cdbSMilanka Ringwald 
3912c7ae6e1SMatthias Ringwald #endif
3922c7ae6e1SMatthias Ringwald 
3932c7ae6e1SMatthias Ringwald 
394fcb08cdbSMilanka Ringwald void sco_demo_close(void){
395c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
3962b89dbfcSMatthias Ringwald 
39726463303SMilanka Ringwald     printf("SCO demo statistics: ");
3981bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
39926463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4002c7ae6e1SMatthias 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);
4011bbecc2bSMatthias Ringwald     } else
4021bbecc2bSMatthias Ringwald #endif
4031bbecc2bSMatthias Ringwald     {
4042c7ae6e1SMatthias 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);
40526463303SMilanka Ringwald     }
40626463303SMilanka Ringwald 
4072c7ae6e1SMatthias Ringwald     negotiated_codec = -1;
4082c7ae6e1SMatthias Ringwald 
4092c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
4102c7ae6e1SMatthias Ringwald 
4112c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
4122c7ae6e1SMatthias Ringwald     wav_writer_close();
4132c7ae6e1SMatthias Ringwald #endif
4142c7ae6e1SMatthias Ringwald 
415*379c5f5fSMatthias Ringwald     audio_terminate();
416fcb08cdbSMilanka Ringwald 
417fcb08cdbSMilanka Ringwald #endif
418fcb08cdbSMilanka Ringwald }
419fcb08cdbSMilanka Ringwald 
420fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
421fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
422fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
4232c7ae6e1SMatthias Ringwald 
4242b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
425220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4261bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
427fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
4281bbecc2bSMatthias Ringwald #endif
429fcb08cdbSMilanka Ringwald     } else {
430fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
431fcb08cdbSMilanka Ringwald     }
432fcb08cdbSMilanka Ringwald #endif
433fcb08cdbSMilanka Ringwald }
434fcb08cdbSMilanka Ringwald 
435f7c85330SMatthias Ringwald void sco_demo_init(void){
436f7c85330SMatthias Ringwald 	// status
4372b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
438*379c5f5fSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
4392b89dbfcSMatthias Ringwald #endif
440f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
441f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
442*379c5f5fSMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
443f7c85330SMatthias Ringwald #else
444f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
445f7c85330SMatthias Ringwald #endif
446f7c85330SMatthias Ringwald #endif
447f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
448f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
449f7c85330SMatthias Ringwald #endif
450f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
451f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
452f7c85330SMatthias Ringwald #endif
453f7c85330SMatthias Ringwald 
4542b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
455c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
456c4e666bcSMatthias Ringwald #else
457f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
4587294d009SMatthias Ringwald #endif
459f7c85330SMatthias Ringwald 
460f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
461f7c85330SMatthias Ringwald     phase = 'a';
462f7c85330SMatthias Ringwald #endif
463f7c85330SMatthias Ringwald }
464f7c85330SMatthias Ringwald 
4651a919128SMatthias Ringwald void sco_report(void);
4661a919128SMatthias Ringwald void sco_report(void){
4674a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
4684a96141eSMatthias Ringwald }
469f7c85330SMatthias Ringwald 
470f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
471f7c85330SMatthias Ringwald 
472f7c85330SMatthias Ringwald     if (!sco_handle) return;
473f7c85330SMatthias Ringwald 
474c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
475c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
476f7c85330SMatthias Ringwald 
477f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
478f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
479f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
4801bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
481220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
482c4e666bcSMatthias Ringwald         // overwrite
483c4e666bcSMatthias Ringwald         sco_payload_length = 24;
484c4e666bcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
485c4e666bcSMatthias Ringwald 
486220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
487220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
488220eb563SMilanka Ringwald         }
489220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
490d5e5f834SMatthias Ringwald         if (msbc_file_out){
491d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
492d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
493d76591efSMatthias Ringwald         }
4947294d009SMatthias Ringwald 
495b025eb5fSMatthias Ringwald         sco_demo_msbc_fill_sine_audio_frame();
4961bbecc2bSMatthias Ringwald     } else
4971bbecc2bSMatthias Ringwald #endif
4981bbecc2bSMatthias Ringwald     {
499*379c5f5fSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME;
500adaba9f3SMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]);
501220eb563SMilanka Ringwald     }
5021a919128SMatthias Ringwald #endif
5032b89dbfcSMatthias Ringwald 
5042b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5052b89dbfcSMatthias Ringwald 
5062b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
5072b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
5082b89dbfcSMatthias Ringwald         // MSBC
5092b89dbfcSMatthias Ringwald 
5102b89dbfcSMatthias Ringwald         // overwrite
5112b89dbfcSMatthias Ringwald         sco_payload_length = 24;
5122b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
5132b89dbfcSMatthias Ringwald 
514*379c5f5fSMatthias Ringwald         if (audio_input_paused){
515*379c5f5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
516b025eb5fSMatthias Ringwald                 // resume sending
517*379c5f5fSMatthias Ringwald                 audio_input_paused = 0;
5182b89dbfcSMatthias Ringwald             }
519b025eb5fSMatthias Ringwald         }
520b025eb5fSMatthias Ringwald 
521*379c5f5fSMatthias Ringwald         if (!audio_input_paused){
522b025eb5fSMatthias Ringwald             int num_samples = hfp_msbc_num_audio_samples_per_frame();
523*379c5f5fSMatthias Ringwald             if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert
524*379c5f5fSMatthias Ringwald             if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= (unsigned int)(num_samples * BYTES_PER_FRAME)){
525*379c5f5fSMatthias Ringwald                 int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
526b025eb5fSMatthias Ringwald                 uint32_t bytes_read;
527*379c5f5fSMatthias Ringwald                 btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
528b025eb5fSMatthias Ringwald                 hfp_msbc_encode_audio_frame(sample_buffer);
529b025eb5fSMatthias Ringwald                 num_audio_frames++;
530b025eb5fSMatthias Ringwald             }
531b025eb5fSMatthias Ringwald             if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
532b025eb5fSMatthias Ringwald                 log_error("mSBC stream should not be empty.");
533*379c5f5fSMatthias Ringwald             }
534*379c5f5fSMatthias Ringwald         }
535*379c5f5fSMatthias Ringwald 
536*379c5f5fSMatthias Ringwald         if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
537b025eb5fSMatthias Ringwald             memset(sco_packet + 3, 0, sco_payload_length);
538*379c5f5fSMatthias Ringwald             audio_input_paused = 1;
539b025eb5fSMatthias Ringwald         } else {
5402b89dbfcSMatthias Ringwald             hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
5412b89dbfcSMatthias Ringwald             if (msbc_file_out){
5422b89dbfcSMatthias Ringwald                 // log outgoing mSBC data for testing
5432b89dbfcSMatthias Ringwald                 fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
5442b89dbfcSMatthias Ringwald             }
545b025eb5fSMatthias Ringwald         }
5462b89dbfcSMatthias Ringwald 
5472b89dbfcSMatthias Ringwald     } else {
5482b89dbfcSMatthias Ringwald         // CVSD
5492b89dbfcSMatthias Ringwald 
550*379c5f5fSMatthias Ringwald         log_info("send: bytes avail %u, free %u", btstack_ring_buffer_bytes_available(&audio_input_ring_buffer), btstack_ring_buffer_bytes_free(&audio_input_ring_buffer));
5512b89dbfcSMatthias Ringwald         // fill with silence while paused
5522b89dbfcSMatthias Ringwald         int bytes_to_copy = sco_payload_length;
553*379c5f5fSMatthias Ringwald         if (audio_input_paused){
554*379c5f5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
5552b89dbfcSMatthias Ringwald                 // resume sending
556*379c5f5fSMatthias Ringwald                 audio_input_paused = 0;
5572b89dbfcSMatthias Ringwald             }
5582b89dbfcSMatthias Ringwald         }
5592b89dbfcSMatthias Ringwald 
5602b89dbfcSMatthias Ringwald         // get data from ringbuffer
5612b89dbfcSMatthias Ringwald         uint16_t pos = 0;
5628fd6902dSMatthias Ringwald         uint8_t * sample_data = &sco_packet[3];
563*379c5f5fSMatthias Ringwald         if (!audio_input_paused){
5642b89dbfcSMatthias Ringwald             uint32_t bytes_read = 0;
565*379c5f5fSMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
5668fd6902dSMatthias Ringwald             // flip 16 on big endian systems
5678fd6902dSMatthias Ringwald             // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
5688fd6902dSMatthias Ringwald             if (btstack_is_big_endian()){
5698d3be402SMatthias Ringwald                 unsigned int i;
5708fd6902dSMatthias Ringwald                 for (i=0;i<bytes_read;i+=2){
5718fd6902dSMatthias Ringwald                     uint8_t tmp        = sample_data[i*2];
5728fd6902dSMatthias Ringwald                     sample_data[i*2]   = sample_data[i*2+1];
5738fd6902dSMatthias Ringwald                     sample_data[i*2+1] = tmp;
5748fd6902dSMatthias Ringwald                 }
5758fd6902dSMatthias Ringwald             }
5762b89dbfcSMatthias Ringwald             bytes_to_copy -= bytes_read;
5772b89dbfcSMatthias Ringwald             pos           += bytes_read;
5782b89dbfcSMatthias Ringwald         }
5792b89dbfcSMatthias Ringwald 
5802b89dbfcSMatthias Ringwald         // fill with 0 if not enough
5812b89dbfcSMatthias Ringwald         if (bytes_to_copy){
5828fd6902dSMatthias Ringwald             memset(sample_data + pos, 0, bytes_to_copy);
583*379c5f5fSMatthias Ringwald             audio_input_paused = 1;
5842b89dbfcSMatthias Ringwald         }
5852b89dbfcSMatthias Ringwald     }
5862b89dbfcSMatthias Ringwald #else
5872b89dbfcSMatthias Ringwald     // just send '0's
5882b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
5892b89dbfcSMatthias Ringwald         sco_payload_length = 24;
5902b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
5912b89dbfcSMatthias Ringwald     }
5922b89dbfcSMatthias Ringwald     memset(sco_packet + 3, 0, sco_payload_length);
5932b89dbfcSMatthias Ringwald #endif
5942b89dbfcSMatthias Ringwald #endif
5952b89dbfcSMatthias Ringwald 
596f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
597c4e666bcSMatthias Ringwald     memset(&sco_packet[3], phase++, sco_payload_length);
598f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
5991a919128SMatthias Ringwald #endif
6001a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
60138b2eaafSMatthias Ringwald     int j;
602c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
60338b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
604f7c85330SMatthias Ringwald     }
605f7c85330SMatthias Ringwald #endif
6061a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
6071a919128SMatthias Ringwald     int j;
608c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6091a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
6101a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
6111a919128SMatthias Ringwald     }
6121a919128SMatthias Ringwald #endif
6131a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
6141a919128SMatthias Ringwald     int j;
615c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6161a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
6171a919128SMatthias Ringwald     }
6181a919128SMatthias Ringwald     // additional hack
6191a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
6201a919128SMatthias Ringwald     (void) phase;
621f7c85330SMatthias Ringwald #endif
622220eb563SMilanka Ringwald 
6232b89dbfcSMatthias Ringwald     // test silence
6242b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
6252b89dbfcSMatthias Ringwald 
626c4e666bcSMatthias Ringwald     // set handle + flags
627c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
628c4e666bcSMatthias Ringwald     // set len
629c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
630c4e666bcSMatthias Ringwald     // finally send packet
631f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
632f7c85330SMatthias Ringwald 
633f7c85330SMatthias Ringwald     // request another send event
634f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
635f7c85330SMatthias Ringwald 
6364a96141eSMatthias Ringwald     count_sent++;
6371a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
6384a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
6391a919128SMatthias Ringwald #endif
640f7c85330SMatthias Ringwald }
641f7c85330SMatthias Ringwald 
642f7c85330SMatthias Ringwald /**
643f7c85330SMatthias Ringwald  * @brief Process received data
644f7c85330SMatthias Ringwald  */
6451a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
6461a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
6471a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
6481a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
6491a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
6501a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
6511a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
6521a919128SMatthias Ringwald 
653f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
654f7c85330SMatthias Ringwald 
655fcb08cdbSMilanka Ringwald     dump_data = 1;
6568b29cfc6SMatthias Ringwald 
6574a96141eSMatthias Ringwald     count_received++;
6581a919128SMatthias Ringwald     static uint32_t packets = 0;
6591a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
6601a919128SMatthias Ringwald     static uint32_t data_received = 0;
6611a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
6624a96141eSMatthias Ringwald 
6631a919128SMatthias Ringwald     data_received += size - 3;
6641a919128SMatthias Ringwald     packets++;
6651a919128SMatthias Ringwald     if (data_received > 100000){
666d4f907a6SMatthias 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);
6671a919128SMatthias Ringwald         crc_errors = 0;
6681a919128SMatthias Ringwald         byte_errors = 0;
6691a919128SMatthias Ringwald         data_received = 0;
6701a919128SMatthias Ringwald         packets = 0;
6711a919128SMatthias Ringwald     }
6724a96141eSMatthias Ringwald 
6732b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
674c4e666bcSMatthias Ringwald     switch (negotiated_codec){
6751bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
676c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
677fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
678c4e666bcSMatthias Ringwald             break;
6791bbecc2bSMatthias Ringwald #endif
680c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
681fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
682c4e666bcSMatthias Ringwald             break;
683c4e666bcSMatthias Ringwald         default:
684c4e666bcSMatthias Ringwald             break;
6858b29cfc6SMatthias Ringwald     }
686dbb41bfeSMilanka Ringwald     dump_data = 0;
6878b29cfc6SMatthias Ringwald #endif
6888b29cfc6SMatthias Ringwald 
689b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
6901a919128SMatthias Ringwald         crc_errors++;
6911a919128SMatthias Ringwald         // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
6921a919128SMatthias Ringwald         // printf_hexdump(&packet[3], size-3);
693f7c85330SMatthias Ringwald         return;
694f7c85330SMatthias Ringwald     }
6958b29cfc6SMatthias Ringwald     if (dump_data){
696f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
6971a919128SMatthias Ringwald         printf("data: ");
698f7c85330SMatthias Ringwald         int i;
699f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
700f7c85330SMatthias Ringwald             printf("%c", packet[i]);
701f7c85330SMatthias Ringwald         }
702f7c85330SMatthias Ringwald         printf("\n");
7038b29cfc6SMatthias Ringwald         dump_data = 0;
7041a919128SMatthias Ringwald #endif
7051a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
7061a919128SMatthias Ringwald         // colored hexdump with expected
7071a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
7081a919128SMatthias Ringwald         int i;
7091a919128SMatthias Ringwald         printf("data: ");
7101a919128SMatthias Ringwald         for (i=3;i<size;i++){
7111a919128SMatthias Ringwald             if (packet[i] != expected_byte){
7121a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7131a919128SMatthias Ringwald             } else {
7141a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7151a919128SMatthias Ringwald             }
7161a919128SMatthias Ringwald             expected_byte = packet[i]+1;
7171a919128SMatthias Ringwald         }
7181a919128SMatthias Ringwald         printf("\n");
7191a919128SMatthias Ringwald #endif
720a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
7211a919128SMatthias Ringwald         int i;
7221a919128SMatthias Ringwald         int contains_error = 0;
7231a919128SMatthias Ringwald         for (i=3;i<size;i++){
7241a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7251a919128SMatthias Ringwald                 contains_error = 1;
7261a919128SMatthias Ringwald                 byte_errors++;
7271a919128SMatthias Ringwald             }
7281a919128SMatthias Ringwald         }
7291a919128SMatthias Ringwald         if (contains_error){
7301a919128SMatthias Ringwald             printf("data: ");
7311a919128SMatthias Ringwald             for (i=0;i<3;i++){
7321a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7331a919128SMatthias Ringwald             }
7341a919128SMatthias Ringwald             for (i=3;i<size;i++){
7351a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7361a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7371a919128SMatthias Ringwald                 } else {
7381a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
7391a919128SMatthias Ringwald                 }
7401a919128SMatthias Ringwald             }
7411a919128SMatthias Ringwald             printf("\n");
7421a919128SMatthias Ringwald         }
743f7c85330SMatthias Ringwald #endif
7448b29cfc6SMatthias Ringwald     }
745f7c85330SMatthias Ringwald }
746