xref: /btstack/example/sco_demo_util.c (revision 01b2daf8adf115d897fc5fe158f267eb5e8d9bc8)
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"
47379c5f5fSMatthias Ringwald 
48379c5f5fSMatthias Ringwald #include "btstack_audio.h"
49fcb08cdbSMilanka Ringwald #include "btstack_debug.h"
50379c5f5fSMatthias Ringwald #include "btstack_ring_buffer.h"
5135fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h"
52379c5f5fSMatthias Ringwald #include "classic/btstack_sbc.h"
5335fd3fb9SMatthias Ringwald #include "classic/hfp.h"
54379c5f5fSMatthias 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
69*01b2daf8SMatthias Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_ASCII
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
92379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
93f7c85330SMatthias Ringwald 
94379c5f5fSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
95379c5f5fSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
96f7c85330SMatthias Ringwald 
972b89dbfcSMatthias Ringwald // output
98379c5f5fSMatthias Ringwald 
99d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
100d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
101379c5f5fSMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
102379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
103d861f4bfSMatthias Ringwald #endif
104d861f4bfSMatthias Ringwald 
1052b89dbfcSMatthias Ringwald 
1062b89dbfcSMatthias Ringwald // input
1072b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
108379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
109379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
110379c5f5fSMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2*8000];  // full second input buffer
111379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
112f7c85330SMatthias Ringwald #endif
113f7c85330SMatthias Ringwald 
114fcb08cdbSMilanka Ringwald static int dump_data = 1;
115fcb08cdbSMilanka Ringwald static int count_sent = 0;
116fcb08cdbSMilanka Ringwald static int count_received = 0;
117c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
118c4e666bcSMatthias Ringwald 
1191bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
120379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
1211bbecc2bSMatthias Ringwald #endif
1221bbecc2bSMatthias Ringwald 
123379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
124379c5f5fSMatthias Ringwald 
125379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8)
126fcb08cdbSMilanka Ringwald 
1271bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
128d5e5f834SMatthias Ringwald FILE * msbc_file_in;
129d5e5f834SMatthias Ringwald FILE * msbc_file_out;
1301bbecc2bSMatthias Ringwald #endif
1317294d009SMatthias Ringwald 
1322b89dbfcSMatthias Ringwald int num_samples_to_write;
1332b89dbfcSMatthias Ringwald int num_audio_frames;
134249d94cfSMatthias Ringwald unsigned int phase;
1352b89dbfcSMatthias Ringwald 
136f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
137d6a06398SMatthias Ringwald 
1387556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz
139c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
1407556ab9fSMatthias Ringwald      0,   3135,   6237,   9270,  12202,  14999,  17633,  20073,  22294,  24270,
1417556ab9fSMatthias Ringwald  25980,  27406,  28531,  29344,  29835,  30000,  29835,  29344,  28531,  27406,
1427556ab9fSMatthias Ringwald  25980,  24270,  22294,  20073,  17633,  14999,  12202,   9270,   6237,   3135,
1437556ab9fSMatthias Ringwald      0,  -3135,  -6237,  -9270, -12202, -14999, -17633, -20073, -22294, -24270,
1447556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406,
1457556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202,  -9270,  -6237,  -3135,
14635fd3fb9SMatthias Ringwald };
14735fd3fb9SMatthias Ringwald 
14859c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
149adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){
150249d94cfSMatthias Ringwald     unsigned int i;
15159c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
15259c97ae1SMatthias Ringwald         int16_t sample = sine_int16_at_16000hz[phase];
153adaba9f3SMatthias Ringwald         little_endian_store_16(data, i * 2, sample);
15459c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
15559c97ae1SMatthias Ringwald         phase += 2;
156c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
15735fd3fb9SMatthias Ringwald             phase = 0;
15835fd3fb9SMatthias Ringwald         }
15935fd3fb9SMatthias Ringwald     }
16035fd3fb9SMatthias Ringwald }
16135fd3fb9SMatthias Ringwald 
1621bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
1631bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
164249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){
165249d94cfSMatthias Ringwald     unsigned int i;
1661bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
1671bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
1681bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1691bbecc2bSMatthias Ringwald             phase = 0;
1701bbecc2bSMatthias Ringwald         }
1711bbecc2bSMatthias Ringwald     }
1721bbecc2bSMatthias Ringwald }
1731bbecc2bSMatthias Ringwald 
174b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){
17535fd3fb9SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
17635fd3fb9SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
177379c5f5fSMatthias Ringwald     if (num_samples > MAX_NUM_MSBC_SAMPLES) return;
178379c5f5fSMatthias Ringwald     int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
17959c97ae1SMatthias Ringwald     sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer);
18035fd3fb9SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
18135fd3fb9SMatthias Ringwald     num_audio_frames++;
18235fd3fb9SMatthias Ringwald }
1832b89dbfcSMatthias Ringwald #endif
1841bbecc2bSMatthias Ringwald #endif
185dbb41bfeSMilanka Ringwald 
186d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
187d861f4bfSMatthias Ringwald 
188379c5f5fSMatthias Ringwald static void playback_callback(int16_t * buffer, uint16_t num_samples){
1892b89dbfcSMatthias Ringwald 
190c4e666bcSMatthias Ringwald     // config based on codec
191379c5f5fSMatthias Ringwald     int bytes_to_copy   = num_samples * BYTES_PER_FRAME;
192be030f50SMilanka Ringwald     uint32_t prebuffer_bytes;
193c4e666bcSMatthias Ringwald     switch (negotiated_codec){
194c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
195c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
196c4e666bcSMatthias Ringwald             break;
197c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
198c4e666bcSMatthias Ringwald         default:
199379c5f5fSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
200c4e666bcSMatthias Ringwald             break;
201dbb41bfeSMilanka Ringwald     }
202dbb41bfeSMilanka Ringwald 
203c4e666bcSMatthias Ringwald     // fill with silence while paused
204379c5f5fSMatthias Ringwald     if (audio_output_paused){
205379c5f5fSMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){
206379c5f5fSMatthias Ringwald             memset(buffer, 0, bytes_to_copy);
207379c5f5fSMatthias Ringwald             return;
208dbb41bfeSMilanka Ringwald         } else {
209c4e666bcSMatthias Ringwald             // resume playback
210379c5f5fSMatthias Ringwald             audio_output_paused = 0;
211dbb41bfeSMilanka Ringwald         }
212c4e666bcSMatthias Ringwald     }
213c4e666bcSMatthias Ringwald 
214c4e666bcSMatthias Ringwald     // get data from ringbuffer
215c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
216379c5f5fSMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, bytes_to_copy, &bytes_read);
217c4e666bcSMatthias Ringwald     bytes_to_copy -= bytes_read;
218c4e666bcSMatthias Ringwald 
219c4e666bcSMatthias Ringwald     // fill with 0 if not enough
220c4e666bcSMatthias Ringwald     if (bytes_to_copy){
221379c5f5fSMatthias Ringwald         memset(buffer + bytes_read, 0, bytes_to_copy);
222379c5f5fSMatthias Ringwald         audio_output_paused = 1;
223c4e666bcSMatthias Ringwald     }
224379c5f5fSMatthias Ringwald }
2258b29cfc6SMatthias Ringwald 
226379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
227379c5f5fSMatthias Ringwald static void recording_callback(const int16_t * buffer, uint16_t num_samples){
228379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
229c4e666bcSMatthias Ringwald }
230379c5f5fSMatthias Ringwald #endif
231c4e666bcSMatthias Ringwald 
232c4e666bcSMatthias Ringwald // return 1 if ok
233379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
234c4e666bcSMatthias Ringwald 
235379c5f5fSMatthias Ringwald     // init buffers
236379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
237379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
238379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
239379c5f5fSMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
240379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
241379c5f5fSMatthias Ringwald     printf("Audio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&audio_input_ring_buffer));
2422b89dbfcSMatthias Ringwald #endif
2432b89dbfcSMatthias Ringwald 
244379c5f5fSMatthias Ringwald     // config and setup audio playback/recording
245379c5f5fSMatthias Ringwald     const btstack_audio_t * audio = btstack_audio_get_instance();
246379c5f5fSMatthias Ringwald     if (!audio) return 0;
2472b89dbfcSMatthias Ringwald 
248379c5f5fSMatthias Ringwald     void (*recording)(const int16_t * buffer, uint16_t num_samples) = NULL;
249379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
250379c5f5fSMatthias Ringwald     recording = &recording_callback;
251379c5f5fSMatthias Ringwald #endif
252379c5f5fSMatthias Ringwald     audio->init(1, sample_rate, &playback_callback, recording);
253379c5f5fSMatthias Ringwald     audio->start_stream();
254379c5f5fSMatthias Ringwald 
255379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
256379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
257379c5f5fSMatthias Ringwald     audio_input_paused  = 1;
2582b89dbfcSMatthias Ringwald #endif
2592b89dbfcSMatthias Ringwald 
260c4e666bcSMatthias Ringwald     return 1;
261c4e666bcSMatthias Ringwald }
2622b89dbfcSMatthias Ringwald 
263379c5f5fSMatthias Ringwald static void audio_terminate(void){
264379c5f5fSMatthias Ringwald     const btstack_audio_t * audio = btstack_audio_get_instance();
265379c5f5fSMatthias Ringwald     if (!audio) return;
266379c5f5fSMatthias Ringwald     audio->close();
2672b89dbfcSMatthias Ringwald }
268c4e666bcSMatthias Ringwald 
2691bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
270d861f4bfSMatthias Ringwald 
271c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
272c4e666bcSMatthias Ringwald     UNUSED(context);
273c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
2742c7ae6e1SMatthias Ringwald     UNUSED(data);
2752c7ae6e1SMatthias Ringwald     UNUSED(num_samples);
2762c7ae6e1SMatthias Ringwald     UNUSED(num_channels);
2772c7ae6e1SMatthias Ringwald 
2782c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
279c4e666bcSMatthias Ringwald 
280c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
281379c5f5fSMatthias Ringwald 
282379c5f5fSMatthias Ringwald     // samples in callback in host endianess, ready for playback
283379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
284dbb41bfeSMilanka Ringwald 
2852c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
286fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
287fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
288fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
289fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
290fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
2912c7ae6e1SMatthias Ringwald         wav_writer_close();
292fcb08cdbSMilanka Ringwald     }
2931bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */
2942c7ae6e1SMatthias Ringwald 
2951bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */
296fcb08cdbSMilanka Ringwald }
2971bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
2981bbecc2bSMatthias Ringwald 
2991bbecc2bSMatthias Ringwald 
3001bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
301fcb08cdbSMilanka Ringwald 
302fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
303c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
304c4e666bcSMatthias Ringwald 
305fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
306220eb563SMilanka Ringwald     hfp_msbc_init();
3072c7ae6e1SMatthias Ringwald 
3082c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3092c7ae6e1SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3102c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
3112c7ae6e1SMatthias Ringwald #endif
3122c7ae6e1SMatthias Ringwald 
3132b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
314b025eb5fSMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
3152b89dbfcSMatthias Ringwald #endif
316973d7173SMatthias Ringwald 
317d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
318d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
319d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
320d5e5f834SMatthias Ringwald #endif
3212b89dbfcSMatthias Ringwald 
3227294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
323d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
324d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
3257294d009SMatthias Ringwald #endif
326dbb41bfeSMilanka Ringwald 
327379c5f5fSMatthias Ringwald     audio_initialize(MSBC_SAMPLE_RATE);
328fcb08cdbSMilanka Ringwald }
329fcb08cdbSMilanka Ringwald 
330fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
331fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
332d5e5f834SMatthias Ringwald         if (msbc_file_in){
333d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
334d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
335d5e5f834SMatthias Ringwald         }
336fcb08cdbSMilanka Ringwald     }
337dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
338fcb08cdbSMilanka Ringwald }
3391bbecc2bSMatthias Ringwald #endif
340fcb08cdbSMilanka Ringwald 
341fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
342c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
343c4e666bcSMatthias Ringwald 
344fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
345c4e666bcSMatthias Ringwald 
3462c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
347c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3482c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
3492c7ae6e1SMatthias Ringwald #endif
350dbb41bfeSMilanka Ringwald 
351379c5f5fSMatthias Ringwald     audio_initialize(CVSD_SAMPLE_RATE);
352fbc7c9f2SMilanka Ringwald }
353fbc7c9f2SMilanka Ringwald 
354fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
355dbb41bfeSMilanka Ringwald     if (!num_samples_to_write) return;
3562c7ae6e1SMatthias Ringwald 
3575303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
3581f8694ccSMatthias Ringwald 
3591f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
3601f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
3611f8694ccSMatthias Ringwald         return;
3621f8694ccSMatthias Ringwald     }
3632c7ae6e1SMatthias Ringwald 
364c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
365379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
3665303ddeeSMatthias Ringwald 
3675303ddeeSMatthias Ringwald     // convert into host endian
3685303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
3695303ddeeSMatthias Ringwald     int i;
3705303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
3715303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
3725303ddeeSMatthias Ringwald     }
3735303ddeeSMatthias Ringwald 
374e36764ddSMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out);
3755303ddeeSMatthias Ringwald 
3762c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3772c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3782c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3792c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3802c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3812c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3822c7ae6e1SMatthias Ringwald         wav_writer_close();
3832c7ae6e1SMatthias Ringwald     }
3842c7ae6e1SMatthias Ringwald #endif
3852c7ae6e1SMatthias Ringwald 
386379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
387fcb08cdbSMilanka Ringwald }
388fcb08cdbSMilanka Ringwald 
3892c7ae6e1SMatthias Ringwald #endif
3902c7ae6e1SMatthias Ringwald 
3912c7ae6e1SMatthias Ringwald 
392fcb08cdbSMilanka Ringwald void sco_demo_close(void){
393c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
3942b89dbfcSMatthias Ringwald 
39526463303SMilanka Ringwald     printf("SCO demo statistics: ");
3961bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
39726463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
3982c7ae6e1SMatthias 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);
3991bbecc2bSMatthias Ringwald     } else
4001bbecc2bSMatthias Ringwald #endif
4011bbecc2bSMatthias Ringwald     {
4022c7ae6e1SMatthias 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);
40326463303SMilanka Ringwald     }
40426463303SMilanka Ringwald 
4052c7ae6e1SMatthias Ringwald     negotiated_codec = -1;
4062c7ae6e1SMatthias Ringwald 
4072c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
4082c7ae6e1SMatthias Ringwald 
4092c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
4102c7ae6e1SMatthias Ringwald     wav_writer_close();
4112c7ae6e1SMatthias Ringwald #endif
4122c7ae6e1SMatthias Ringwald 
413379c5f5fSMatthias Ringwald     audio_terminate();
414fcb08cdbSMilanka Ringwald 
415fcb08cdbSMilanka Ringwald #endif
416fcb08cdbSMilanka Ringwald }
417fcb08cdbSMilanka Ringwald 
418fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
419fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
420fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
4212c7ae6e1SMatthias Ringwald 
4222b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
423220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4241bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
425fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
4261bbecc2bSMatthias Ringwald #endif
427fcb08cdbSMilanka Ringwald     } else {
428fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
429fcb08cdbSMilanka Ringwald     }
430fcb08cdbSMilanka Ringwald #endif
431fcb08cdbSMilanka Ringwald }
432fcb08cdbSMilanka Ringwald 
433f7c85330SMatthias Ringwald void sco_demo_init(void){
434f7c85330SMatthias Ringwald 	// status
4352b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
436379c5f5fSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
4372b89dbfcSMatthias Ringwald #endif
438f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
439f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
440379c5f5fSMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
441f7c85330SMatthias Ringwald #else
442f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
443f7c85330SMatthias Ringwald #endif
444f7c85330SMatthias Ringwald #endif
445f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
446f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
447f7c85330SMatthias Ringwald #endif
448f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
449f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
450f7c85330SMatthias Ringwald #endif
451f7c85330SMatthias Ringwald 
4522b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
453c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
454c4e666bcSMatthias Ringwald #else
455f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
4567294d009SMatthias Ringwald #endif
457f7c85330SMatthias Ringwald }
458f7c85330SMatthias Ringwald 
4591a919128SMatthias Ringwald void sco_report(void);
4601a919128SMatthias Ringwald void sco_report(void){
4614a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
4624a96141eSMatthias Ringwald }
463f7c85330SMatthias Ringwald 
464f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
465f7c85330SMatthias Ringwald 
466e1de95beSMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
467f7c85330SMatthias Ringwald 
468c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
469c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
470f7c85330SMatthias Ringwald 
471f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
472f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
473f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
4741bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
475220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
476*01b2daf8SMatthias Ringwald 
477c4e666bcSMatthias Ringwald         // overwrite
478c4e666bcSMatthias Ringwald         sco_payload_length = 24;
479c4e666bcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
480c4e666bcSMatthias Ringwald 
481220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
482220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
483220eb563SMilanka Ringwald         }
484220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
485d5e5f834SMatthias Ringwald         if (msbc_file_out){
486d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
487d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
488d76591efSMatthias Ringwald         }
4897294d009SMatthias Ringwald 
490b025eb5fSMatthias Ringwald         sco_demo_msbc_fill_sine_audio_frame();
4911bbecc2bSMatthias Ringwald     } else
4921bbecc2bSMatthias Ringwald #endif
4931bbecc2bSMatthias Ringwald     {
494379c5f5fSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME;
495adaba9f3SMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]);
496220eb563SMilanka Ringwald     }
4971a919128SMatthias Ringwald #endif
4982b89dbfcSMatthias Ringwald 
4992b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5002b89dbfcSMatthias Ringwald 
5012b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
5022b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
5032b89dbfcSMatthias Ringwald         // MSBC
5042b89dbfcSMatthias Ringwald 
5052b89dbfcSMatthias Ringwald         // overwrite
5062b89dbfcSMatthias Ringwald         sco_payload_length = 24;
5072b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
5082b89dbfcSMatthias Ringwald 
509379c5f5fSMatthias Ringwald         if (audio_input_paused){
510379c5f5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
511b025eb5fSMatthias Ringwald                 // resume sending
512379c5f5fSMatthias Ringwald                 audio_input_paused = 0;
5132b89dbfcSMatthias Ringwald             }
514b025eb5fSMatthias Ringwald         }
515b025eb5fSMatthias Ringwald 
516379c5f5fSMatthias Ringwald         if (!audio_input_paused){
517b025eb5fSMatthias Ringwald             int num_samples = hfp_msbc_num_audio_samples_per_frame();
518379c5f5fSMatthias Ringwald             if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert
519379c5f5fSMatthias 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)){
520379c5f5fSMatthias Ringwald                 int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
521b025eb5fSMatthias Ringwald                 uint32_t bytes_read;
522379c5f5fSMatthias Ringwald                 btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
523b025eb5fSMatthias Ringwald                 hfp_msbc_encode_audio_frame(sample_buffer);
524b025eb5fSMatthias Ringwald                 num_audio_frames++;
525b025eb5fSMatthias Ringwald             }
526b025eb5fSMatthias Ringwald             if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
527b025eb5fSMatthias Ringwald                 log_error("mSBC stream should not be empty.");
528379c5f5fSMatthias Ringwald             }
529379c5f5fSMatthias Ringwald         }
530379c5f5fSMatthias Ringwald 
531379c5f5fSMatthias Ringwald         if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
532b025eb5fSMatthias Ringwald             memset(sco_packet + 3, 0, sco_payload_length);
533379c5f5fSMatthias Ringwald             audio_input_paused = 1;
534b025eb5fSMatthias Ringwald         } else {
5352b89dbfcSMatthias Ringwald             hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
5362b89dbfcSMatthias Ringwald             if (msbc_file_out){
5372b89dbfcSMatthias Ringwald                 // log outgoing mSBC data for testing
5382b89dbfcSMatthias Ringwald                 fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
5392b89dbfcSMatthias Ringwald             }
540b025eb5fSMatthias Ringwald         }
5412b89dbfcSMatthias Ringwald 
5422b89dbfcSMatthias Ringwald     } else {
5432b89dbfcSMatthias Ringwald         // CVSD
5442b89dbfcSMatthias Ringwald 
545379c5f5fSMatthias 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));
5462b89dbfcSMatthias Ringwald         // fill with silence while paused
5472b89dbfcSMatthias Ringwald         int bytes_to_copy = sco_payload_length;
548379c5f5fSMatthias Ringwald         if (audio_input_paused){
549379c5f5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
5502b89dbfcSMatthias Ringwald                 // resume sending
551379c5f5fSMatthias Ringwald                 audio_input_paused = 0;
5522b89dbfcSMatthias Ringwald             }
5532b89dbfcSMatthias Ringwald         }
5542b89dbfcSMatthias Ringwald 
5552b89dbfcSMatthias Ringwald         // get data from ringbuffer
5562b89dbfcSMatthias Ringwald         uint16_t pos = 0;
5578fd6902dSMatthias Ringwald         uint8_t * sample_data = &sco_packet[3];
558379c5f5fSMatthias Ringwald         if (!audio_input_paused){
5592b89dbfcSMatthias Ringwald             uint32_t bytes_read = 0;
560379c5f5fSMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
5618fd6902dSMatthias Ringwald             // flip 16 on big endian systems
5628fd6902dSMatthias Ringwald             // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
5638fd6902dSMatthias Ringwald             if (btstack_is_big_endian()){
5648d3be402SMatthias Ringwald                 unsigned int i;
5658fd6902dSMatthias Ringwald                 for (i=0;i<bytes_read;i+=2){
5668fd6902dSMatthias Ringwald                     uint8_t tmp        = sample_data[i*2];
5678fd6902dSMatthias Ringwald                     sample_data[i*2]   = sample_data[i*2+1];
5688fd6902dSMatthias Ringwald                     sample_data[i*2+1] = tmp;
5698fd6902dSMatthias Ringwald                 }
5708fd6902dSMatthias Ringwald             }
5712b89dbfcSMatthias Ringwald             bytes_to_copy -= bytes_read;
5722b89dbfcSMatthias Ringwald             pos           += bytes_read;
5732b89dbfcSMatthias Ringwald         }
5742b89dbfcSMatthias Ringwald 
5752b89dbfcSMatthias Ringwald         // fill with 0 if not enough
5762b89dbfcSMatthias Ringwald         if (bytes_to_copy){
5778fd6902dSMatthias Ringwald             memset(sample_data + pos, 0, bytes_to_copy);
578379c5f5fSMatthias Ringwald             audio_input_paused = 1;
5792b89dbfcSMatthias Ringwald         }
5802b89dbfcSMatthias Ringwald     }
5812b89dbfcSMatthias Ringwald #else
5822b89dbfcSMatthias Ringwald     // just send '0's
5832b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
5842b89dbfcSMatthias Ringwald         sco_payload_length = 24;
5852b89dbfcSMatthias Ringwald         sco_packet_length = sco_payload_length + 3;
5862b89dbfcSMatthias Ringwald     }
5872b89dbfcSMatthias Ringwald     memset(sco_packet + 3, 0, sco_payload_length);
5882b89dbfcSMatthias Ringwald #endif
5892b89dbfcSMatthias Ringwald #endif
5902b89dbfcSMatthias Ringwald 
591f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
592*01b2daf8SMatthias Ringwald     // store packet counter-xxxx
593*01b2daf8SMatthias Ringwald     snprintf((char *)&sco_packet[3], 5, "%04u", phase++);
594*01b2daf8SMatthias Ringwald     uint8_t ascii = (phase & 0x0f) + 'a';
595*01b2daf8SMatthias Ringwald     sco_packet[3+4] = '-';
596*01b2daf8SMatthias Ringwald     memset(&sco_packet[3+5], ascii, sco_payload_length-5);
5971a919128SMatthias Ringwald #endif
5981a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
59938b2eaafSMatthias Ringwald     int j;
600c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
60138b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
602f7c85330SMatthias Ringwald     }
603f7c85330SMatthias Ringwald #endif
6041a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
6051a919128SMatthias Ringwald     int j;
606c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6071a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
6081a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
6091a919128SMatthias Ringwald     }
6101a919128SMatthias Ringwald #endif
6111a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
6121a919128SMatthias Ringwald     int j;
613c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6141a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
6151a919128SMatthias Ringwald     }
6161a919128SMatthias Ringwald     // additional hack
6171a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
6181a919128SMatthias Ringwald     (void) phase;
619f7c85330SMatthias Ringwald #endif
620220eb563SMilanka Ringwald 
6212b89dbfcSMatthias Ringwald     // test silence
6222b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
6232b89dbfcSMatthias Ringwald 
624c4e666bcSMatthias Ringwald     // set handle + flags
625c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
626c4e666bcSMatthias Ringwald     // set len
627c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
628c4e666bcSMatthias Ringwald     // finally send packet
629f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
630f7c85330SMatthias Ringwald 
631f7c85330SMatthias Ringwald     // request another send event
632f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
633f7c85330SMatthias Ringwald 
6344a96141eSMatthias Ringwald     count_sent++;
6351a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
6364a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
6371a919128SMatthias Ringwald #endif
638f7c85330SMatthias Ringwald }
639f7c85330SMatthias Ringwald 
640f7c85330SMatthias Ringwald /**
641f7c85330SMatthias Ringwald  * @brief Process received data
642f7c85330SMatthias Ringwald  */
6431a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
6441a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
6451a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
6461a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
6471a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
6481a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
6491a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
6501a919128SMatthias Ringwald 
651f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
652f7c85330SMatthias Ringwald 
653fcb08cdbSMilanka Ringwald     dump_data = 1;
6548b29cfc6SMatthias Ringwald 
6554a96141eSMatthias Ringwald     count_received++;
6561a919128SMatthias Ringwald     static uint32_t packets = 0;
6571a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
6581a919128SMatthias Ringwald     static uint32_t data_received = 0;
6591a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
6604a96141eSMatthias Ringwald 
6611a919128SMatthias Ringwald     data_received += size - 3;
6621a919128SMatthias Ringwald     packets++;
6631a919128SMatthias Ringwald     if (data_received > 100000){
664d4f907a6SMatthias 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);
6651a919128SMatthias Ringwald         crc_errors = 0;
6661a919128SMatthias Ringwald         byte_errors = 0;
6671a919128SMatthias Ringwald         data_received = 0;
6681a919128SMatthias Ringwald         packets = 0;
6691a919128SMatthias Ringwald     }
6704a96141eSMatthias Ringwald 
6712b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
672c4e666bcSMatthias Ringwald     switch (negotiated_codec){
6731bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
674c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
675fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
676c4e666bcSMatthias Ringwald             break;
6771bbecc2bSMatthias Ringwald #endif
678c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
679fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
680c4e666bcSMatthias Ringwald             break;
681c4e666bcSMatthias Ringwald         default:
682c4e666bcSMatthias Ringwald             break;
6838b29cfc6SMatthias Ringwald     }
684dbb41bfeSMilanka Ringwald     dump_data = 0;
6858b29cfc6SMatthias Ringwald #endif
6868b29cfc6SMatthias Ringwald 
687*01b2daf8SMatthias Ringwald #if 0
688b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
6891a919128SMatthias Ringwald         crc_errors++;
690*01b2daf8SMatthias Ringwald         printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
691*01b2daf8SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
692f7c85330SMatthias Ringwald         return;
693f7c85330SMatthias Ringwald     }
694*01b2daf8SMatthias Ringwald #endif
695*01b2daf8SMatthias Ringwald 
6968b29cfc6SMatthias Ringwald     if (dump_data){
697f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
6981a919128SMatthias Ringwald         printf("data: ");
699f7c85330SMatthias Ringwald         int i;
700f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
701f7c85330SMatthias Ringwald             printf("%c", packet[i]);
702f7c85330SMatthias Ringwald         }
703f7c85330SMatthias Ringwald         printf("\n");
7048b29cfc6SMatthias Ringwald         dump_data = 0;
7051a919128SMatthias Ringwald #endif
7061a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
7071a919128SMatthias Ringwald         // colored hexdump with expected
7081a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
7091a919128SMatthias Ringwald         int i;
7101a919128SMatthias Ringwald         printf("data: ");
7111a919128SMatthias Ringwald         for (i=3;i<size;i++){
7121a919128SMatthias Ringwald             if (packet[i] != expected_byte){
7131a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7141a919128SMatthias Ringwald             } else {
7151a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7161a919128SMatthias Ringwald             }
7171a919128SMatthias Ringwald             expected_byte = packet[i]+1;
7181a919128SMatthias Ringwald         }
7191a919128SMatthias Ringwald         printf("\n");
7201a919128SMatthias Ringwald #endif
721a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
7221a919128SMatthias Ringwald         int i;
7231a919128SMatthias Ringwald         int contains_error = 0;
7241a919128SMatthias Ringwald         for (i=3;i<size;i++){
7251a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7261a919128SMatthias Ringwald                 contains_error = 1;
7271a919128SMatthias Ringwald                 byte_errors++;
7281a919128SMatthias Ringwald             }
7291a919128SMatthias Ringwald         }
7301a919128SMatthias Ringwald         if (contains_error){
7311a919128SMatthias Ringwald             printf("data: ");
7321a919128SMatthias Ringwald             for (i=0;i<3;i++){
7331a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7341a919128SMatthias Ringwald             }
7351a919128SMatthias Ringwald             for (i=3;i<size;i++){
7361a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7371a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7381a919128SMatthias Ringwald                 } else {
7391a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
7401a919128SMatthias Ringwald                 }
7411a919128SMatthias Ringwald             }
7421a919128SMatthias Ringwald             printf("\n");
7431a919128SMatthias Ringwald         }
744f7c85330SMatthias Ringwald #endif
7458b29cfc6SMatthias Ringwald     }
746f7c85330SMatthias Ringwald }
747