xref: /btstack/example/sco_demo_util.c (revision f89e874b332bd0767adc4c7ecf025efed38f8dbb)
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
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH 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 
38e501bae0SMatthias 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 
56*f89e874bSMatthias Ringwald #ifdef _MSC_VER
57*f89e874bSMatthias Ringwald // ignore deprecated warning for fopen
58*f89e874bSMatthias Ringwald #pragma warning(disable : 4996)
59*f89e874bSMatthias Ringwald #endif
60*f89e874bSMatthias Ringwald 
6135fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
62fbc7c9f2SMilanka Ringwald #include "wav_util.h"
6335fd3fb9SMatthias Ringwald #endif
64fbc7c9f2SMilanka Ringwald 
65c4e666bcSMatthias Ringwald // test modes
66f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		 0
67f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII		 1
68f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER	 2
691a919128SMatthias Ringwald #define SCO_DEMO_MODE_55         3
701a919128SMatthias Ringwald #define SCO_DEMO_MODE_00         4
71463c9c89SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 5
72f7c85330SMatthias Ringwald 
73f7c85330SMatthias Ringwald // SCO demo configuration
74d365bb51SMatthias Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_MICROPHONE
75c4e666bcSMatthias Ringwald 
76c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console
77f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD           100
78f7c85330SMatthias Ringwald 
79f55ac442SMatthias Ringwald // #define ENABLE_SCO_STEREO_PLAYBACK
80f55ac442SMatthias Ringwald 
81d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
822c7ae6e1SMatthias Ringwald // length and name of wav file on disk
83c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
848b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
85c4e666bcSMatthias Ringwald 
86c4e666bcSMatthias Ringwald // name of sbc test files
87d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME       "sco_output.msbc"
882308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME        "sco_input.msbc"
89859f2bc5SMatthias Ringwald #endif
90859f2bc5SMatthias Ringwald 
91220eb563SMilanka Ringwald 
92c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
93c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS    50
94c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS    50
958b29cfc6SMatthias Ringwald 
96c4e666bcSMatthias Ringwald // constants
97c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
98c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE        8000
99c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE        16000
100379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
101f7c85330SMatthias Ringwald 
102379c5f5fSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
103379c5f5fSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
104f7c85330SMatthias Ringwald 
1052b89dbfcSMatthias Ringwald // output
106379c5f5fSMatthias Ringwald 
107d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
108d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
109379c5f5fSMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
110379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
111d861f4bfSMatthias Ringwald #endif
112d861f4bfSMatthias Ringwald 
1132b89dbfcSMatthias Ringwald 
1142b89dbfcSMatthias Ringwald // input
1152b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
116379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
117379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
118379c5f5fSMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2*8000];  // full second input buffer
119379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
120f7c85330SMatthias Ringwald #endif
121f7c85330SMatthias Ringwald 
122fcb08cdbSMilanka Ringwald static int dump_data = 1;
123fcb08cdbSMilanka Ringwald static int count_sent = 0;
124fcb08cdbSMilanka Ringwald static int count_received = 0;
125c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
126c4e666bcSMatthias Ringwald 
1271bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
128379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
129859f2bc5SMatthias Ringwald 
130859f2bc5SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
131859f2bc5SMatthias Ringwald FILE * msbc_file_in;
132859f2bc5SMatthias Ringwald FILE * msbc_file_out;
133859f2bc5SMatthias Ringwald #endif
134859f2bc5SMatthias Ringwald 
1351bbecc2bSMatthias Ringwald #endif
1361bbecc2bSMatthias Ringwald 
137379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
138379c5f5fSMatthias Ringwald 
139379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8)
140fcb08cdbSMilanka Ringwald 
1412b89dbfcSMatthias Ringwald int num_samples_to_write;
1422b89dbfcSMatthias Ringwald int num_audio_frames;
143249d94cfSMatthias Ringwald unsigned int phase;
1442b89dbfcSMatthias Ringwald 
145f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
146d6a06398SMatthias Ringwald 
1477556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz
148c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
1497556ab9fSMatthias Ringwald      0,   3135,   6237,   9270,  12202,  14999,  17633,  20073,  22294,  24270,
1507556ab9fSMatthias Ringwald  25980,  27406,  28531,  29344,  29835,  30000,  29835,  29344,  28531,  27406,
1517556ab9fSMatthias Ringwald  25980,  24270,  22294,  20073,  17633,  14999,  12202,   9270,   6237,   3135,
1527556ab9fSMatthias Ringwald      0,  -3135,  -6237,  -9270, -12202, -14999, -17633, -20073, -22294, -24270,
1537556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406,
1547556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202,  -9270,  -6237,  -3135,
15535fd3fb9SMatthias Ringwald };
15635fd3fb9SMatthias Ringwald 
15759c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
158adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){
159249d94cfSMatthias Ringwald     unsigned int i;
16059c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
16159c97ae1SMatthias Ringwald         int16_t sample = sine_int16_at_16000hz[phase];
162adaba9f3SMatthias Ringwald         little_endian_store_16(data, i * 2, sample);
16359c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
16459c97ae1SMatthias Ringwald         phase += 2;
165c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
16635fd3fb9SMatthias Ringwald             phase = 0;
16735fd3fb9SMatthias Ringwald         }
16835fd3fb9SMatthias Ringwald     }
16935fd3fb9SMatthias Ringwald }
17035fd3fb9SMatthias Ringwald 
1711bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
1721bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
173249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){
174249d94cfSMatthias Ringwald     unsigned int i;
1751bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
1761bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
1771bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1781bbecc2bSMatthias Ringwald             phase = 0;
1791bbecc2bSMatthias Ringwald         }
1801bbecc2bSMatthias Ringwald     }
1811bbecc2bSMatthias Ringwald }
1821bbecc2bSMatthias Ringwald 
183b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){
18435fd3fb9SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
18535fd3fb9SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
186379c5f5fSMatthias Ringwald     if (num_samples > MAX_NUM_MSBC_SAMPLES) return;
187379c5f5fSMatthias Ringwald     int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
18859c97ae1SMatthias Ringwald     sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer);
18935fd3fb9SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
19035fd3fb9SMatthias Ringwald     num_audio_frames++;
19135fd3fb9SMatthias Ringwald }
1922b89dbfcSMatthias Ringwald #endif
1931bbecc2bSMatthias Ringwald #endif
194dbb41bfeSMilanka Ringwald 
195d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
196d861f4bfSMatthias Ringwald 
197379c5f5fSMatthias Ringwald static void playback_callback(int16_t * buffer, uint16_t num_samples){
1982b89dbfcSMatthias Ringwald 
199be030f50SMilanka Ringwald     uint32_t prebuffer_bytes;
200c4e666bcSMatthias Ringwald     switch (negotiated_codec){
201c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
202c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
203c4e666bcSMatthias Ringwald             break;
204c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
205c4e666bcSMatthias Ringwald         default:
206379c5f5fSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
207c4e666bcSMatthias Ringwald             break;
208dbb41bfeSMilanka Ringwald     }
209dbb41bfeSMilanka Ringwald 
210c4e666bcSMatthias Ringwald     // fill with silence while paused
211379c5f5fSMatthias Ringwald     if (audio_output_paused){
212379c5f5fSMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){
213f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
214f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME * 2);
215f55ac442SMatthias Ringwald #else
216f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
217f55ac442SMatthias Ringwald #endif
218379c5f5fSMatthias Ringwald            return;
219dbb41bfeSMilanka Ringwald         } else {
220c4e666bcSMatthias Ringwald             // resume playback
221379c5f5fSMatthias Ringwald             audio_output_paused = 0;
222dbb41bfeSMilanka Ringwald         }
223c4e666bcSMatthias Ringwald     }
224c4e666bcSMatthias Ringwald 
225c4e666bcSMatthias Ringwald     // get data from ringbuffer
226c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
227f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
228f55ac442SMatthias Ringwald     while (num_samples){
229f55ac442SMatthias Ringwald         int16_t temp[16];
230f55ac442SMatthias Ringwald         unsigned int bytes_to_read = btstack_min(num_samples * BYTES_PER_FRAME, sizeof(temp));
231f55ac442SMatthias Ringwald         btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) &temp[0], bytes_to_read, &bytes_read);
232f55ac442SMatthias Ringwald         if (bytes_read == 0) break;
233f55ac442SMatthias Ringwald         unsigned int i;
234f55ac442SMatthias Ringwald         for (i=0;i<bytes_read / BYTES_PER_FRAME;i++){
235f55ac442SMatthias Ringwald             *buffer++ = temp[i];
236f55ac442SMatthias Ringwald             *buffer++ = temp[i];
237f55ac442SMatthias Ringwald             num_samples--;
238f55ac442SMatthias Ringwald         }
239f55ac442SMatthias Ringwald     }
240f55ac442SMatthias Ringwald #else
241f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
242f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
243f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
244f55ac442SMatthias Ringwald #endif
245c4e666bcSMatthias Ringwald 
246c4e666bcSMatthias Ringwald     // fill with 0 if not enough
247f55ac442SMatthias Ringwald     if (num_samples){
248f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
249f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME * 2);
250f55ac442SMatthias Ringwald #else
251f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
252f55ac442SMatthias Ringwald #endif
253379c5f5fSMatthias Ringwald         audio_output_paused = 1;
254c4e666bcSMatthias Ringwald     }
255379c5f5fSMatthias Ringwald }
2568b29cfc6SMatthias Ringwald 
257379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
258379c5f5fSMatthias Ringwald static void recording_callback(const int16_t * buffer, uint16_t num_samples){
259379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
260c4e666bcSMatthias Ringwald }
261379c5f5fSMatthias Ringwald #endif
262c4e666bcSMatthias Ringwald 
263c4e666bcSMatthias Ringwald // return 1 if ok
264379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
265c4e666bcSMatthias Ringwald 
266d365bb51SMatthias Ringwald     // -- output -- //
267d365bb51SMatthias Ringwald 
268379c5f5fSMatthias Ringwald     // init buffers
269379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
270379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2712b89dbfcSMatthias Ringwald 
272d365bb51SMatthias Ringwald     // config and setup audio playback
273d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
274d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2752b89dbfcSMatthias Ringwald 
276f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK
277f55ac442SMatthias Ringwald     audio_sink->init(2, sample_rate, &playback_callback);
278f55ac442SMatthias Ringwald #else
279d365bb51SMatthias Ringwald     audio_sink->init(1, sample_rate, &playback_callback);
280f55ac442SMatthias Ringwald #endif
281d365bb51SMatthias Ringwald     audio_sink->start_stream();
282379c5f5fSMatthias Ringwald 
283379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
284d365bb51SMatthias Ringwald 
285d365bb51SMatthias Ringwald     // -- input -- //
286d365bb51SMatthias Ringwald 
287379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
288d365bb51SMatthias Ringwald     // init buffers
289d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
290d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
291d365bb51SMatthias Ringwald 
292d365bb51SMatthias Ringwald     // config and setup audio recording
293d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
294d365bb51SMatthias Ringwald     if (!audio_source) return 0;
295d365bb51SMatthias Ringwald 
296d365bb51SMatthias Ringwald     audio_source->init(1, sample_rate, &recording_callback);
297d365bb51SMatthias Ringwald     audio_source->start_stream();
298d365bb51SMatthias Ringwald 
299379c5f5fSMatthias Ringwald     audio_input_paused  = 1;
3002b89dbfcSMatthias Ringwald #endif
3012b89dbfcSMatthias Ringwald 
302c4e666bcSMatthias Ringwald     return 1;
303c4e666bcSMatthias Ringwald }
3042b89dbfcSMatthias Ringwald 
305379c5f5fSMatthias Ringwald static void audio_terminate(void){
306d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
307d365bb51SMatthias Ringwald     if (!audio_sink) return;
308d365bb51SMatthias Ringwald     audio_sink->close();
309d365bb51SMatthias Ringwald 
310d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
311d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
312d365bb51SMatthias Ringwald     if (!audio_source) return;
313d365bb51SMatthias Ringwald     audio_source->close();
314d365bb51SMatthias Ringwald #endif
3152b89dbfcSMatthias Ringwald }
316c4e666bcSMatthias Ringwald 
3171bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
318d861f4bfSMatthias Ringwald 
319c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
320c4e666bcSMatthias Ringwald     UNUSED(context);
321c4e666bcSMatthias Ringwald     UNUSED(sample_rate);
3222c7ae6e1SMatthias Ringwald     UNUSED(data);
3232c7ae6e1SMatthias Ringwald     UNUSED(num_samples);
3242c7ae6e1SMatthias Ringwald     UNUSED(num_channels);
3252c7ae6e1SMatthias Ringwald 
3262c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
327c4e666bcSMatthias Ringwald 
328c4e666bcSMatthias Ringwald     // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
329379c5f5fSMatthias Ringwald 
330379c5f5fSMatthias Ringwald     // samples in callback in host endianess, ready for playback
331379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
332dbb41bfeSMilanka Ringwald 
3332c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
334fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
335fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
336fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
337fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
338fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
3392c7ae6e1SMatthias Ringwald         wav_writer_close();
340fcb08cdbSMilanka Ringwald     }
3411bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3422c7ae6e1SMatthias Ringwald 
3431bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */
344fcb08cdbSMilanka Ringwald }
3451bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
3461bbecc2bSMatthias Ringwald 
3471bbecc2bSMatthias Ringwald 
3481bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
349fcb08cdbSMilanka Ringwald 
350fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
351c4e666bcSMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
352c4e666bcSMatthias Ringwald 
353fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
354220eb563SMilanka Ringwald     hfp_msbc_init();
3552c7ae6e1SMatthias Ringwald 
3562c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3572c7ae6e1SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3582c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
3592c7ae6e1SMatthias Ringwald #endif
3602c7ae6e1SMatthias Ringwald 
3612b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
362b025eb5fSMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
3632b89dbfcSMatthias Ringwald #endif
364973d7173SMatthias Ringwald 
365d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
366d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
367d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
368d5e5f834SMatthias Ringwald #endif
3692b89dbfcSMatthias Ringwald 
3707294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
371d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
372d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
3737294d009SMatthias Ringwald #endif
374dbb41bfeSMilanka Ringwald 
375379c5f5fSMatthias Ringwald     audio_initialize(MSBC_SAMPLE_RATE);
376fcb08cdbSMilanka Ringwald }
377fcb08cdbSMilanka Ringwald 
378fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
379859f2bc5SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
380fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
381d5e5f834SMatthias Ringwald         if (msbc_file_in){
382d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
383d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
384d5e5f834SMatthias Ringwald         }
385fcb08cdbSMilanka Ringwald     }
386859f2bc5SMatthias Ringwald #endif
387dbb41bfeSMilanka Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
388fcb08cdbSMilanka Ringwald }
3891bbecc2bSMatthias Ringwald #endif
390fcb08cdbSMilanka Ringwald 
391fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
392c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
393c4e666bcSMatthias Ringwald 
394fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
395c4e666bcSMatthias Ringwald 
3962c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
397c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
3982c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
3992c7ae6e1SMatthias Ringwald #endif
400dbb41bfeSMilanka Ringwald 
401379c5f5fSMatthias Ringwald     audio_initialize(CVSD_SAMPLE_RATE);
402fbc7c9f2SMilanka Ringwald }
403fbc7c9f2SMilanka Ringwald 
404fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
4052c7ae6e1SMatthias Ringwald 
4065303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
4071f8694ccSMatthias Ringwald 
4081f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
4091f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
4101f8694ccSMatthias Ringwald         return;
4111f8694ccSMatthias Ringwald     }
4122c7ae6e1SMatthias Ringwald 
413c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
414379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
4155303ddeeSMatthias Ringwald 
4165303ddeeSMatthias Ringwald     // convert into host endian
4175303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
4185303ddeeSMatthias Ringwald     int i;
4195303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
4205303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
4215303ddeeSMatthias Ringwald     }
4225303ddeeSMatthias Ringwald 
4235f4f94c7SMatthias Ringwald     // treat packet as bad frame if controller does not report 'all good'
4245f4f94c7SMatthias Ringwald     bool bad_frame = (packet[1] & 0x30) != 0;
4255f4f94c7SMatthias Ringwald 
4265f4f94c7SMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out);
4275303ddeeSMatthias Ringwald 
4282c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
4292c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
4302c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
4312c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
4322c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
4332c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
4342c7ae6e1SMatthias Ringwald         wav_writer_close();
4352c7ae6e1SMatthias Ringwald     }
4362c7ae6e1SMatthias Ringwald #endif
4372c7ae6e1SMatthias Ringwald 
438379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
439fcb08cdbSMilanka Ringwald }
440fcb08cdbSMilanka Ringwald 
4412c7ae6e1SMatthias Ringwald #endif
4422c7ae6e1SMatthias Ringwald 
4432c7ae6e1SMatthias Ringwald 
444fcb08cdbSMilanka Ringwald void sco_demo_close(void){
445c4e666bcSMatthias Ringwald     printf("SCO demo close\n");
4462b89dbfcSMatthias Ringwald 
44726463303SMilanka Ringwald     printf("SCO demo statistics: ");
4481bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
44926463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4502c7ae6e1SMatthias 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);
4511bbecc2bSMatthias Ringwald     } else
4521bbecc2bSMatthias Ringwald #endif
4531bbecc2bSMatthias Ringwald     {
4542c7ae6e1SMatthias 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);
45526463303SMilanka Ringwald     }
45626463303SMilanka Ringwald 
4572c7ae6e1SMatthias Ringwald     negotiated_codec = -1;
4582c7ae6e1SMatthias Ringwald 
4592c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
4602c7ae6e1SMatthias Ringwald 
4612c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
4622c7ae6e1SMatthias Ringwald     wav_writer_close();
4632c7ae6e1SMatthias Ringwald #endif
4642c7ae6e1SMatthias Ringwald 
465379c5f5fSMatthias Ringwald     audio_terminate();
466fcb08cdbSMilanka Ringwald 
467fcb08cdbSMilanka Ringwald #endif
468fcb08cdbSMilanka Ringwald }
469fcb08cdbSMilanka Ringwald 
470fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
471fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
472fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
4732c7ae6e1SMatthias Ringwald 
4742b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
475220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
4761bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
477fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
4781bbecc2bSMatthias Ringwald #endif
479fcb08cdbSMilanka Ringwald     } else {
480fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
481fcb08cdbSMilanka Ringwald     }
482fcb08cdbSMilanka Ringwald #endif
483fcb08cdbSMilanka Ringwald }
484fcb08cdbSMilanka Ringwald 
485f7c85330SMatthias Ringwald void sco_demo_init(void){
486eaffacf9SMatthias Ringwald 
487eaffacf9SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS
488eaffacf9SMatthias Ringwald     printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n");
489eaffacf9SMatthias Ringwald     gap_secure_connections_enable(false);
490eaffacf9SMatthias Ringwald #endif
491eaffacf9SMatthias Ringwald 
492f7c85330SMatthias Ringwald 	// status
4932b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
494379c5f5fSMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
4952b89dbfcSMatthias Ringwald #endif
496f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
4971befbc1eSMatthias Ringwald     if (btstack_audio_sink_get_instance()){
498379c5f5fSMatthias Ringwald         printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
4991befbc1eSMatthias Ringwald     } else {
500f7c85330SMatthias Ringwald         printf("SCO Demo: Sending sine wave, hexdump received data.\n");
5011befbc1eSMatthias Ringwald     }
502f7c85330SMatthias Ringwald #endif
503f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
504f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
505f7c85330SMatthias Ringwald #endif
506f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
507f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
508f7c85330SMatthias Ringwald #endif
509f7c85330SMatthias Ringwald 
5102b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
511c4e666bcSMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
512c4e666bcSMatthias Ringwald #else
513f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
5147294d009SMatthias Ringwald #endif
515f7c85330SMatthias Ringwald }
516f7c85330SMatthias Ringwald 
5171a919128SMatthias Ringwald void sco_report(void);
5181a919128SMatthias Ringwald void sco_report(void){
5194a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
5204a96141eSMatthias Ringwald }
521f7c85330SMatthias Ringwald 
522f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
523f7c85330SMatthias Ringwald 
524e1de95beSMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
525f7c85330SMatthias Ringwald 
526c4e666bcSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
527c4e666bcSMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
528f7c85330SMatthias Ringwald 
529f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
530f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
531f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
5321bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
533220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
53401b2daf8SMatthias Ringwald 
535220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
536220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
537220eb563SMilanka Ringwald         }
538220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
539859f2bc5SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
540d5e5f834SMatthias Ringwald         if (msbc_file_out){
541d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
542d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
543d76591efSMatthias Ringwald         }
544859f2bc5SMatthias Ringwald #endif
545b025eb5fSMatthias Ringwald         sco_demo_msbc_fill_sine_audio_frame();
5461bbecc2bSMatthias Ringwald     } else
5471bbecc2bSMatthias Ringwald #endif
5481bbecc2bSMatthias Ringwald     {
549379c5f5fSMatthias Ringwald         const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME;
550adaba9f3SMatthias Ringwald         sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]);
551220eb563SMilanka Ringwald     }
5521a919128SMatthias Ringwald #endif
5532b89dbfcSMatthias Ringwald 
5542b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
5552b89dbfcSMatthias Ringwald 
5561befbc1eSMatthias Ringwald     if (btstack_audio_source_get_instance()){
5571befbc1eSMatthias Ringwald 
5582b89dbfcSMatthias Ringwald         if (negotiated_codec == HFP_CODEC_MSBC){
5592b89dbfcSMatthias Ringwald             // MSBC
5602b89dbfcSMatthias Ringwald 
561379c5f5fSMatthias Ringwald             if (audio_input_paused){
562379c5f5fSMatthias Ringwald                 if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
563b025eb5fSMatthias Ringwald                     // resume sending
564379c5f5fSMatthias Ringwald                     audio_input_paused = 0;
5652b89dbfcSMatthias Ringwald                 }
566b025eb5fSMatthias Ringwald             }
567b025eb5fSMatthias Ringwald 
568379c5f5fSMatthias Ringwald             if (!audio_input_paused){
569b025eb5fSMatthias Ringwald                 int num_samples = hfp_msbc_num_audio_samples_per_frame();
570379c5f5fSMatthias Ringwald                 if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert
571379c5f5fSMatthias 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)){
572379c5f5fSMatthias Ringwald                     int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
573b025eb5fSMatthias Ringwald                     uint32_t bytes_read;
574379c5f5fSMatthias Ringwald                     btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
575b025eb5fSMatthias Ringwald                     hfp_msbc_encode_audio_frame(sample_buffer);
576b025eb5fSMatthias Ringwald                     num_audio_frames++;
577b025eb5fSMatthias Ringwald                 }
578b025eb5fSMatthias Ringwald                 if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
579b025eb5fSMatthias Ringwald                     log_error("mSBC stream should not be empty.");
580379c5f5fSMatthias Ringwald                 }
581379c5f5fSMatthias Ringwald             }
582379c5f5fSMatthias Ringwald 
583379c5f5fSMatthias Ringwald             if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
584b025eb5fSMatthias Ringwald                 memset(sco_packet + 3, 0, sco_payload_length);
585379c5f5fSMatthias Ringwald                 audio_input_paused = 1;
586b025eb5fSMatthias Ringwald             } else {
5872b89dbfcSMatthias Ringwald                 hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
58889714ad0SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
589dfec1b51SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
5902b89dbfcSMatthias Ringwald                 if (msbc_file_out){
5912b89dbfcSMatthias Ringwald                     // log outgoing mSBC data for testing
5922b89dbfcSMatthias Ringwald                     fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
5932b89dbfcSMatthias Ringwald                 }
594dfec1b51SMatthias Ringwald #endif
59589714ad0SMatthias Ringwald #endif
596b025eb5fSMatthias Ringwald             }
5972b89dbfcSMatthias Ringwald 
5982b89dbfcSMatthias Ringwald         } else {
5992b89dbfcSMatthias Ringwald             // CVSD
6002b89dbfcSMatthias Ringwald 
601abf7f0baSMatthias Ringwald             log_debug("send: bytes avail %u, free %u", btstack_ring_buffer_bytes_available(&audio_input_ring_buffer), btstack_ring_buffer_bytes_free(&audio_input_ring_buffer));
6022b89dbfcSMatthias Ringwald             // fill with silence while paused
6032b89dbfcSMatthias Ringwald             int bytes_to_copy = sco_payload_length;
604379c5f5fSMatthias Ringwald             if (audio_input_paused){
605379c5f5fSMatthias Ringwald                 if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
6062b89dbfcSMatthias Ringwald                     // resume sending
607379c5f5fSMatthias Ringwald                     audio_input_paused = 0;
6082b89dbfcSMatthias Ringwald                 }
6092b89dbfcSMatthias Ringwald             }
6102b89dbfcSMatthias Ringwald 
6112b89dbfcSMatthias Ringwald             // get data from ringbuffer
6122b89dbfcSMatthias Ringwald             uint16_t pos = 0;
6138fd6902dSMatthias Ringwald             uint8_t * sample_data = &sco_packet[3];
614379c5f5fSMatthias Ringwald             if (!audio_input_paused){
6152b89dbfcSMatthias Ringwald                 uint32_t bytes_read = 0;
616379c5f5fSMatthias Ringwald                 btstack_ring_buffer_read(&audio_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
6178fd6902dSMatthias Ringwald                 // flip 16 on big endian systems
6188fd6902dSMatthias Ringwald                 // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
6198fd6902dSMatthias Ringwald                 if (btstack_is_big_endian()){
6208d3be402SMatthias Ringwald                     unsigned int i;
6218fd6902dSMatthias Ringwald                     for (i=0;i<bytes_read;i+=2){
6228fd6902dSMatthias Ringwald                         uint8_t tmp        = sample_data[i*2];
6238fd6902dSMatthias Ringwald                         sample_data[i*2]   = sample_data[i*2+1];
6248fd6902dSMatthias Ringwald                         sample_data[i*2+1] = tmp;
6258fd6902dSMatthias Ringwald                     }
6268fd6902dSMatthias Ringwald                 }
6272b89dbfcSMatthias Ringwald                 bytes_to_copy -= bytes_read;
6282b89dbfcSMatthias Ringwald                 pos           += bytes_read;
6292b89dbfcSMatthias Ringwald             }
6302b89dbfcSMatthias Ringwald 
6312b89dbfcSMatthias Ringwald             // fill with 0 if not enough
6322b89dbfcSMatthias Ringwald             if (bytes_to_copy){
6338fd6902dSMatthias Ringwald                 memset(sample_data + pos, 0, bytes_to_copy);
634379c5f5fSMatthias Ringwald                 audio_input_paused = 1;
6352b89dbfcSMatthias Ringwald             }
6362b89dbfcSMatthias Ringwald         }
6371befbc1eSMatthias Ringwald     }
6381befbc1eSMatthias Ringwald     else {
6392b89dbfcSMatthias Ringwald         // just send '0's
6402b89dbfcSMatthias Ringwald         memset(sco_packet + 3, 0, sco_payload_length);
6411befbc1eSMatthias Ringwald     }
6422b89dbfcSMatthias Ringwald #endif
6432b89dbfcSMatthias Ringwald 
644f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
64501b2daf8SMatthias Ringwald     // store packet counter-xxxx
64601b2daf8SMatthias Ringwald     snprintf((char *)&sco_packet[3], 5, "%04u", phase++);
64701b2daf8SMatthias Ringwald     uint8_t ascii = (phase & 0x0f) + 'a';
64801b2daf8SMatthias Ringwald     sco_packet[3+4] = '-';
64901b2daf8SMatthias Ringwald     memset(&sco_packet[3+5], ascii, sco_payload_length-5);
6501a919128SMatthias Ringwald #endif
6511a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
65238b2eaafSMatthias Ringwald     int j;
653c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
65438b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
655f7c85330SMatthias Ringwald     }
656f7c85330SMatthias Ringwald #endif
6571a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55
6581a919128SMatthias Ringwald     int j;
659c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6601a919128SMatthias Ringwald         // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
6611a919128SMatthias Ringwald         sco_packet[3+j] = 0x55;
6621a919128SMatthias Ringwald     }
6631a919128SMatthias Ringwald #endif
6641a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00
6651a919128SMatthias Ringwald     int j;
666c4e666bcSMatthias Ringwald     for (j=0;j<sco_payload_length;j++){
6671a919128SMatthias Ringwald         sco_packet[3+j] = 0x00;
6681a919128SMatthias Ringwald     }
6691a919128SMatthias Ringwald     // additional hack
6701a919128SMatthias Ringwald     // big_endian_store_16(sco_packet, 5, phase++);
6711a919128SMatthias Ringwald     (void) phase;
672f7c85330SMatthias Ringwald #endif
673220eb563SMilanka Ringwald 
6742b89dbfcSMatthias Ringwald     // test silence
6752b89dbfcSMatthias Ringwald     // memset(sco_packet+3, 0, sco_payload_length);
6762b89dbfcSMatthias Ringwald 
677c4e666bcSMatthias Ringwald     // set handle + flags
678c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
679c4e666bcSMatthias Ringwald     // set len
680c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
681c4e666bcSMatthias Ringwald     // finally send packet
682f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
683f7c85330SMatthias Ringwald 
684f7c85330SMatthias Ringwald     // request another send event
685f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
686f7c85330SMatthias Ringwald 
6874a96141eSMatthias Ringwald     count_sent++;
6881a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55
6894a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
6901a919128SMatthias Ringwald #endif
691f7c85330SMatthias Ringwald }
692f7c85330SMatthias Ringwald 
693f7c85330SMatthias Ringwald /**
694f7c85330SMatthias Ringwald  * @brief Process received data
695f7c85330SMatthias Ringwald  */
6961a919128SMatthias Ringwald #define ANSI_COLOR_RED     "\x1b[31m"
6971a919128SMatthias Ringwald #define ANSI_COLOR_GREEN   "\x1b[32m"
6981a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW  "\x1b[33m"
6991a919128SMatthias Ringwald #define ANSI_COLOR_BLUE    "\x1b[34m"
7001a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m"
7011a919128SMatthias Ringwald #define ANSI_COLOR_CYAN    "\x1b[36m"
7021a919128SMatthias Ringwald #define ANSI_COLOR_RESET   "\x1b[0m"
7031a919128SMatthias Ringwald 
704f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
705f7c85330SMatthias Ringwald 
706fcb08cdbSMilanka Ringwald     dump_data = 1;
7078b29cfc6SMatthias Ringwald 
7084a96141eSMatthias Ringwald     count_received++;
7091a919128SMatthias Ringwald     static uint32_t packets = 0;
7101a919128SMatthias Ringwald     static uint32_t crc_errors = 0;
7111a919128SMatthias Ringwald     static uint32_t data_received = 0;
7121a919128SMatthias Ringwald     static uint32_t byte_errors = 0;
7134a96141eSMatthias Ringwald 
7141a919128SMatthias Ringwald     data_received += size - 3;
7151a919128SMatthias Ringwald     packets++;
7161a919128SMatthias Ringwald     if (data_received > 100000){
717d4f907a6SMatthias 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);
7181a919128SMatthias Ringwald         crc_errors = 0;
7191a919128SMatthias Ringwald         byte_errors = 0;
7201a919128SMatthias Ringwald         data_received = 0;
7211a919128SMatthias Ringwald         packets = 0;
7221a919128SMatthias Ringwald     }
7234a96141eSMatthias Ringwald 
7242b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
725c4e666bcSMatthias Ringwald     switch (negotiated_codec){
7261bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
727c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
728fcb08cdbSMilanka Ringwald             sco_demo_receive_mSBC(packet, size);
729c4e666bcSMatthias Ringwald             break;
7301bbecc2bSMatthias Ringwald #endif
731c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
732fcb08cdbSMilanka Ringwald             sco_demo_receive_CVSD(packet, size);
733c4e666bcSMatthias Ringwald             break;
734c4e666bcSMatthias Ringwald         default:
735c4e666bcSMatthias Ringwald             break;
7368b29cfc6SMatthias Ringwald     }
737dbb41bfeSMilanka Ringwald     dump_data = 0;
7388b29cfc6SMatthias Ringwald #endif
7398b29cfc6SMatthias Ringwald 
74001b2daf8SMatthias Ringwald #if 0
741b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
7421a919128SMatthias Ringwald         crc_errors++;
74301b2daf8SMatthias Ringwald         printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
74401b2daf8SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
745f7c85330SMatthias Ringwald         return;
746f7c85330SMatthias Ringwald     }
74701b2daf8SMatthias Ringwald #endif
74801b2daf8SMatthias Ringwald 
7498b29cfc6SMatthias Ringwald     if (dump_data){
750f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
7511a919128SMatthias Ringwald         printf("data: ");
752f7c85330SMatthias Ringwald         int i;
753f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
754f7c85330SMatthias Ringwald             printf("%c", packet[i]);
755f7c85330SMatthias Ringwald         }
756f7c85330SMatthias Ringwald         printf("\n");
7578b29cfc6SMatthias Ringwald         dump_data = 0;
7581a919128SMatthias Ringwald #endif
7591a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
7601a919128SMatthias Ringwald         // colored hexdump with expected
7611a919128SMatthias Ringwald         static uint8_t expected_byte = 0;
7621a919128SMatthias Ringwald         int i;
7631a919128SMatthias Ringwald         printf("data: ");
7641a919128SMatthias Ringwald         for (i=3;i<size;i++){
7651a919128SMatthias Ringwald             if (packet[i] != expected_byte){
7661a919128SMatthias Ringwald                 printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7671a919128SMatthias Ringwald             } else {
7681a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7691a919128SMatthias Ringwald             }
7701a919128SMatthias Ringwald             expected_byte = packet[i]+1;
7711a919128SMatthias Ringwald         }
7721a919128SMatthias Ringwald         printf("\n");
7731a919128SMatthias Ringwald #endif
774a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00
7751a919128SMatthias Ringwald         int i;
7761a919128SMatthias Ringwald         int contains_error = 0;
7771a919128SMatthias Ringwald         for (i=3;i<size;i++){
7781a919128SMatthias Ringwald             if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7791a919128SMatthias Ringwald                 contains_error = 1;
7801a919128SMatthias Ringwald                 byte_errors++;
7811a919128SMatthias Ringwald             }
7821a919128SMatthias Ringwald         }
7831a919128SMatthias Ringwald         if (contains_error){
7841a919128SMatthias Ringwald             printf("data: ");
7851a919128SMatthias Ringwald             for (i=0;i<3;i++){
7861a919128SMatthias Ringwald                 printf("%02x ", packet[i]);
7871a919128SMatthias Ringwald             }
7881a919128SMatthias Ringwald             for (i=3;i<size;i++){
7891a919128SMatthias Ringwald                 if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){
7901a919128SMatthias Ringwald                     printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]);
7911a919128SMatthias Ringwald                 } else {
7921a919128SMatthias Ringwald                     printf("%02x ", packet[i]);
7931a919128SMatthias Ringwald                 }
7941a919128SMatthias Ringwald             }
7951a919128SMatthias Ringwald             printf("\n");
7961a919128SMatthias Ringwald         }
797f7c85330SMatthias Ringwald #endif
7988b29cfc6SMatthias Ringwald     }
799f7c85330SMatthias Ringwald }
800