xref: /btstack/example/sco_demo_util.c (revision d365bb511ad50c3e161b326cac60f8bade7ad566)
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*d365bb51SMatthias Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_MICROPHONE
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 
235*d365bb51SMatthias Ringwald     // -- output -- //
236*d365bb51SMatthias Ringwald 
237379c5f5fSMatthias Ringwald     // init buffers
238379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
239379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2402b89dbfcSMatthias Ringwald 
241*d365bb51SMatthias Ringwald     // config and setup audio playback
242*d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
243*d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2442b89dbfcSMatthias Ringwald 
245*d365bb51SMatthias Ringwald     audio_sink->init(1, sample_rate, &playback_callback);
246*d365bb51SMatthias Ringwald     audio_sink->start_stream();
247379c5f5fSMatthias Ringwald 
248379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
249*d365bb51SMatthias Ringwald 
250*d365bb51SMatthias Ringwald     // -- input -- //
251*d365bb51SMatthias Ringwald 
252379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
253*d365bb51SMatthias Ringwald     // init buffers
254*d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
255*d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
256*d365bb51SMatthias Ringwald 
257*d365bb51SMatthias Ringwald     // config and setup audio recording
258*d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
259*d365bb51SMatthias Ringwald     if (!audio_source) return 0;
260*d365bb51SMatthias Ringwald 
261*d365bb51SMatthias Ringwald     audio_source->init(1, sample_rate, &recording_callback);
262*d365bb51SMatthias Ringwald     audio_source->start_stream();
263*d365bb51SMatthias Ringwald 
264379c5f5fSMatthias Ringwald     audio_input_paused  = 1;
2652b89dbfcSMatthias Ringwald #endif
2662b89dbfcSMatthias Ringwald 
267c4e666bcSMatthias Ringwald     return 1;
268c4e666bcSMatthias Ringwald }
2692b89dbfcSMatthias Ringwald 
270379c5f5fSMatthias Ringwald static void audio_terminate(void){
271*d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
272*d365bb51SMatthias Ringwald     if (!audio_sink) return;
273*d365bb51SMatthias Ringwald     audio_sink->close();
274*d365bb51SMatthias Ringwald 
275*d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
276*d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
277*d365bb51SMatthias Ringwald     if (!audio_source) return;
278*d365bb51SMatthias Ringwald     audio_source->close();
279*d365bb51SMatthias Ringwald #endif
2802b89dbfcSMatthias Ringwald }
281c4e666bcSMatthias Ringwald 
2821bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
283d861f4bfSMatthias Ringwald 
284c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
285c4e666bcSMatthias Ringwald     UNUSED(context);
286c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
2872c7ae6e1SMatthias Ringwald     UNUSED(data);
2882c7ae6e1SMatthias Ringwald     UNUSED(num_samples);
2892c7ae6e1SMatthias Ringwald     UNUSED(num_channels);
2902c7ae6e1SMatthias Ringwald 
2912c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
292c4e666bcSMatthias Ringwald 
293c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
294379c5f5fSMatthias Ringwald 
295379c5f5fSMatthias Ringwald     // samples in callback in host endianess, ready for playback
296379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
297dbb41bfeSMilanka Ringwald 
2982c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
299fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
300fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
301fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
302fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
303fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
3042c7ae6e1SMatthias Ringwald         wav_writer_close();
305fcb08cdbSMilanka Ringwald     }
3061bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3072c7ae6e1SMatthias Ringwald 
3081bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */
309fcb08cdbSMilanka Ringwald }
3101bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
3111bbecc2bSMatthias Ringwald 
3121bbecc2bSMatthias Ringwald 
3131bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
314fcb08cdbSMilanka Ringwald 
315fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
316c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
317c4e666bcSMatthias Ringwald 
318fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
319220eb563SMilanka Ringwald     hfp_msbc_init();
3202c7ae6e1SMatthias Ringwald 
3212c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3222c7ae6e1SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3232c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
3242c7ae6e1SMatthias Ringwald #endif
3252c7ae6e1SMatthias Ringwald 
3262b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
327b025eb5fSMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
3282b89dbfcSMatthias Ringwald #endif
329973d7173SMatthias Ringwald 
330d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
331d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
332d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
333d5e5f834SMatthias Ringwald #endif
3342b89dbfcSMatthias Ringwald 
3357294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
336d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
337d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
3387294d009SMatthias Ringwald #endif
339dbb41bfeSMilanka Ringwald 
340379c5f5fSMatthias Ringwald     audio_initialize(MSBC_SAMPLE_RATE);
341fcb08cdbSMilanka Ringwald }
342fcb08cdbSMilanka Ringwald 
343fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
344fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
345d5e5f834SMatthias Ringwald         if (msbc_file_in){
346d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
347d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
348d5e5f834SMatthias Ringwald         }
349fcb08cdbSMilanka Ringwald     }
350dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
351fcb08cdbSMilanka Ringwald }
3521bbecc2bSMatthias Ringwald #endif
353fcb08cdbSMilanka Ringwald 
354fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
355c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
356c4e666bcSMatthias Ringwald 
357fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
358c4e666bcSMatthias Ringwald 
3592c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
360c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3612c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
3622c7ae6e1SMatthias Ringwald #endif
363dbb41bfeSMilanka Ringwald 
364379c5f5fSMatthias Ringwald     audio_initialize(CVSD_SAMPLE_RATE);
365fbc7c9f2SMilanka Ringwald }
366fbc7c9f2SMilanka Ringwald 
367fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
368dbb41bfeSMilanka Ringwald     if (!num_samples_to_write) return;
3692c7ae6e1SMatthias Ringwald 
3705303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
3711f8694ccSMatthias Ringwald 
3721f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
3731f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
3741f8694ccSMatthias Ringwald         return;
3751f8694ccSMatthias Ringwald     }
3762c7ae6e1SMatthias Ringwald 
377c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
378379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
3795303ddeeSMatthias Ringwald 
3805303ddeeSMatthias Ringwald     // convert into host endian
3815303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
3825303ddeeSMatthias Ringwald     int i;
3835303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
3845303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
3855303ddeeSMatthias Ringwald     }
3865303ddeeSMatthias Ringwald 
387e36764ddSMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out);
3885303ddeeSMatthias Ringwald 
3892c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3902c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3912c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3922c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3932c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3942c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3952c7ae6e1SMatthias Ringwald         wav_writer_close();
3962c7ae6e1SMatthias Ringwald     }
3972c7ae6e1SMatthias Ringwald #endif
3982c7ae6e1SMatthias Ringwald 
399379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
400fcb08cdbSMilanka Ringwald }
401fcb08cdbSMilanka Ringwald 
4022c7ae6e1SMatthias Ringwald #endif
4032c7ae6e1SMatthias Ringwald 
4042c7ae6e1SMatthias Ringwald 
405fcb08cdbSMilanka Ringwald void sco_demo_close(void){
406c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
4072b89dbfcSMatthias Ringwald 
40826463303SMilanka Ringwald     printf("SCO demo statistics: ");
4091bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
41026463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4112c7ae6e1SMatthias 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);
4121bbecc2bSMatthias Ringwald     } else
4131bbecc2bSMatthias Ringwald #endif
4141bbecc2bSMatthias Ringwald     {
4152c7ae6e1SMatthias 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);
41626463303SMilanka Ringwald     }
41726463303SMilanka Ringwald 
4182c7ae6e1SMatthias Ringwald     negotiated_codec = -1;
4192c7ae6e1SMatthias Ringwald 
4202c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
4212c7ae6e1SMatthias Ringwald 
4222c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
4232c7ae6e1SMatthias Ringwald     wav_writer_close();
4242c7ae6e1SMatthias Ringwald #endif
4252c7ae6e1SMatthias Ringwald 
426379c5f5fSMatthias Ringwald     audio_terminate();
427fcb08cdbSMilanka Ringwald 
428fcb08cdbSMilanka Ringwald #endif
429fcb08cdbSMilanka Ringwald }
430fcb08cdbSMilanka Ringwald 
431fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
432fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
433fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
4342c7ae6e1SMatthias Ringwald 
4352b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
436220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4371bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
438fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
4391bbecc2bSMatthias Ringwald #endif
440fcb08cdbSMilanka Ringwald     } else {
441fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
442fcb08cdbSMilanka Ringwald     }
443fcb08cdbSMilanka Ringwald #endif
444fcb08cdbSMilanka Ringwald }
445fcb08cdbSMilanka Ringwald 
446f7c85330SMatthias Ringwald void sco_demo_init(void){
447f7c85330SMatthias Ringwald 	// status
4482b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
449379c5f5fSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
4502b89dbfcSMatthias Ringwald #endif
451f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
452f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
453379c5f5fSMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
454f7c85330SMatthias Ringwald #else
455f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
456f7c85330SMatthias Ringwald #endif
457f7c85330SMatthias Ringwald #endif
458f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
459f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
460f7c85330SMatthias Ringwald #endif
461f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
462f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
463f7c85330SMatthias Ringwald #endif
464f7c85330SMatthias Ringwald 
4652b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
466c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
467c4e666bcSMatthias Ringwald #else
468f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
4697294d009SMatthias Ringwald #endif
470f7c85330SMatthias Ringwald }
471f7c85330SMatthias Ringwald 
4721a919128SMatthias Ringwald void sco_report(void);
4731a919128SMatthias Ringwald void sco_report(void){
4744a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
4754a96141eSMatthias Ringwald }
476f7c85330SMatthias Ringwald 
477f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
478f7c85330SMatthias Ringwald 
479e1de95beSMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
480f7c85330SMatthias Ringwald 
481c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
482c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
483f7c85330SMatthias Ringwald 
484f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
485f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
486f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
4871bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
488220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
48901b2daf8SMatthias Ringwald 
490220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
491220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
492220eb563SMilanka Ringwald         }
493220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
494d5e5f834SMatthias Ringwald         if (msbc_file_out){
495d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
496d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
497d76591efSMatthias Ringwald         }
4987294d009SMatthias Ringwald 
499b025eb5fSMatthias Ringwald         sco_demo_msbc_fill_sine_audio_frame();
5001bbecc2bSMatthias Ringwald     } else
5011bbecc2bSMatthias Ringwald #endif
5021bbecc2bSMatthias Ringwald     {
503379c5f5fSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME;
504adaba9f3SMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]);
505220eb563SMilanka Ringwald     }
5061a919128SMatthias Ringwald #endif
5072b89dbfcSMatthias Ringwald 
5082b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5092b89dbfcSMatthias Ringwald 
5102b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO
5112b89dbfcSMatthias Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
5122b89dbfcSMatthias Ringwald         // MSBC
5132b89dbfcSMatthias Ringwald 
514379c5f5fSMatthias Ringwald         if (audio_input_paused){
515379c5f5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
516b025eb5fSMatthias Ringwald                 // resume sending
517379c5f5fSMatthias Ringwald                 audio_input_paused = 0;
5182b89dbfcSMatthias Ringwald             }
519b025eb5fSMatthias Ringwald         }
520b025eb5fSMatthias Ringwald 
521379c5f5fSMatthias Ringwald         if (!audio_input_paused){
522b025eb5fSMatthias Ringwald             int num_samples = hfp_msbc_num_audio_samples_per_frame();
523379c5f5fSMatthias Ringwald             if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert
524379c5f5fSMatthias 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)){
525379c5f5fSMatthias Ringwald                 int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
526b025eb5fSMatthias Ringwald                 uint32_t bytes_read;
527379c5f5fSMatthias 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.");
533379c5f5fSMatthias Ringwald             }
534379c5f5fSMatthias Ringwald         }
535379c5f5fSMatthias Ringwald 
536379c5f5fSMatthias Ringwald         if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
537b025eb5fSMatthias Ringwald             memset(sco_packet + 3, 0, sco_payload_length);
538379c5f5fSMatthias 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 
550379c5f5fSMatthias 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;
553379c5f5fSMatthias Ringwald         if (audio_input_paused){
554379c5f5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
5552b89dbfcSMatthias Ringwald                 // resume sending
556379c5f5fSMatthias 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];
563379c5f5fSMatthias Ringwald         if (!audio_input_paused){
5642b89dbfcSMatthias Ringwald             uint32_t bytes_read = 0;
565379c5f5fSMatthias 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);
583379c5f5fSMatthias Ringwald             audio_input_paused = 1;
5842b89dbfcSMatthias Ringwald         }
5852b89dbfcSMatthias Ringwald     }
5862b89dbfcSMatthias Ringwald #else
5872b89dbfcSMatthias Ringwald     // just send '0's
5882b89dbfcSMatthias Ringwald     memset(sco_packet + 3, 0, sco_payload_length);
5892b89dbfcSMatthias Ringwald #endif
5902b89dbfcSMatthias Ringwald #endif
5912b89dbfcSMatthias Ringwald 
592f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
59301b2daf8SMatthias Ringwald     // store packet counter-xxxx
59401b2daf8SMatthias Ringwald     snprintf((char *)&sco_packet[3], 5, "%04u", phase++);
59501b2daf8SMatthias Ringwald     uint8_t ascii = (phase & 0x0f) + 'a';
59601b2daf8SMatthias Ringwald     sco_packet[3+4] = '-';
59701b2daf8SMatthias Ringwald     memset(&sco_packet[3+5], ascii, sco_payload_length-5);
5981a919128SMatthias Ringwald #endif
5991a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
60038b2eaafSMatthias Ringwald     int j;
601c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
60238b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
603f7c85330SMatthias Ringwald     }
604f7c85330SMatthias Ringwald #endif
6051a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
6061a919128SMatthias Ringwald     int j;
607c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6081a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
6091a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
6101a919128SMatthias Ringwald     }
6111a919128SMatthias Ringwald #endif
6121a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
6131a919128SMatthias Ringwald     int j;
614c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6151a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
6161a919128SMatthias Ringwald     }
6171a919128SMatthias Ringwald     // additional hack
6181a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
6191a919128SMatthias Ringwald     (void) phase;
620f7c85330SMatthias Ringwald #endif
621220eb563SMilanka Ringwald 
6222b89dbfcSMatthias Ringwald     // test silence
6232b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
6242b89dbfcSMatthias Ringwald 
625c4e666bcSMatthias Ringwald     // set handle + flags
626c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
627c4e666bcSMatthias Ringwald     // set len
628c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
629c4e666bcSMatthias Ringwald     // finally send packet
630f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
631f7c85330SMatthias Ringwald 
632f7c85330SMatthias Ringwald     // request another send event
633f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
634f7c85330SMatthias Ringwald 
6354a96141eSMatthias Ringwald     count_sent++;
6361a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
6374a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
6381a919128SMatthias Ringwald #endif
639f7c85330SMatthias Ringwald }
640f7c85330SMatthias Ringwald 
641f7c85330SMatthias Ringwald /**
642f7c85330SMatthias Ringwald  * @brief Process received data
643f7c85330SMatthias Ringwald  */
6441a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
6451a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
6461a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
6471a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
6481a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
6491a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
6501a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
6511a919128SMatthias Ringwald 
652f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
653f7c85330SMatthias Ringwald 
654fcb08cdbSMilanka Ringwald     dump_data = 1;
6558b29cfc6SMatthias Ringwald 
6564a96141eSMatthias Ringwald     count_received++;
6571a919128SMatthias Ringwald     static uint32_t packets = 0;
6581a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
6591a919128SMatthias Ringwald     static uint32_t data_received = 0;
6601a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
6614a96141eSMatthias Ringwald 
6621a919128SMatthias Ringwald     data_received += size - 3;
6631a919128SMatthias Ringwald     packets++;
6641a919128SMatthias Ringwald     if (data_received > 100000){
665d4f907a6SMatthias 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);
6661a919128SMatthias Ringwald         crc_errors = 0;
6671a919128SMatthias Ringwald         byte_errors = 0;
6681a919128SMatthias Ringwald         data_received = 0;
6691a919128SMatthias Ringwald         packets = 0;
6701a919128SMatthias Ringwald     }
6714a96141eSMatthias Ringwald 
6722b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
673c4e666bcSMatthias Ringwald     switch (negotiated_codec){
6741bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
675c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
676fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
677c4e666bcSMatthias Ringwald             break;
6781bbecc2bSMatthias Ringwald #endif
679c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
680fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
681c4e666bcSMatthias Ringwald             break;
682c4e666bcSMatthias Ringwald         default:
683c4e666bcSMatthias Ringwald             break;
6848b29cfc6SMatthias Ringwald     }
685dbb41bfeSMilanka Ringwald     dump_data = 0;
6868b29cfc6SMatthias Ringwald #endif
6878b29cfc6SMatthias Ringwald 
68801b2daf8SMatthias Ringwald #if 0
689b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
6901a919128SMatthias Ringwald         crc_errors++;
69101b2daf8SMatthias Ringwald         printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
69201b2daf8SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
693f7c85330SMatthias Ringwald         return;
694f7c85330SMatthias Ringwald     }
69501b2daf8SMatthias Ringwald #endif
69601b2daf8SMatthias Ringwald 
6978b29cfc6SMatthias Ringwald     if (dump_data){
698f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
6991a919128SMatthias Ringwald         printf("data: ");
700f7c85330SMatthias Ringwald         int i;
701f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
702f7c85330SMatthias Ringwald             printf("%c", packet[i]);
703f7c85330SMatthias Ringwald         }
704f7c85330SMatthias Ringwald         printf("\n");
7058b29cfc6SMatthias Ringwald         dump_data = 0;
7061a919128SMatthias Ringwald #endif
7071a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
7081a919128SMatthias Ringwald         // colored hexdump with expected
7091a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
7101a919128SMatthias Ringwald         int i;
7111a919128SMatthias Ringwald         printf("data: ");
7121a919128SMatthias Ringwald         for (i=3;i<size;i++){
7131a919128SMatthias Ringwald             if (packet[i] != expected_byte){
7141a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7151a919128SMatthias Ringwald             } else {
7161a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7171a919128SMatthias Ringwald             }
7181a919128SMatthias Ringwald             expected_byte = packet[i]+1;
7191a919128SMatthias Ringwald         }
7201a919128SMatthias Ringwald         printf("\n");
7211a919128SMatthias Ringwald #endif
722a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
7231a919128SMatthias Ringwald         int i;
7241a919128SMatthias Ringwald         int contains_error = 0;
7251a919128SMatthias Ringwald         for (i=3;i<size;i++){
7261a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7271a919128SMatthias Ringwald                 contains_error = 1;
7281a919128SMatthias Ringwald                 byte_errors++;
7291a919128SMatthias Ringwald             }
7301a919128SMatthias Ringwald         }
7311a919128SMatthias Ringwald         if (contains_error){
7321a919128SMatthias Ringwald             printf("data: ");
7331a919128SMatthias Ringwald             for (i=0;i<3;i++){
7341a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7351a919128SMatthias Ringwald             }
7361a919128SMatthias Ringwald             for (i=3;i<size;i++){
7371a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7381a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7391a919128SMatthias Ringwald                 } else {
7401a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
7411a919128SMatthias Ringwald                 }
7421a919128SMatthias Ringwald             }
7431a919128SMatthias Ringwald             printf("\n");
7441a919128SMatthias Ringwald         }
745f7c85330SMatthias Ringwald #endif
7468b29cfc6SMatthias Ringwald     }
747f7c85330SMatthias Ringwald }
748