xref: /btstack/example/sco_demo_util.c (revision 1befbc1ef6c3889038fea82e0707172f28db9b58)
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"
80d4f907a6SMatthias Ringwald #endif
81c4e666bcSMatthias Ringwald 
82c4e666bcSMatthias Ringwald // name of sbc test files
83d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME       "sco_output.msbc"
842308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME        "sco_input.msbc"
85220eb563SMilanka Ringwald 
86c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
87c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS    50
88c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS    50
898b29cfc6SMatthias Ringwald 
90c4e666bcSMatthias Ringwald // constants
91c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
92c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE        8000
93c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE        16000
94379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
95f7c85330SMatthias Ringwald 
96379c5f5fSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
97379c5f5fSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
98f7c85330SMatthias Ringwald 
992b89dbfcSMatthias Ringwald // output
100379c5f5fSMatthias Ringwald 
101d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
102d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
103379c5f5fSMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
104379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
105d861f4bfSMatthias Ringwald #endif
106d861f4bfSMatthias Ringwald 
1072b89dbfcSMatthias Ringwald 
1082b89dbfcSMatthias Ringwald // input
1092b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
110379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
111379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
112379c5f5fSMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2*8000];  // full second input buffer
113379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
114f7c85330SMatthias Ringwald #endif
115f7c85330SMatthias Ringwald 
116fcb08cdbSMilanka Ringwald static int dump_data = 1;
117fcb08cdbSMilanka Ringwald static int count_sent = 0;
118fcb08cdbSMilanka Ringwald static int count_received = 0;
119c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
120c4e666bcSMatthias Ringwald 
1211bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
122379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
1231bbecc2bSMatthias Ringwald #endif
1241bbecc2bSMatthias Ringwald 
125379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
126379c5f5fSMatthias Ringwald 
127379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8)
128fcb08cdbSMilanka Ringwald 
1291bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
130d5e5f834SMatthias Ringwald FILE * msbc_file_in;
131d5e5f834SMatthias Ringwald FILE * msbc_file_out;
1321bbecc2bSMatthias Ringwald #endif
1337294d009SMatthias Ringwald 
1342b89dbfcSMatthias Ringwald int num_samples_to_write;
1352b89dbfcSMatthias Ringwald int num_audio_frames;
136249d94cfSMatthias Ringwald unsigned int phase;
1372b89dbfcSMatthias Ringwald 
138f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
139d6a06398SMatthias Ringwald 
1407556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz
141c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
1427556ab9fSMatthias Ringwald      0,   3135,   6237,   9270,  12202,  14999,  17633,  20073,  22294,  24270,
1437556ab9fSMatthias Ringwald  25980,  27406,  28531,  29344,  29835,  30000,  29835,  29344,  28531,  27406,
1447556ab9fSMatthias Ringwald  25980,  24270,  22294,  20073,  17633,  14999,  12202,   9270,   6237,   3135,
1457556ab9fSMatthias Ringwald      0,  -3135,  -6237,  -9270, -12202, -14999, -17633, -20073, -22294, -24270,
1467556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406,
1477556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202,  -9270,  -6237,  -3135,
14835fd3fb9SMatthias Ringwald };
14935fd3fb9SMatthias Ringwald 
15059c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
151adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){
152249d94cfSMatthias Ringwald     unsigned int i;
15359c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
15459c97ae1SMatthias Ringwald         int16_t sample = sine_int16_at_16000hz[phase];
155adaba9f3SMatthias Ringwald         little_endian_store_16(data, i * 2, sample);
15659c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
15759c97ae1SMatthias Ringwald         phase += 2;
158c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
15935fd3fb9SMatthias Ringwald             phase = 0;
16035fd3fb9SMatthias Ringwald         }
16135fd3fb9SMatthias Ringwald     }
16235fd3fb9SMatthias Ringwald }
16335fd3fb9SMatthias Ringwald 
1641bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
1651bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
166249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){
167249d94cfSMatthias Ringwald     unsigned int i;
1681bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
1691bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
1701bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1711bbecc2bSMatthias Ringwald             phase = 0;
1721bbecc2bSMatthias Ringwald         }
1731bbecc2bSMatthias Ringwald     }
1741bbecc2bSMatthias Ringwald }
1751bbecc2bSMatthias Ringwald 
176b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){
17735fd3fb9SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
17835fd3fb9SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
179379c5f5fSMatthias Ringwald     if (num_samples > MAX_NUM_MSBC_SAMPLES) return;
180379c5f5fSMatthias Ringwald     int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
18159c97ae1SMatthias Ringwald     sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer);
18235fd3fb9SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
18335fd3fb9SMatthias Ringwald     num_audio_frames++;
18435fd3fb9SMatthias Ringwald }
1852b89dbfcSMatthias Ringwald #endif
1861bbecc2bSMatthias Ringwald #endif
187dbb41bfeSMilanka Ringwald 
188d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
189d861f4bfSMatthias Ringwald 
190379c5f5fSMatthias Ringwald static void playback_callback(int16_t * buffer, uint16_t num_samples){
1912b89dbfcSMatthias Ringwald 
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){
206f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
207f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME * 2);
208f55ac442SMatthias Ringwald #else
209f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
210f55ac442SMatthias Ringwald #endif
211379c5f5fSMatthias Ringwald            return;
212dbb41bfeSMilanka Ringwald         } else {
213c4e666bcSMatthias Ringwald             // resume playback
214379c5f5fSMatthias Ringwald             audio_output_paused = 0;
215dbb41bfeSMilanka Ringwald         }
216c4e666bcSMatthias Ringwald     }
217c4e666bcSMatthias Ringwald 
218c4e666bcSMatthias Ringwald     // get data from ringbuffer
219c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
220f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
221f55ac442SMatthias Ringwald     while (num_samples){
222f55ac442SMatthias Ringwald         int16_t temp[16];
223f55ac442SMatthias Ringwald         unsigned int bytes_to_read = btstack_min(num_samples * BYTES_PER_FRAME, sizeof(temp));
224f55ac442SMatthias Ringwald         btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) &temp[0], bytes_to_read, &bytes_read);
225f55ac442SMatthias Ringwald         if (bytes_read == 0) break;
226f55ac442SMatthias Ringwald         unsigned int i;
227f55ac442SMatthias Ringwald         for (i=0;i<bytes_read / BYTES_PER_FRAME;i++){
228f55ac442SMatthias Ringwald             *buffer++ = temp[i];
229f55ac442SMatthias Ringwald             *buffer++ = temp[i];
230f55ac442SMatthias Ringwald             num_samples--;
231f55ac442SMatthias Ringwald         }
232f55ac442SMatthias Ringwald     }
233f55ac442SMatthias Ringwald #else
234f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
235f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
236f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
237f55ac442SMatthias Ringwald #endif
238c4e666bcSMatthias Ringwald 
239c4e666bcSMatthias Ringwald     // fill with 0 if not enough
240f55ac442SMatthias Ringwald     if (num_samples){
241f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
242f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME * 2);
243f55ac442SMatthias Ringwald #else
244f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
245f55ac442SMatthias Ringwald #endif
246379c5f5fSMatthias Ringwald         audio_output_paused = 1;
247c4e666bcSMatthias Ringwald     }
248379c5f5fSMatthias Ringwald }
2498b29cfc6SMatthias Ringwald 
250379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
251379c5f5fSMatthias Ringwald static void recording_callback(const int16_t * buffer, uint16_t num_samples){
252379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
253c4e666bcSMatthias Ringwald }
254379c5f5fSMatthias Ringwald #endif
255c4e666bcSMatthias Ringwald 
256c4e666bcSMatthias Ringwald // return 1 if ok
257379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
258c4e666bcSMatthias Ringwald 
259d365bb51SMatthias Ringwald     // -- output -- //
260d365bb51SMatthias Ringwald 
261379c5f5fSMatthias Ringwald     // init buffers
262379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
263379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2642b89dbfcSMatthias Ringwald 
265d365bb51SMatthias Ringwald     // config and setup audio playback
266d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
267d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2682b89dbfcSMatthias Ringwald 
269f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
270f55ac442SMatthias Ringwald     audio_sink->init(2, sample_rate, &playback_callback);
271f55ac442SMatthias Ringwald #else
272d365bb51SMatthias Ringwald     audio_sink->init(1, sample_rate, &playback_callback);
273f55ac442SMatthias Ringwald #endif
274d365bb51SMatthias Ringwald     audio_sink->start_stream();
275379c5f5fSMatthias Ringwald 
276379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
277d365bb51SMatthias Ringwald 
278d365bb51SMatthias Ringwald     // -- input -- //
279d365bb51SMatthias Ringwald 
280379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
281d365bb51SMatthias Ringwald     // init buffers
282d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
283d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
284d365bb51SMatthias Ringwald 
285d365bb51SMatthias Ringwald     // config and setup audio recording
286d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
287d365bb51SMatthias Ringwald     if (!audio_source) return 0;
288d365bb51SMatthias Ringwald 
289d365bb51SMatthias Ringwald     audio_source->init(1, sample_rate, &recording_callback);
290d365bb51SMatthias Ringwald     audio_source->start_stream();
291d365bb51SMatthias Ringwald 
292379c5f5fSMatthias Ringwald     audio_input_paused  = 1;
2932b89dbfcSMatthias Ringwald #endif
2942b89dbfcSMatthias Ringwald 
295c4e666bcSMatthias Ringwald     return 1;
296c4e666bcSMatthias Ringwald }
2972b89dbfcSMatthias Ringwald 
298379c5f5fSMatthias Ringwald static void audio_terminate(void){
299d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
300d365bb51SMatthias Ringwald     if (!audio_sink) return;
301d365bb51SMatthias Ringwald     audio_sink->close();
302d365bb51SMatthias Ringwald 
303d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
304d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
305d365bb51SMatthias Ringwald     if (!audio_source) return;
306d365bb51SMatthias Ringwald     audio_source->close();
307d365bb51SMatthias Ringwald #endif
3082b89dbfcSMatthias Ringwald }
309c4e666bcSMatthias Ringwald 
3101bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
311d861f4bfSMatthias Ringwald 
312c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
313c4e666bcSMatthias Ringwald     UNUSED(context);
314c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
3152c7ae6e1SMatthias Ringwald     UNUSED(data);
3162c7ae6e1SMatthias Ringwald     UNUSED(num_samples);
3172c7ae6e1SMatthias Ringwald     UNUSED(num_channels);
3182c7ae6e1SMatthias Ringwald 
3192c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
320c4e666bcSMatthias Ringwald 
321c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
322379c5f5fSMatthias Ringwald 
323379c5f5fSMatthias Ringwald     // samples in callback in host endianess, ready for playback
324379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
325dbb41bfeSMilanka Ringwald 
3262c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
327fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
328fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
329fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
330fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
331fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
3322c7ae6e1SMatthias Ringwald         wav_writer_close();
333fcb08cdbSMilanka Ringwald     }
3341bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3352c7ae6e1SMatthias Ringwald 
3361bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */
337fcb08cdbSMilanka Ringwald }
3381bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
3391bbecc2bSMatthias Ringwald 
3401bbecc2bSMatthias Ringwald 
3411bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
342fcb08cdbSMilanka Ringwald 
343fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
344c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
345c4e666bcSMatthias Ringwald 
346fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
347220eb563SMilanka Ringwald     hfp_msbc_init();
3482c7ae6e1SMatthias Ringwald 
3492c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3502c7ae6e1SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3512c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
3522c7ae6e1SMatthias Ringwald #endif
3532c7ae6e1SMatthias Ringwald 
3542b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
355b025eb5fSMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
3562b89dbfcSMatthias Ringwald #endif
357973d7173SMatthias Ringwald 
358d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
359d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
360d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
361d5e5f834SMatthias Ringwald #endif
3622b89dbfcSMatthias Ringwald 
3637294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
364d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
365d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
3667294d009SMatthias Ringwald #endif
367dbb41bfeSMilanka Ringwald 
368379c5f5fSMatthias Ringwald     audio_initialize(MSBC_SAMPLE_RATE);
369fcb08cdbSMilanka Ringwald }
370fcb08cdbSMilanka Ringwald 
371fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
372fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
373d5e5f834SMatthias Ringwald         if (msbc_file_in){
374d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
375d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
376d5e5f834SMatthias Ringwald         }
377fcb08cdbSMilanka Ringwald     }
378dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
379fcb08cdbSMilanka Ringwald }
3801bbecc2bSMatthias Ringwald #endif
381fcb08cdbSMilanka Ringwald 
382fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
383c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
384c4e666bcSMatthias Ringwald 
385fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
386c4e666bcSMatthias Ringwald 
3872c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
388c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3892c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
3902c7ae6e1SMatthias Ringwald #endif
391dbb41bfeSMilanka Ringwald 
392379c5f5fSMatthias Ringwald     audio_initialize(CVSD_SAMPLE_RATE);
393fbc7c9f2SMilanka Ringwald }
394fbc7c9f2SMilanka Ringwald 
395fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
3962c7ae6e1SMatthias Ringwald 
3975303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
3981f8694ccSMatthias Ringwald 
3991f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
4001f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
4011f8694ccSMatthias Ringwald         return;
4021f8694ccSMatthias Ringwald     }
4032c7ae6e1SMatthias Ringwald 
404c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
405379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
4065303ddeeSMatthias Ringwald 
4075303ddeeSMatthias Ringwald     // convert into host endian
4085303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
4095303ddeeSMatthias Ringwald     int i;
4105303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
4115303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
4125303ddeeSMatthias Ringwald     }
4135303ddeeSMatthias Ringwald 
414e36764ddSMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out);
4155303ddeeSMatthias Ringwald 
4162c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
4172c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
4182c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
4192c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
4202c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
4212c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
4222c7ae6e1SMatthias Ringwald         wav_writer_close();
4232c7ae6e1SMatthias Ringwald     }
4242c7ae6e1SMatthias Ringwald #endif
4252c7ae6e1SMatthias Ringwald 
426379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
427fcb08cdbSMilanka Ringwald }
428fcb08cdbSMilanka Ringwald 
4292c7ae6e1SMatthias Ringwald #endif
4302c7ae6e1SMatthias Ringwald 
4312c7ae6e1SMatthias Ringwald 
432fcb08cdbSMilanka Ringwald void sco_demo_close(void){
433c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
4342b89dbfcSMatthias Ringwald 
43526463303SMilanka Ringwald     printf("SCO demo statistics: ");
4361bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
43726463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4382c7ae6e1SMatthias 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);
4391bbecc2bSMatthias Ringwald     } else
4401bbecc2bSMatthias Ringwald #endif
4411bbecc2bSMatthias Ringwald     {
4422c7ae6e1SMatthias 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);
44326463303SMilanka Ringwald     }
44426463303SMilanka Ringwald 
4452c7ae6e1SMatthias Ringwald     negotiated_codec = -1;
4462c7ae6e1SMatthias Ringwald 
4472c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
4482c7ae6e1SMatthias Ringwald 
4492c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
4502c7ae6e1SMatthias Ringwald     wav_writer_close();
4512c7ae6e1SMatthias Ringwald #endif
4522c7ae6e1SMatthias Ringwald 
453379c5f5fSMatthias Ringwald     audio_terminate();
454fcb08cdbSMilanka Ringwald 
455fcb08cdbSMilanka Ringwald #endif
456fcb08cdbSMilanka Ringwald }
457fcb08cdbSMilanka Ringwald 
458fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
459fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
460fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
4612c7ae6e1SMatthias Ringwald 
4622b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
463220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4641bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
465fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
4661bbecc2bSMatthias Ringwald #endif
467fcb08cdbSMilanka Ringwald     } else {
468fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
469fcb08cdbSMilanka Ringwald     }
470fcb08cdbSMilanka Ringwald #endif
471fcb08cdbSMilanka Ringwald }
472fcb08cdbSMilanka Ringwald 
473f7c85330SMatthias Ringwald void sco_demo_init(void){
474f7c85330SMatthias Ringwald 	// status
4752b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
476379c5f5fSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
4772b89dbfcSMatthias Ringwald #endif
478f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
479*1befbc1eSMatthias Ringwald     if (btstack_audio_sink_get_instance()){
480379c5f5fSMatthias Ringwald         printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
481*1befbc1eSMatthias Ringwald     } else {
482f7c85330SMatthias Ringwald         printf("SCO Demo: Sending sine wave, hexdump received data.\n");
483*1befbc1eSMatthias Ringwald     }
484f7c85330SMatthias Ringwald #endif
485f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
486f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
487f7c85330SMatthias Ringwald #endif
488f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
489f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
490f7c85330SMatthias Ringwald #endif
491f7c85330SMatthias Ringwald 
4922b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
493c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
494c4e666bcSMatthias Ringwald #else
495f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
4967294d009SMatthias Ringwald #endif
497f7c85330SMatthias Ringwald }
498f7c85330SMatthias Ringwald 
4991a919128SMatthias Ringwald void sco_report(void);
5001a919128SMatthias Ringwald void sco_report(void){
5014a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
5024a96141eSMatthias Ringwald }
503f7c85330SMatthias Ringwald 
504f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
505f7c85330SMatthias Ringwald 
506e1de95beSMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
507f7c85330SMatthias Ringwald 
508c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
509c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
510f7c85330SMatthias Ringwald 
511f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
512f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
513f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
5141bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
515220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
51601b2daf8SMatthias Ringwald 
517220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
518220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
519220eb563SMilanka Ringwald         }
520220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
521d5e5f834SMatthias Ringwald         if (msbc_file_out){
522d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
523d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
524d76591efSMatthias Ringwald         }
5257294d009SMatthias Ringwald 
526b025eb5fSMatthias Ringwald         sco_demo_msbc_fill_sine_audio_frame();
5271bbecc2bSMatthias Ringwald     } else
5281bbecc2bSMatthias Ringwald #endif
5291bbecc2bSMatthias Ringwald     {
530379c5f5fSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME;
531adaba9f3SMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]);
532220eb563SMilanka Ringwald     }
5331a919128SMatthias Ringwald #endif
5342b89dbfcSMatthias Ringwald 
5352b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5362b89dbfcSMatthias Ringwald 
537*1befbc1eSMatthias Ringwald     if (btstack_audio_source_get_instance()){
538*1befbc1eSMatthias Ringwald 
5392b89dbfcSMatthias Ringwald         if (negotiated_codec == HFP_CODEC_MSBC){
5402b89dbfcSMatthias Ringwald             // MSBC
5412b89dbfcSMatthias Ringwald 
542379c5f5fSMatthias Ringwald             if (audio_input_paused){
543379c5f5fSMatthias Ringwald                 if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
544b025eb5fSMatthias Ringwald                     // resume sending
545379c5f5fSMatthias Ringwald                     audio_input_paused = 0;
5462b89dbfcSMatthias Ringwald                 }
547b025eb5fSMatthias Ringwald             }
548b025eb5fSMatthias Ringwald 
549379c5f5fSMatthias Ringwald             if (!audio_input_paused){
550b025eb5fSMatthias Ringwald                 int num_samples = hfp_msbc_num_audio_samples_per_frame();
551379c5f5fSMatthias Ringwald                 if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert
552379c5f5fSMatthias 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)){
553379c5f5fSMatthias Ringwald                     int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
554b025eb5fSMatthias Ringwald                     uint32_t bytes_read;
555379c5f5fSMatthias Ringwald                     btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
556b025eb5fSMatthias Ringwald                     hfp_msbc_encode_audio_frame(sample_buffer);
557b025eb5fSMatthias Ringwald                     num_audio_frames++;
558b025eb5fSMatthias Ringwald                 }
559b025eb5fSMatthias Ringwald                 if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
560b025eb5fSMatthias Ringwald                     log_error("mSBC stream should not be empty.");
561379c5f5fSMatthias Ringwald                 }
562379c5f5fSMatthias Ringwald             }
563379c5f5fSMatthias Ringwald 
564379c5f5fSMatthias Ringwald             if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
565b025eb5fSMatthias Ringwald                 memset(sco_packet + 3, 0, sco_payload_length);
566379c5f5fSMatthias Ringwald                 audio_input_paused = 1;
567b025eb5fSMatthias Ringwald             } else {
5682b89dbfcSMatthias Ringwald                 hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
5692b89dbfcSMatthias Ringwald                 if (msbc_file_out){
5702b89dbfcSMatthias Ringwald                     // log outgoing mSBC data for testing
5712b89dbfcSMatthias Ringwald                     fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
5722b89dbfcSMatthias Ringwald                 }
573b025eb5fSMatthias Ringwald             }
5742b89dbfcSMatthias Ringwald 
5752b89dbfcSMatthias Ringwald         } else {
5762b89dbfcSMatthias Ringwald             // CVSD
5772b89dbfcSMatthias Ringwald 
578379c5f5fSMatthias 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));
5792b89dbfcSMatthias Ringwald             // fill with silence while paused
5802b89dbfcSMatthias Ringwald             int bytes_to_copy = sco_payload_length;
581379c5f5fSMatthias Ringwald             if (audio_input_paused){
582379c5f5fSMatthias Ringwald                 if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
5832b89dbfcSMatthias Ringwald                     // resume sending
584379c5f5fSMatthias Ringwald                     audio_input_paused = 0;
5852b89dbfcSMatthias Ringwald                 }
5862b89dbfcSMatthias Ringwald             }
5872b89dbfcSMatthias Ringwald 
5882b89dbfcSMatthias Ringwald             // get data from ringbuffer
5892b89dbfcSMatthias Ringwald             uint16_t pos = 0;
5908fd6902dSMatthias Ringwald             uint8_t * sample_data = &sco_packet[3];
591379c5f5fSMatthias Ringwald             if (!audio_input_paused){
5922b89dbfcSMatthias Ringwald                 uint32_t bytes_read = 0;
593379c5f5fSMatthias Ringwald                 btstack_ring_buffer_read(&audio_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
5948fd6902dSMatthias Ringwald                 // flip 16 on big endian systems
5958fd6902dSMatthias Ringwald                 // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
5968fd6902dSMatthias Ringwald                 if (btstack_is_big_endian()){
5978d3be402SMatthias Ringwald                     unsigned int i;
5988fd6902dSMatthias Ringwald                     for (i=0;i<bytes_read;i+=2){
5998fd6902dSMatthias Ringwald                         uint8_t tmp        = sample_data[i*2];
6008fd6902dSMatthias Ringwald                         sample_data[i*2]   = sample_data[i*2+1];
6018fd6902dSMatthias Ringwald                         sample_data[i*2+1] = tmp;
6028fd6902dSMatthias Ringwald                     }
6038fd6902dSMatthias Ringwald                 }
6042b89dbfcSMatthias Ringwald                 bytes_to_copy -= bytes_read;
6052b89dbfcSMatthias Ringwald                 pos           += bytes_read;
6062b89dbfcSMatthias Ringwald             }
6072b89dbfcSMatthias Ringwald 
6082b89dbfcSMatthias Ringwald             // fill with 0 if not enough
6092b89dbfcSMatthias Ringwald             if (bytes_to_copy){
6108fd6902dSMatthias Ringwald                 memset(sample_data + pos, 0, bytes_to_copy);
611379c5f5fSMatthias Ringwald                 audio_input_paused = 1;
6122b89dbfcSMatthias Ringwald             }
6132b89dbfcSMatthias Ringwald         }
614*1befbc1eSMatthias Ringwald     }
615*1befbc1eSMatthias Ringwald     else {
6162b89dbfcSMatthias Ringwald         // just send '0's
6172b89dbfcSMatthias Ringwald         memset(sco_packet + 3, 0, sco_payload_length);
618*1befbc1eSMatthias Ringwald     }
6192b89dbfcSMatthias Ringwald #endif
6202b89dbfcSMatthias Ringwald 
621f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
62201b2daf8SMatthias Ringwald     // store packet counter-xxxx
62301b2daf8SMatthias Ringwald     snprintf((char *)&sco_packet[3], 5, "%04u", phase++);
62401b2daf8SMatthias Ringwald     uint8_t ascii = (phase & 0x0f) + 'a';
62501b2daf8SMatthias Ringwald     sco_packet[3+4] = '-';
62601b2daf8SMatthias Ringwald     memset(&sco_packet[3+5], ascii, sco_payload_length-5);
6271a919128SMatthias Ringwald #endif
6281a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
62938b2eaafSMatthias Ringwald     int j;
630c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
63138b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
632f7c85330SMatthias Ringwald     }
633f7c85330SMatthias Ringwald #endif
6341a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
6351a919128SMatthias Ringwald     int j;
636c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6371a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
6381a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
6391a919128SMatthias Ringwald     }
6401a919128SMatthias Ringwald #endif
6411a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
6421a919128SMatthias Ringwald     int j;
643c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6441a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
6451a919128SMatthias Ringwald     }
6461a919128SMatthias Ringwald     // additional hack
6471a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
6481a919128SMatthias Ringwald     (void) phase;
649f7c85330SMatthias Ringwald #endif
650220eb563SMilanka Ringwald 
6512b89dbfcSMatthias Ringwald     // test silence
6522b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
6532b89dbfcSMatthias Ringwald 
654c4e666bcSMatthias Ringwald     // set handle + flags
655c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
656c4e666bcSMatthias Ringwald     // set len
657c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
658c4e666bcSMatthias Ringwald     // finally send packet
659f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
660f7c85330SMatthias Ringwald 
661f7c85330SMatthias Ringwald     // request another send event
662f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
663f7c85330SMatthias Ringwald 
6644a96141eSMatthias Ringwald     count_sent++;
6651a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
6664a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
6671a919128SMatthias Ringwald #endif
668f7c85330SMatthias Ringwald }
669f7c85330SMatthias Ringwald 
670f7c85330SMatthias Ringwald /**
671f7c85330SMatthias Ringwald  * @brief Process received data
672f7c85330SMatthias Ringwald  */
6731a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
6741a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
6751a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
6761a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
6771a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
6781a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
6791a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
6801a919128SMatthias Ringwald 
681f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
682f7c85330SMatthias Ringwald 
683fcb08cdbSMilanka Ringwald     dump_data = 1;
6848b29cfc6SMatthias Ringwald 
6854a96141eSMatthias Ringwald     count_received++;
6861a919128SMatthias Ringwald     static uint32_t packets = 0;
6871a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
6881a919128SMatthias Ringwald     static uint32_t data_received = 0;
6891a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
6904a96141eSMatthias Ringwald 
6911a919128SMatthias Ringwald     data_received += size - 3;
6921a919128SMatthias Ringwald     packets++;
6931a919128SMatthias Ringwald     if (data_received > 100000){
694d4f907a6SMatthias 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);
6951a919128SMatthias Ringwald         crc_errors = 0;
6961a919128SMatthias Ringwald         byte_errors = 0;
6971a919128SMatthias Ringwald         data_received = 0;
6981a919128SMatthias Ringwald         packets = 0;
6991a919128SMatthias Ringwald     }
7004a96141eSMatthias Ringwald 
7012b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
702c4e666bcSMatthias Ringwald     switch (negotiated_codec){
7031bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
704c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
705fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
706c4e666bcSMatthias Ringwald             break;
7071bbecc2bSMatthias Ringwald #endif
708c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
709fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
710c4e666bcSMatthias Ringwald             break;
711c4e666bcSMatthias Ringwald         default:
712c4e666bcSMatthias Ringwald             break;
7138b29cfc6SMatthias Ringwald     }
714dbb41bfeSMilanka Ringwald     dump_data = 0;
7158b29cfc6SMatthias Ringwald #endif
7168b29cfc6SMatthias Ringwald 
71701b2daf8SMatthias Ringwald #if 0
718b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
7191a919128SMatthias Ringwald         crc_errors++;
72001b2daf8SMatthias Ringwald         printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
72101b2daf8SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
722f7c85330SMatthias Ringwald         return;
723f7c85330SMatthias Ringwald     }
72401b2daf8SMatthias Ringwald #endif
72501b2daf8SMatthias Ringwald 
7268b29cfc6SMatthias Ringwald     if (dump_data){
727f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
7281a919128SMatthias Ringwald         printf("data: ");
729f7c85330SMatthias Ringwald         int i;
730f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
731f7c85330SMatthias Ringwald             printf("%c", packet[i]);
732f7c85330SMatthias Ringwald         }
733f7c85330SMatthias Ringwald         printf("\n");
7348b29cfc6SMatthias Ringwald         dump_data = 0;
7351a919128SMatthias Ringwald #endif
7361a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
7371a919128SMatthias Ringwald         // colored hexdump with expected
7381a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
7391a919128SMatthias Ringwald         int i;
7401a919128SMatthias Ringwald         printf("data: ");
7411a919128SMatthias Ringwald         for (i=3;i<size;i++){
7421a919128SMatthias Ringwald             if (packet[i] != expected_byte){
7431a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7441a919128SMatthias Ringwald             } else {
7451a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7461a919128SMatthias Ringwald             }
7471a919128SMatthias Ringwald             expected_byte = packet[i]+1;
7481a919128SMatthias Ringwald         }
7491a919128SMatthias Ringwald         printf("\n");
7501a919128SMatthias Ringwald #endif
751a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
7521a919128SMatthias Ringwald         int i;
7531a919128SMatthias Ringwald         int contains_error = 0;
7541a919128SMatthias Ringwald         for (i=3;i<size;i++){
7551a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7561a919128SMatthias Ringwald                 contains_error = 1;
7571a919128SMatthias Ringwald                 byte_errors++;
7581a919128SMatthias Ringwald             }
7591a919128SMatthias Ringwald         }
7601a919128SMatthias Ringwald         if (contains_error){
7611a919128SMatthias Ringwald             printf("data: ");
7621a919128SMatthias Ringwald             for (i=0;i<3;i++){
7631a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7641a919128SMatthias Ringwald             }
7651a919128SMatthias Ringwald             for (i=3;i<size;i++){
7661a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7671a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7681a919128SMatthias Ringwald                 } else {
7691a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
7701a919128SMatthias Ringwald                 }
7711a919128SMatthias Ringwald             }
7721a919128SMatthias Ringwald             printf("\n");
7731a919128SMatthias Ringwald         }
774f7c85330SMatthias Ringwald #endif
7758b29cfc6SMatthias Ringwald     }
776f7c85330SMatthias Ringwald }
777