xref: /btstack/example/sco_demo_util.c (revision 859f2bc59e250ae08419cda9fa43c25dc9b5b2c1)
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
69d365bb51SMatthias 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 
74f55ac442SMatthias Ringwald // #define ENABLE_SCO_STEREO_PLAYBACK
75f55ac442SMatthias Ringwald 
76d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
772c7ae6e1SMatthias Ringwald // length and name of wav file on disk
78c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
798b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
80c4e666bcSMatthias Ringwald 
81c4e666bcSMatthias Ringwald // name of sbc test files
82d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME       "sco_output.msbc"
832308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME        "sco_input.msbc"
84*859f2bc5SMatthias Ringwald #endif
85*859f2bc5SMatthias Ringwald 
86220eb563SMilanka Ringwald 
87c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
88c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS    50
89c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS    50
908b29cfc6SMatthias Ringwald 
91c4e666bcSMatthias Ringwald // constants
92c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
93c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE        8000
94c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE        16000
95379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
96f7c85330SMatthias Ringwald 
97379c5f5fSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
98379c5f5fSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
99f7c85330SMatthias Ringwald 
1002b89dbfcSMatthias Ringwald // output
101379c5f5fSMatthias Ringwald 
102d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
103d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
104379c5f5fSMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
105379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
106d861f4bfSMatthias Ringwald #endif
107d861f4bfSMatthias Ringwald 
1082b89dbfcSMatthias Ringwald 
1092b89dbfcSMatthias Ringwald // input
1102b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
111379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
112379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
113379c5f5fSMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2*8000];  // full second input buffer
114379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
115f7c85330SMatthias Ringwald #endif
116f7c85330SMatthias Ringwald 
117fcb08cdbSMilanka Ringwald static int dump_data = 1;
118fcb08cdbSMilanka Ringwald static int count_sent = 0;
119fcb08cdbSMilanka Ringwald static int count_received = 0;
120c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
121c4e666bcSMatthias Ringwald 
1221bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
123379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
124*859f2bc5SMatthias Ringwald 
125*859f2bc5SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
126*859f2bc5SMatthias Ringwald FILE * msbc_file_in;
127*859f2bc5SMatthias Ringwald FILE * msbc_file_out;
128*859f2bc5SMatthias Ringwald #endif
129*859f2bc5SMatthias Ringwald 
1301bbecc2bSMatthias Ringwald #endif
1311bbecc2bSMatthias Ringwald 
132379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
133379c5f5fSMatthias Ringwald 
134379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8)
135fcb08cdbSMilanka Ringwald 
1362b89dbfcSMatthias Ringwald int num_samples_to_write;
1372b89dbfcSMatthias Ringwald int num_audio_frames;
138249d94cfSMatthias Ringwald unsigned int phase;
1392b89dbfcSMatthias Ringwald 
140f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
141d6a06398SMatthias Ringwald 
1427556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz
143c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
1447556ab9fSMatthias Ringwald      0,   3135,   6237,   9270,  12202,  14999,  17633,  20073,  22294,  24270,
1457556ab9fSMatthias Ringwald  25980,  27406,  28531,  29344,  29835,  30000,  29835,  29344,  28531,  27406,
1467556ab9fSMatthias Ringwald  25980,  24270,  22294,  20073,  17633,  14999,  12202,   9270,   6237,   3135,
1477556ab9fSMatthias Ringwald      0,  -3135,  -6237,  -9270, -12202, -14999, -17633, -20073, -22294, -24270,
1487556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406,
1497556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202,  -9270,  -6237,  -3135,
15035fd3fb9SMatthias Ringwald };
15135fd3fb9SMatthias Ringwald 
15259c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
153adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){
154249d94cfSMatthias Ringwald     unsigned int i;
15559c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
15659c97ae1SMatthias Ringwald         int16_t sample = sine_int16_at_16000hz[phase];
157adaba9f3SMatthias Ringwald         little_endian_store_16(data, i * 2, sample);
15859c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
15959c97ae1SMatthias Ringwald         phase += 2;
160c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
16135fd3fb9SMatthias Ringwald             phase = 0;
16235fd3fb9SMatthias Ringwald         }
16335fd3fb9SMatthias Ringwald     }
16435fd3fb9SMatthias Ringwald }
16535fd3fb9SMatthias Ringwald 
1661bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
1671bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
168249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){
169249d94cfSMatthias Ringwald     unsigned int i;
1701bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
1711bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
1721bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1731bbecc2bSMatthias Ringwald             phase = 0;
1741bbecc2bSMatthias Ringwald         }
1751bbecc2bSMatthias Ringwald     }
1761bbecc2bSMatthias Ringwald }
1771bbecc2bSMatthias Ringwald 
178b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){
17935fd3fb9SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
18035fd3fb9SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
181379c5f5fSMatthias Ringwald     if (num_samples > MAX_NUM_MSBC_SAMPLES) return;
182379c5f5fSMatthias Ringwald     int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
18359c97ae1SMatthias Ringwald     sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer);
18435fd3fb9SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
18535fd3fb9SMatthias Ringwald     num_audio_frames++;
18635fd3fb9SMatthias Ringwald }
1872b89dbfcSMatthias Ringwald #endif
1881bbecc2bSMatthias Ringwald #endif
189dbb41bfeSMilanka Ringwald 
190d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
191d861f4bfSMatthias Ringwald 
192379c5f5fSMatthias Ringwald static void playback_callback(int16_t * buffer, uint16_t num_samples){
1932b89dbfcSMatthias Ringwald 
194be030f50SMilanka Ringwald     uint32_t prebuffer_bytes;
195c4e666bcSMatthias Ringwald     switch (negotiated_codec){
196c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
197c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
198c4e666bcSMatthias Ringwald             break;
199c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
200c4e666bcSMatthias Ringwald         default:
201379c5f5fSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
202c4e666bcSMatthias Ringwald             break;
203dbb41bfeSMilanka Ringwald     }
204dbb41bfeSMilanka Ringwald 
205c4e666bcSMatthias Ringwald     // fill with silence while paused
206379c5f5fSMatthias Ringwald     if (audio_output_paused){
207379c5f5fSMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){
208f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
209f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME * 2);
210f55ac442SMatthias Ringwald #else
211f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
212f55ac442SMatthias Ringwald #endif
213379c5f5fSMatthias Ringwald            return;
214dbb41bfeSMilanka Ringwald         } else {
215c4e666bcSMatthias Ringwald             // resume playback
216379c5f5fSMatthias Ringwald             audio_output_paused = 0;
217dbb41bfeSMilanka Ringwald         }
218c4e666bcSMatthias Ringwald     }
219c4e666bcSMatthias Ringwald 
220c4e666bcSMatthias Ringwald     // get data from ringbuffer
221c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
222f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
223f55ac442SMatthias Ringwald     while (num_samples){
224f55ac442SMatthias Ringwald         int16_t temp[16];
225f55ac442SMatthias Ringwald         unsigned int bytes_to_read = btstack_min(num_samples * BYTES_PER_FRAME, sizeof(temp));
226f55ac442SMatthias Ringwald         btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) &temp[0], bytes_to_read, &bytes_read);
227f55ac442SMatthias Ringwald         if (bytes_read == 0) break;
228f55ac442SMatthias Ringwald         unsigned int i;
229f55ac442SMatthias Ringwald         for (i=0;i<bytes_read / BYTES_PER_FRAME;i++){
230f55ac442SMatthias Ringwald             *buffer++ = temp[i];
231f55ac442SMatthias Ringwald             *buffer++ = temp[i];
232f55ac442SMatthias Ringwald             num_samples--;
233f55ac442SMatthias Ringwald         }
234f55ac442SMatthias Ringwald     }
235f55ac442SMatthias Ringwald #else
236f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
237f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
238f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
239f55ac442SMatthias Ringwald #endif
240c4e666bcSMatthias Ringwald 
241c4e666bcSMatthias Ringwald     // fill with 0 if not enough
242f55ac442SMatthias Ringwald     if (num_samples){
243f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
244f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME * 2);
245f55ac442SMatthias Ringwald #else
246f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
247f55ac442SMatthias Ringwald #endif
248379c5f5fSMatthias Ringwald         audio_output_paused = 1;
249c4e666bcSMatthias Ringwald     }
250379c5f5fSMatthias Ringwald }
2518b29cfc6SMatthias Ringwald 
252379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
253379c5f5fSMatthias Ringwald static void recording_callback(const int16_t * buffer, uint16_t num_samples){
254379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
255c4e666bcSMatthias Ringwald }
256379c5f5fSMatthias Ringwald #endif
257c4e666bcSMatthias Ringwald 
258c4e666bcSMatthias Ringwald // return 1 if ok
259379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
260c4e666bcSMatthias Ringwald 
261d365bb51SMatthias Ringwald     // -- output -- //
262d365bb51SMatthias Ringwald 
263379c5f5fSMatthias Ringwald     // init buffers
264379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
265379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2662b89dbfcSMatthias Ringwald 
267d365bb51SMatthias Ringwald     // config and setup audio playback
268d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
269d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2702b89dbfcSMatthias Ringwald 
271f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
272f55ac442SMatthias Ringwald     audio_sink->init(2, sample_rate, &playback_callback);
273f55ac442SMatthias Ringwald #else
274d365bb51SMatthias Ringwald     audio_sink->init(1, sample_rate, &playback_callback);
275f55ac442SMatthias Ringwald #endif
276d365bb51SMatthias Ringwald     audio_sink->start_stream();
277379c5f5fSMatthias Ringwald 
278379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
279d365bb51SMatthias Ringwald 
280d365bb51SMatthias Ringwald     // -- input -- //
281d365bb51SMatthias Ringwald 
282379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
283d365bb51SMatthias Ringwald     // init buffers
284d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
285d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
286d365bb51SMatthias Ringwald 
287d365bb51SMatthias Ringwald     // config and setup audio recording
288d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
289d365bb51SMatthias Ringwald     if (!audio_source) return 0;
290d365bb51SMatthias Ringwald 
291d365bb51SMatthias Ringwald     audio_source->init(1, sample_rate, &recording_callback);
292d365bb51SMatthias Ringwald     audio_source->start_stream();
293d365bb51SMatthias Ringwald 
294379c5f5fSMatthias Ringwald     audio_input_paused  = 1;
2952b89dbfcSMatthias Ringwald #endif
2962b89dbfcSMatthias Ringwald 
297c4e666bcSMatthias Ringwald     return 1;
298c4e666bcSMatthias Ringwald }
2992b89dbfcSMatthias Ringwald 
300379c5f5fSMatthias Ringwald static void audio_terminate(void){
301d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
302d365bb51SMatthias Ringwald     if (!audio_sink) return;
303d365bb51SMatthias Ringwald     audio_sink->close();
304d365bb51SMatthias Ringwald 
305d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
306d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
307d365bb51SMatthias Ringwald     if (!audio_source) return;
308d365bb51SMatthias Ringwald     audio_source->close();
309d365bb51SMatthias Ringwald #endif
3102b89dbfcSMatthias Ringwald }
311c4e666bcSMatthias Ringwald 
3121bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
313d861f4bfSMatthias Ringwald 
314c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
315c4e666bcSMatthias Ringwald     UNUSED(context);
316c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
3172c7ae6e1SMatthias Ringwald     UNUSED(data);
3182c7ae6e1SMatthias Ringwald     UNUSED(num_samples);
3192c7ae6e1SMatthias Ringwald     UNUSED(num_channels);
3202c7ae6e1SMatthias Ringwald 
3212c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
322c4e666bcSMatthias Ringwald 
323c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
324379c5f5fSMatthias Ringwald 
325379c5f5fSMatthias Ringwald     // samples in callback in host endianess, ready for playback
326379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
327dbb41bfeSMilanka Ringwald 
3282c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
329fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
330fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
331fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
332fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
333fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
3342c7ae6e1SMatthias Ringwald         wav_writer_close();
335fcb08cdbSMilanka Ringwald     }
3361bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3372c7ae6e1SMatthias Ringwald 
3381bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */
339fcb08cdbSMilanka Ringwald }
3401bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
3411bbecc2bSMatthias Ringwald 
3421bbecc2bSMatthias Ringwald 
3431bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
344fcb08cdbSMilanka Ringwald 
345fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
346c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
347c4e666bcSMatthias Ringwald 
348fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
349220eb563SMilanka Ringwald     hfp_msbc_init();
3502c7ae6e1SMatthias Ringwald 
3512c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3522c7ae6e1SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3532c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
3542c7ae6e1SMatthias Ringwald #endif
3552c7ae6e1SMatthias Ringwald 
3562b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
357b025eb5fSMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
3582b89dbfcSMatthias Ringwald #endif
359973d7173SMatthias Ringwald 
360d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
361d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
362d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
363d5e5f834SMatthias Ringwald #endif
3642b89dbfcSMatthias Ringwald 
3657294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
366d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
367d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
3687294d009SMatthias Ringwald #endif
369dbb41bfeSMilanka Ringwald 
370379c5f5fSMatthias Ringwald     audio_initialize(MSBC_SAMPLE_RATE);
371fcb08cdbSMilanka Ringwald }
372fcb08cdbSMilanka Ringwald 
373fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
374*859f2bc5SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
375fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
376d5e5f834SMatthias Ringwald         if (msbc_file_in){
377d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
378d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
379d5e5f834SMatthias Ringwald         }
380fcb08cdbSMilanka Ringwald     }
381*859f2bc5SMatthias Ringwald #endif
382dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
383fcb08cdbSMilanka Ringwald }
3841bbecc2bSMatthias Ringwald #endif
385fcb08cdbSMilanka Ringwald 
386fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
387c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
388c4e666bcSMatthias Ringwald 
389fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
390c4e666bcSMatthias Ringwald 
3912c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
392c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3932c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
3942c7ae6e1SMatthias Ringwald #endif
395dbb41bfeSMilanka Ringwald 
396379c5f5fSMatthias Ringwald     audio_initialize(CVSD_SAMPLE_RATE);
397fbc7c9f2SMilanka Ringwald }
398fbc7c9f2SMilanka Ringwald 
399fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
4002c7ae6e1SMatthias Ringwald 
4015303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
4021f8694ccSMatthias Ringwald 
4031f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
4041f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
4051f8694ccSMatthias Ringwald         return;
4061f8694ccSMatthias Ringwald     }
4072c7ae6e1SMatthias Ringwald 
408c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
409379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
4105303ddeeSMatthias Ringwald 
4115303ddeeSMatthias Ringwald     // convert into host endian
4125303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
4135303ddeeSMatthias Ringwald     int i;
4145303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
4155303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
4165303ddeeSMatthias Ringwald     }
4175303ddeeSMatthias Ringwald 
418e36764ddSMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out);
4195303ddeeSMatthias Ringwald 
4202c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
4212c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
4222c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
4232c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
4242c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
4252c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
4262c7ae6e1SMatthias Ringwald         wav_writer_close();
4272c7ae6e1SMatthias Ringwald     }
4282c7ae6e1SMatthias Ringwald #endif
4292c7ae6e1SMatthias Ringwald 
430379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
431fcb08cdbSMilanka Ringwald }
432fcb08cdbSMilanka Ringwald 
4332c7ae6e1SMatthias Ringwald #endif
4342c7ae6e1SMatthias Ringwald 
4352c7ae6e1SMatthias Ringwald 
436fcb08cdbSMilanka Ringwald void sco_demo_close(void){
437c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
4382b89dbfcSMatthias Ringwald 
43926463303SMilanka Ringwald     printf("SCO demo statistics: ");
4401bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
44126463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4422c7ae6e1SMatthias 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);
4431bbecc2bSMatthias Ringwald     } else
4441bbecc2bSMatthias Ringwald #endif
4451bbecc2bSMatthias Ringwald     {
4462c7ae6e1SMatthias 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);
44726463303SMilanka Ringwald     }
44826463303SMilanka Ringwald 
4492c7ae6e1SMatthias Ringwald     negotiated_codec = -1;
4502c7ae6e1SMatthias Ringwald 
4512c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
4522c7ae6e1SMatthias Ringwald 
4532c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
4542c7ae6e1SMatthias Ringwald     wav_writer_close();
4552c7ae6e1SMatthias Ringwald #endif
4562c7ae6e1SMatthias Ringwald 
457379c5f5fSMatthias Ringwald     audio_terminate();
458fcb08cdbSMilanka Ringwald 
459fcb08cdbSMilanka Ringwald #endif
460fcb08cdbSMilanka Ringwald }
461fcb08cdbSMilanka Ringwald 
462fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
463fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
464fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
4652c7ae6e1SMatthias Ringwald 
4662b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
467220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4681bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
469fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
4701bbecc2bSMatthias Ringwald #endif
471fcb08cdbSMilanka Ringwald     } else {
472fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
473fcb08cdbSMilanka Ringwald     }
474fcb08cdbSMilanka Ringwald #endif
475fcb08cdbSMilanka Ringwald }
476fcb08cdbSMilanka Ringwald 
477f7c85330SMatthias Ringwald void sco_demo_init(void){
478f7c85330SMatthias Ringwald 	// status
4792b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
480379c5f5fSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
4812b89dbfcSMatthias Ringwald #endif
482f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
4831befbc1eSMatthias Ringwald     if (btstack_audio_sink_get_instance()){
484379c5f5fSMatthias Ringwald         printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
4851befbc1eSMatthias Ringwald     } else {
486f7c85330SMatthias Ringwald         printf("SCO Demo: Sending sine wave, hexdump received data.\n");
4871befbc1eSMatthias Ringwald     }
488f7c85330SMatthias Ringwald #endif
489f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
490f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
491f7c85330SMatthias Ringwald #endif
492f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
493f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
494f7c85330SMatthias Ringwald #endif
495f7c85330SMatthias Ringwald 
4962b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
497c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
498c4e666bcSMatthias Ringwald #else
499f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
5007294d009SMatthias Ringwald #endif
501f7c85330SMatthias Ringwald }
502f7c85330SMatthias Ringwald 
5031a919128SMatthias Ringwald void sco_report(void);
5041a919128SMatthias Ringwald void sco_report(void){
5054a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
5064a96141eSMatthias Ringwald }
507f7c85330SMatthias Ringwald 
508f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
509f7c85330SMatthias Ringwald 
510e1de95beSMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
511f7c85330SMatthias Ringwald 
512c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
513c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
514f7c85330SMatthias Ringwald 
515f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
516f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
517f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
5181bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
519220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
52001b2daf8SMatthias Ringwald 
521220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
522220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
523220eb563SMilanka Ringwald         }
524220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
525*859f2bc5SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
526d5e5f834SMatthias Ringwald         if (msbc_file_out){
527d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
528d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
529d76591efSMatthias Ringwald         }
530*859f2bc5SMatthias Ringwald #endif
531b025eb5fSMatthias Ringwald         sco_demo_msbc_fill_sine_audio_frame();
5321bbecc2bSMatthias Ringwald     } else
5331bbecc2bSMatthias Ringwald #endif
5341bbecc2bSMatthias Ringwald     {
535379c5f5fSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME;
536adaba9f3SMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]);
537220eb563SMilanka Ringwald     }
5381a919128SMatthias Ringwald #endif
5392b89dbfcSMatthias Ringwald 
5402b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5412b89dbfcSMatthias Ringwald 
5421befbc1eSMatthias Ringwald     if (btstack_audio_source_get_instance()){
5431befbc1eSMatthias Ringwald 
5442b89dbfcSMatthias Ringwald         if (negotiated_codec == HFP_CODEC_MSBC){
5452b89dbfcSMatthias Ringwald             // MSBC
5462b89dbfcSMatthias Ringwald 
547379c5f5fSMatthias Ringwald             if (audio_input_paused){
548379c5f5fSMatthias Ringwald                 if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
549b025eb5fSMatthias Ringwald                     // resume sending
550379c5f5fSMatthias Ringwald                     audio_input_paused = 0;
5512b89dbfcSMatthias Ringwald                 }
552b025eb5fSMatthias Ringwald             }
553b025eb5fSMatthias Ringwald 
554379c5f5fSMatthias Ringwald             if (!audio_input_paused){
555b025eb5fSMatthias Ringwald                 int num_samples = hfp_msbc_num_audio_samples_per_frame();
556379c5f5fSMatthias Ringwald                 if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert
557379c5f5fSMatthias 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)){
558379c5f5fSMatthias Ringwald                     int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
559b025eb5fSMatthias Ringwald                     uint32_t bytes_read;
560379c5f5fSMatthias Ringwald                     btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
561b025eb5fSMatthias Ringwald                     hfp_msbc_encode_audio_frame(sample_buffer);
562b025eb5fSMatthias Ringwald                     num_audio_frames++;
563b025eb5fSMatthias Ringwald                 }
564b025eb5fSMatthias Ringwald                 if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
565b025eb5fSMatthias Ringwald                     log_error("mSBC stream should not be empty.");
566379c5f5fSMatthias Ringwald                 }
567379c5f5fSMatthias Ringwald             }
568379c5f5fSMatthias Ringwald 
569379c5f5fSMatthias Ringwald             if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
570b025eb5fSMatthias Ringwald                 memset(sco_packet + 3, 0, sco_payload_length);
571379c5f5fSMatthias Ringwald                 audio_input_paused = 1;
572b025eb5fSMatthias Ringwald             } else {
5732b89dbfcSMatthias Ringwald                 hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
5742b89dbfcSMatthias Ringwald                 if (msbc_file_out){
5752b89dbfcSMatthias Ringwald                     // log outgoing mSBC data for testing
5762b89dbfcSMatthias Ringwald                     fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
5772b89dbfcSMatthias Ringwald                 }
578b025eb5fSMatthias Ringwald             }
5792b89dbfcSMatthias Ringwald 
5802b89dbfcSMatthias Ringwald         } else {
5812b89dbfcSMatthias Ringwald             // CVSD
5822b89dbfcSMatthias Ringwald 
583379c5f5fSMatthias 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));
5842b89dbfcSMatthias Ringwald             // fill with silence while paused
5852b89dbfcSMatthias Ringwald             int bytes_to_copy = sco_payload_length;
586379c5f5fSMatthias Ringwald             if (audio_input_paused){
587379c5f5fSMatthias Ringwald                 if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
5882b89dbfcSMatthias Ringwald                     // resume sending
589379c5f5fSMatthias Ringwald                     audio_input_paused = 0;
5902b89dbfcSMatthias Ringwald                 }
5912b89dbfcSMatthias Ringwald             }
5922b89dbfcSMatthias Ringwald 
5932b89dbfcSMatthias Ringwald             // get data from ringbuffer
5942b89dbfcSMatthias Ringwald             uint16_t pos = 0;
5958fd6902dSMatthias Ringwald             uint8_t * sample_data = &sco_packet[3];
596379c5f5fSMatthias Ringwald             if (!audio_input_paused){
5972b89dbfcSMatthias Ringwald                 uint32_t bytes_read = 0;
598379c5f5fSMatthias Ringwald                 btstack_ring_buffer_read(&audio_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
5998fd6902dSMatthias Ringwald                 // flip 16 on big endian systems
6008fd6902dSMatthias Ringwald                 // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
6018fd6902dSMatthias Ringwald                 if (btstack_is_big_endian()){
6028d3be402SMatthias Ringwald                     unsigned int i;
6038fd6902dSMatthias Ringwald                     for (i=0;i<bytes_read;i+=2){
6048fd6902dSMatthias Ringwald                         uint8_t tmp        = sample_data[i*2];
6058fd6902dSMatthias Ringwald                         sample_data[i*2]   = sample_data[i*2+1];
6068fd6902dSMatthias Ringwald                         sample_data[i*2+1] = tmp;
6078fd6902dSMatthias Ringwald                     }
6088fd6902dSMatthias Ringwald                 }
6092b89dbfcSMatthias Ringwald                 bytes_to_copy -= bytes_read;
6102b89dbfcSMatthias Ringwald                 pos           += bytes_read;
6112b89dbfcSMatthias Ringwald             }
6122b89dbfcSMatthias Ringwald 
6132b89dbfcSMatthias Ringwald             // fill with 0 if not enough
6142b89dbfcSMatthias Ringwald             if (bytes_to_copy){
6158fd6902dSMatthias Ringwald                 memset(sample_data + pos, 0, bytes_to_copy);
616379c5f5fSMatthias Ringwald                 audio_input_paused = 1;
6172b89dbfcSMatthias Ringwald             }
6182b89dbfcSMatthias Ringwald         }
6191befbc1eSMatthias Ringwald     }
6201befbc1eSMatthias Ringwald     else {
6212b89dbfcSMatthias Ringwald         // just send '0's
6222b89dbfcSMatthias Ringwald         memset(sco_packet + 3, 0, sco_payload_length);
6231befbc1eSMatthias Ringwald     }
6242b89dbfcSMatthias Ringwald #endif
6252b89dbfcSMatthias Ringwald 
626f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
62701b2daf8SMatthias Ringwald     // store packet counter-xxxx
62801b2daf8SMatthias Ringwald     snprintf((char *)&sco_packet[3], 5, "%04u", phase++);
62901b2daf8SMatthias Ringwald     uint8_t ascii = (phase & 0x0f) + 'a';
63001b2daf8SMatthias Ringwald     sco_packet[3+4] = '-';
63101b2daf8SMatthias Ringwald     memset(&sco_packet[3+5], ascii, sco_payload_length-5);
6321a919128SMatthias Ringwald #endif
6331a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
63438b2eaafSMatthias Ringwald     int j;
635c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
63638b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
637f7c85330SMatthias Ringwald     }
638f7c85330SMatthias Ringwald #endif
6391a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
6401a919128SMatthias Ringwald     int j;
641c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6421a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
6431a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
6441a919128SMatthias Ringwald     }
6451a919128SMatthias Ringwald #endif
6461a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
6471a919128SMatthias Ringwald     int j;
648c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6491a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
6501a919128SMatthias Ringwald     }
6511a919128SMatthias Ringwald     // additional hack
6521a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
6531a919128SMatthias Ringwald     (void) phase;
654f7c85330SMatthias Ringwald #endif
655220eb563SMilanka Ringwald 
6562b89dbfcSMatthias Ringwald     // test silence
6572b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
6582b89dbfcSMatthias Ringwald 
659c4e666bcSMatthias Ringwald     // set handle + flags
660c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
661c4e666bcSMatthias Ringwald     // set len
662c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
663c4e666bcSMatthias Ringwald     // finally send packet
664f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
665f7c85330SMatthias Ringwald 
666f7c85330SMatthias Ringwald     // request another send event
667f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
668f7c85330SMatthias Ringwald 
6694a96141eSMatthias Ringwald     count_sent++;
6701a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
6714a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
6721a919128SMatthias Ringwald #endif
673f7c85330SMatthias Ringwald }
674f7c85330SMatthias Ringwald 
675f7c85330SMatthias Ringwald /**
676f7c85330SMatthias Ringwald  * @brief Process received data
677f7c85330SMatthias Ringwald  */
6781a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
6791a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
6801a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
6811a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
6821a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
6831a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
6841a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
6851a919128SMatthias Ringwald 
686f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
687f7c85330SMatthias Ringwald 
688fcb08cdbSMilanka Ringwald     dump_data = 1;
6898b29cfc6SMatthias Ringwald 
6904a96141eSMatthias Ringwald     count_received++;
6911a919128SMatthias Ringwald     static uint32_t packets = 0;
6921a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
6931a919128SMatthias Ringwald     static uint32_t data_received = 0;
6941a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
6954a96141eSMatthias Ringwald 
6961a919128SMatthias Ringwald     data_received += size - 3;
6971a919128SMatthias Ringwald     packets++;
6981a919128SMatthias Ringwald     if (data_received > 100000){
699d4f907a6SMatthias 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);
7001a919128SMatthias Ringwald         crc_errors = 0;
7011a919128SMatthias Ringwald         byte_errors = 0;
7021a919128SMatthias Ringwald         data_received = 0;
7031a919128SMatthias Ringwald         packets = 0;
7041a919128SMatthias Ringwald     }
7054a96141eSMatthias Ringwald 
7062b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
707c4e666bcSMatthias Ringwald     switch (negotiated_codec){
7081bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
709c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
710fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
711c4e666bcSMatthias Ringwald             break;
7121bbecc2bSMatthias Ringwald #endif
713c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
714fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
715c4e666bcSMatthias Ringwald             break;
716c4e666bcSMatthias Ringwald         default:
717c4e666bcSMatthias Ringwald             break;
7188b29cfc6SMatthias Ringwald     }
719dbb41bfeSMilanka Ringwald     dump_data = 0;
7208b29cfc6SMatthias Ringwald #endif
7218b29cfc6SMatthias Ringwald 
72201b2daf8SMatthias Ringwald #if 0
723b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
7241a919128SMatthias Ringwald         crc_errors++;
72501b2daf8SMatthias Ringwald         printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
72601b2daf8SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
727f7c85330SMatthias Ringwald         return;
728f7c85330SMatthias Ringwald     }
72901b2daf8SMatthias Ringwald #endif
73001b2daf8SMatthias Ringwald 
7318b29cfc6SMatthias Ringwald     if (dump_data){
732f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
7331a919128SMatthias Ringwald         printf("data: ");
734f7c85330SMatthias Ringwald         int i;
735f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
736f7c85330SMatthias Ringwald             printf("%c", packet[i]);
737f7c85330SMatthias Ringwald         }
738f7c85330SMatthias Ringwald         printf("\n");
7398b29cfc6SMatthias Ringwald         dump_data = 0;
7401a919128SMatthias Ringwald #endif
7411a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
7421a919128SMatthias Ringwald         // colored hexdump with expected
7431a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
7441a919128SMatthias Ringwald         int i;
7451a919128SMatthias Ringwald         printf("data: ");
7461a919128SMatthias Ringwald         for (i=3;i<size;i++){
7471a919128SMatthias Ringwald             if (packet[i] != expected_byte){
7481a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7491a919128SMatthias Ringwald             } else {
7501a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7511a919128SMatthias Ringwald             }
7521a919128SMatthias Ringwald             expected_byte = packet[i]+1;
7531a919128SMatthias Ringwald         }
7541a919128SMatthias Ringwald         printf("\n");
7551a919128SMatthias Ringwald #endif
756a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
7571a919128SMatthias Ringwald         int i;
7581a919128SMatthias Ringwald         int contains_error = 0;
7591a919128SMatthias Ringwald         for (i=3;i<size;i++){
7601a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7611a919128SMatthias Ringwald                 contains_error = 1;
7621a919128SMatthias Ringwald                 byte_errors++;
7631a919128SMatthias Ringwald             }
7641a919128SMatthias Ringwald         }
7651a919128SMatthias Ringwald         if (contains_error){
7661a919128SMatthias Ringwald             printf("data: ");
7671a919128SMatthias Ringwald             for (i=0;i<3;i++){
7681a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7691a919128SMatthias Ringwald             }
7701a919128SMatthias Ringwald             for (i=3;i<size;i++){
7711a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7721a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7731a919128SMatthias Ringwald                 } else {
7741a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
7751a919128SMatthias Ringwald                 }
7761a919128SMatthias Ringwald             }
7771a919128SMatthias Ringwald             printf("\n");
7781a919128SMatthias Ringwald         }
779f7c85330SMatthias Ringwald #endif
7808b29cfc6SMatthias Ringwald     }
781f7c85330SMatthias Ringwald }
782