xref: /btstack/example/sco_demo_util.c (revision 9582ae6476f483e9aa869d8c0f45c2c0e52fae8b)
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 
56f89e874bSMatthias Ringwald #ifdef _MSC_VER
57f89e874bSMatthias Ringwald // ignore deprecated warning for fopen
58f89e874bSMatthias Ringwald #pragma warning(disable : 4996)
59f89e874bSMatthias Ringwald #endif
60f89e874bSMatthias 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
6794381a69SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 1
68f7c85330SMatthias Ringwald 
69f7c85330SMatthias Ringwald // SCO demo configuration
70d365bb51SMatthias Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_MICROPHONE
71c4e666bcSMatthias Ringwald 
72c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console
73f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD           100
74f7c85330SMatthias Ringwald 
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"
80859f2bc5SMatthias Ringwald #endif
81859f2bc5SMatthias Ringwald 
82c4e666bcSMatthias Ringwald // constants
83c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
84b150a479SMatthias Ringwald #define SAMPLE_RATE_8KHZ        8000
85b150a479SMatthias Ringwald #define SAMPLE_RATE_16KHZ       16000
86379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
87f7c85330SMatthias Ringwald 
88b150a479SMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
89b150a479SMatthias Ringwald #define SCO_PREBUFFER_MS      50
90b150a479SMatthias Ringwald #define PREBUFFER_BYTES_8KHZ  (SCO_PREBUFFER_MS *  SAMPLE_RATE_8KHZ/1000 * BYTES_PER_FRAME)
91b150a479SMatthias Ringwald #define PREBUFFER_BYTES_16KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_16KHZ/1000 * BYTES_PER_FRAME)
92f7c85330SMatthias Ringwald 
93*9582ae64SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH)
94*9582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_16KHZ
95*9582ae64SMatthias Ringwald #else
96*9582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_8KHZ
97*9582ae64SMatthias Ringwald #endif
98*9582ae64SMatthias Ringwald 
99bf958e42SMatthias Ringwald static uint16_t              audio_prebuffer_bytes;
100bf958e42SMatthias Ringwald 
1012b89dbfcSMatthias Ringwald // output
102d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
103*9582ae64SMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
104379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
1052b89dbfcSMatthias Ringwald 
1062b89dbfcSMatthias Ringwald // input
1072b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
108379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
1093cf06407SMatthias Ringwald #else
1103cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR
1113cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data);
1126fb1424bSMatthias Ringwald #endif
113379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
114*9582ae64SMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
115379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
116f7c85330SMatthias Ringwald 
117fcb08cdbSMilanka Ringwald static int count_sent = 0;
118fcb08cdbSMilanka Ringwald static int count_received = 0;
119c4e666bcSMatthias Ringwald 
1201bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
121379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
1221bbecc2bSMatthias Ringwald #endif
1231bbecc2bSMatthias Ringwald 
124379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
125379c5f5fSMatthias Ringwald 
126379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8)
127fcb08cdbSMilanka Ringwald 
1282b89dbfcSMatthias Ringwald int num_samples_to_write;
1292b89dbfcSMatthias Ringwald int num_audio_frames;
1302b89dbfcSMatthias Ringwald 
131bf958e42SMatthias Ringwald // generic codec support
132bf958e42SMatthias Ringwald typedef struct {
133bf958e42SMatthias Ringwald     void (*init)(void);
134bf958e42SMatthias Ringwald     void(*receive)(const uint8_t * packet, uint16_t size);
135bf958e42SMatthias Ringwald     void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length);
136bf958e42SMatthias Ringwald     void (*close)(void);
137bf958e42SMatthias Ringwald } codec_support_t;
138bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL;
139bf958e42SMatthias Ringwald 
1403cf06407SMatthias Ringwald // sine generator
141d6a06398SMatthias Ringwald 
1423cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
1433cf06407SMatthias Ringwald static unsigned int phase;
14494381a69SMatthias Ringwald 
1457556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz
146c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
1477556ab9fSMatthias Ringwald      0,   3135,   6237,   9270,  12202,  14999,  17633,  20073,  22294,  24270,
1487556ab9fSMatthias Ringwald  25980,  27406,  28531,  29344,  29835,  30000,  29835,  29344,  28531,  27406,
1497556ab9fSMatthias Ringwald  25980,  24270,  22294,  20073,  17633,  14999,  12202,   9270,   6237,   3135,
1507556ab9fSMatthias Ringwald      0,  -3135,  -6237,  -9270, -12202, -14999, -17633, -20073, -22294, -24270,
1517556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406,
1527556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202,  -9270,  -6237,  -3135,
15335fd3fb9SMatthias Ringwald };
15435fd3fb9SMatthias Ringwald 
15559c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
1563cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_host_endian(uint16_t num_samples, int16_t * data){
157249d94cfSMatthias Ringwald     unsigned int i;
15859c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
1596fb1424bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase];
16059c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
16159c97ae1SMatthias Ringwald         phase += 2;
162c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
16335fd3fb9SMatthias Ringwald             phase = 0;
16435fd3fb9SMatthias Ringwald         }
16535fd3fb9SMatthias Ringwald     }
16635fd3fb9SMatthias Ringwald }
16735fd3fb9SMatthias Ringwald 
1681bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
1691bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
1703cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(uint16_t num_samples, int16_t * data){
171249d94cfSMatthias Ringwald     unsigned int i;
1721bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
1731bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
1741bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1751bbecc2bSMatthias Ringwald             phase = 0;
1761bbecc2bSMatthias Ringwald         }
1771bbecc2bSMatthias Ringwald     }
1781bbecc2bSMatthias Ringwald }
1792b89dbfcSMatthias Ringwald #endif
1801bbecc2bSMatthias Ringwald #endif
181dbb41bfeSMilanka Ringwald 
18294381a69SMatthias Ringwald // Audio Playback / Recording
183d861f4bfSMatthias Ringwald 
18494381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){
1852b89dbfcSMatthias Ringwald 
186c4e666bcSMatthias Ringwald     // fill with silence while paused
187379c5f5fSMatthias Ringwald     if (audio_output_paused){
188bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){
189f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
190379c5f5fSMatthias Ringwald            return;
191dbb41bfeSMilanka Ringwald         } else {
192c4e666bcSMatthias Ringwald             // resume playback
193379c5f5fSMatthias Ringwald             audio_output_paused = 0;
194dbb41bfeSMilanka Ringwald         }
195c4e666bcSMatthias Ringwald     }
196c4e666bcSMatthias Ringwald 
197c4e666bcSMatthias Ringwald     // get data from ringbuffer
198c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
199f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
200f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
201f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
202c4e666bcSMatthias Ringwald 
203c4e666bcSMatthias Ringwald     // fill with 0 if not enough
204f55ac442SMatthias Ringwald     if (num_samples){
205f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
206379c5f5fSMatthias Ringwald         audio_output_paused = 1;
207c4e666bcSMatthias Ringwald     }
208379c5f5fSMatthias Ringwald }
2098b29cfc6SMatthias Ringwald 
210379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
21194381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){
212379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
213c4e666bcSMatthias Ringwald }
214379c5f5fSMatthias Ringwald #endif
215c4e666bcSMatthias Ringwald 
216c4e666bcSMatthias Ringwald // return 1 if ok
217379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
218c4e666bcSMatthias Ringwald 
219d365bb51SMatthias Ringwald     // -- output -- //
220d365bb51SMatthias Ringwald 
221379c5f5fSMatthias Ringwald     // init buffers
222379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
223379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2242b89dbfcSMatthias Ringwald 
225d365bb51SMatthias Ringwald     // config and setup audio playback
226d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
227d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2282b89dbfcSMatthias Ringwald 
22994381a69SMatthias Ringwald     audio_sink->init(1, sample_rate, &audio_playback_callback);
230d365bb51SMatthias Ringwald     audio_sink->start_stream();
231379c5f5fSMatthias Ringwald 
232379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
233d365bb51SMatthias Ringwald 
234d365bb51SMatthias Ringwald     // -- input -- //
235d365bb51SMatthias Ringwald 
236d365bb51SMatthias Ringwald     // init buffers
237d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
238d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
2396fb1424bSMatthias Ringwald     audio_input_paused  = 1;
240d365bb51SMatthias Ringwald 
2416fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT
242d365bb51SMatthias Ringwald     // config and setup audio recording
243d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
244d365bb51SMatthias Ringwald     if (!audio_source) return 0;
245d365bb51SMatthias Ringwald 
24694381a69SMatthias Ringwald     audio_source->init(1, sample_rate, &audio_recording_callback);
247d365bb51SMatthias Ringwald     audio_source->start_stream();
2482b89dbfcSMatthias Ringwald #endif
2492b89dbfcSMatthias Ringwald 
250c4e666bcSMatthias Ringwald     return 1;
251c4e666bcSMatthias Ringwald }
2522b89dbfcSMatthias Ringwald 
253379c5f5fSMatthias Ringwald static void audio_terminate(void){
254d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
255d365bb51SMatthias Ringwald     if (!audio_sink) return;
256d365bb51SMatthias Ringwald     audio_sink->close();
257d365bb51SMatthias Ringwald 
258d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
259d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
260d365bb51SMatthias Ringwald     if (!audio_source) return;
261d365bb51SMatthias Ringwald     audio_source->close();
262d365bb51SMatthias Ringwald #endif
2632b89dbfcSMatthias Ringwald }
264c4e666bcSMatthias Ringwald 
265d861f4bfSMatthias Ringwald 
26694381a69SMatthias Ringwald // CVSD - 8 kHz
267fcb08cdbSMilanka Ringwald 
268bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){
269c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
270c4e666bcSMatthias Ringwald 
271fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
272c4e666bcSMatthias Ringwald 
273bf958e42SMatthias Ringwald     audio_prebuffer_bytes = PREBUFFER_BYTES_8KHZ;
274bf958e42SMatthias Ringwald 
275bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
276bf958e42SMatthias Ringwald     sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_8000_hz_host_endian;
277bf958e42SMatthias Ringwald #endif
278b150a479SMatthias Ringwald 
2792c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
280b150a479SMatthias Ringwald     num_samples_to_write = SAMPLE_RATE_8KHZ * SCO_WAV_DURATION_IN_SECONDS;
281b150a479SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, SAMPLE_RATE_8KHZ);
2822c7ae6e1SMatthias Ringwald #endif
283dbb41bfeSMilanka Ringwald 
284b150a479SMatthias Ringwald     audio_initialize(SAMPLE_RATE_8KHZ);
285fbc7c9f2SMilanka Ringwald }
286fbc7c9f2SMilanka Ringwald 
287bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){
2882c7ae6e1SMatthias Ringwald 
2895303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
2901f8694ccSMatthias Ringwald 
2911f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
292bf958e42SMatthias Ringwald         printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n");
2931f8694ccSMatthias Ringwald         return;
2941f8694ccSMatthias Ringwald     }
2952c7ae6e1SMatthias Ringwald 
296c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
297379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
2985303ddeeSMatthias Ringwald 
2995303ddeeSMatthias Ringwald     // convert into host endian
3005303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
3015303ddeeSMatthias Ringwald     int i;
3025303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
3035303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
3045303ddeeSMatthias Ringwald     }
3055303ddeeSMatthias Ringwald 
3065f4f94c7SMatthias Ringwald     // treat packet as bad frame if controller does not report 'all good'
3075f4f94c7SMatthias Ringwald     bool bad_frame = (packet[1] & 0x30) != 0;
3085f4f94c7SMatthias Ringwald 
3095f4f94c7SMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out);
3105303ddeeSMatthias Ringwald 
3112c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3122c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3132c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3142c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3152c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3162c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3172c7ae6e1SMatthias Ringwald         wav_writer_close();
3182c7ae6e1SMatthias Ringwald     }
3192c7ae6e1SMatthias Ringwald #endif
3202c7ae6e1SMatthias Ringwald 
321379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
322fcb08cdbSMilanka Ringwald }
323fcb08cdbSMilanka Ringwald 
324bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
3256fb1424bSMatthias Ringwald     uint16_t bytes_to_copy = sco_payload_length;
3266fb1424bSMatthias Ringwald 
3272b89dbfcSMatthias Ringwald     // get data from ringbuffer
3282b89dbfcSMatthias Ringwald     uint16_t pos = 0;
329379c5f5fSMatthias Ringwald     if (!audio_input_paused){
3306fb1424bSMatthias Ringwald         uint16_t samples_to_copy = sco_payload_length / 2;
3312b89dbfcSMatthias Ringwald         uint32_t bytes_read = 0;
3326fb1424bSMatthias Ringwald         btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read);
3338fd6902dSMatthias Ringwald         // flip 16 on big endian systems
3348fd6902dSMatthias Ringwald         // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
3358fd6902dSMatthias Ringwald         if (btstack_is_big_endian()){
3366fb1424bSMatthias Ringwald             uint16_t i;
3376fb1424bSMatthias Ringwald             for (i=0;i<samples_to_copy/2;i+=2){
3386fb1424bSMatthias Ringwald                 uint8_t tmp           = payload_buffer[i*2];
3396fb1424bSMatthias Ringwald                 payload_buffer[i*2]   = payload_buffer[i*2+1];
3406fb1424bSMatthias Ringwald                 payload_buffer[i*2+1] = tmp;
3418fd6902dSMatthias Ringwald             }
3428fd6902dSMatthias Ringwald         }
3432b89dbfcSMatthias Ringwald         bytes_to_copy -= bytes_read;
3442b89dbfcSMatthias Ringwald         pos           += bytes_read;
3452b89dbfcSMatthias Ringwald     }
3462b89dbfcSMatthias Ringwald 
3472b89dbfcSMatthias Ringwald     // fill with 0 if not enough
3482b89dbfcSMatthias Ringwald     if (bytes_to_copy){
3496fb1424bSMatthias Ringwald         memset(payload_buffer + pos, 0, bytes_to_copy);
350379c5f5fSMatthias Ringwald         audio_input_paused = 1;
3512b89dbfcSMatthias Ringwald     }
3522b89dbfcSMatthias Ringwald }
35394381a69SMatthias Ringwald 
354bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){
355bf958e42SMatthias 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);
356bf958e42SMatthias Ringwald }
357bf958e42SMatthias Ringwald 
358bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = {
359bf958e42SMatthias Ringwald         .init         = &sco_demo_cvsd_init,
360bf958e42SMatthias Ringwald         .receive      = &sco_demo_cvsd_receive,
361bf958e42SMatthias Ringwald         .fill_payload = &sco_demo_cvsd_fill_payload,
362bf958e42SMatthias Ringwald         .close        = &sco_demo_cvsd_close
363bf958e42SMatthias Ringwald };
364bf958e42SMatthias Ringwald 
36594381a69SMatthias Ringwald // mSBC - 16 kHz
36694381a69SMatthias Ringwald 
36794381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
36894381a69SMatthias Ringwald 
36994381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
37094381a69SMatthias Ringwald     UNUSED(context);
37194381a69SMatthias Ringwald     UNUSED(sample_rate);
37294381a69SMatthias Ringwald     UNUSED(data);
37394381a69SMatthias Ringwald     UNUSED(num_samples);
37494381a69SMatthias Ringwald     UNUSED(num_channels);
37594381a69SMatthias Ringwald 
37694381a69SMatthias Ringwald     // samples in callback in host endianess, ready for playback
37794381a69SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
37894381a69SMatthias Ringwald 
37994381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
38094381a69SMatthias Ringwald     if (!num_samples_to_write) return;
38194381a69SMatthias Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
38294381a69SMatthias Ringwald     num_samples_to_write -= num_samples;
38394381a69SMatthias Ringwald     wav_writer_write_int16(num_samples, data);
38494381a69SMatthias Ringwald     if (num_samples_to_write == 0){
38594381a69SMatthias Ringwald         wav_writer_close();
386f7c85330SMatthias Ringwald     }
38794381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3881a919128SMatthias Ringwald }
38994381a69SMatthias Ringwald 
390bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){
39194381a69SMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
39294381a69SMatthias Ringwald 
39394381a69SMatthias Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
39494381a69SMatthias Ringwald     hfp_msbc_init();
39594381a69SMatthias Ringwald 
396bf958e42SMatthias Ringwald     audio_prebuffer_bytes = PREBUFFER_BYTES_16KHZ;
397bf958e42SMatthias Ringwald 
398bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
399bf958e42SMatthias Ringwald     sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_16000_hz_host_endian;
400bf958e42SMatthias Ringwald #endif
401b150a479SMatthias Ringwald 
40294381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
403b150a479SMatthias Ringwald     num_samples_to_write = SAMPLE_RATE_16KHZ * SCO_WAV_DURATION_IN_SECONDS;
404b150a479SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, SAMPLE_RATE_16KHZ);
405f7c85330SMatthias Ringwald #endif
406220eb563SMilanka Ringwald 
407b150a479SMatthias Ringwald     audio_initialize(SAMPLE_RATE_16KHZ);
40894381a69SMatthias Ringwald }
40994381a69SMatthias Ringwald 
410bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){
41194381a69SMatthias Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
41294381a69SMatthias Ringwald }
41394381a69SMatthias Ringwald 
414bf958e42SMatthias Ringwald void sco_demo_msbc_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
41594381a69SMatthias Ringwald     if (!audio_input_paused){
41694381a69SMatthias Ringwald         int num_samples = hfp_msbc_num_audio_samples_per_frame();
417b89b876fSMatthias Ringwald         btstack_assert(num_samples <= MAX_NUM_MSBC_SAMPLES);
41894381a69SMatthias 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)){
41994381a69SMatthias Ringwald             int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
42094381a69SMatthias Ringwald             uint32_t bytes_read;
42194381a69SMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
42294381a69SMatthias Ringwald             hfp_msbc_encode_audio_frame(sample_buffer);
42394381a69SMatthias Ringwald             num_audio_frames++;
42494381a69SMatthias Ringwald         }
425b89b876fSMatthias Ringwald         btstack_assert(hfp_msbc_num_bytes_in_stream() >= sco_payload_length);
42694381a69SMatthias Ringwald     }
427b89b876fSMatthias Ringwald 
428b89b876fSMatthias Ringwald     // get data from encoder, fill with 0 if not enough
42994381a69SMatthias Ringwald     if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
43094381a69SMatthias Ringwald         // just send '0's
43194381a69SMatthias Ringwald         memset(payload_buffer, 0, sco_payload_length);
43294381a69SMatthias Ringwald         audio_input_paused = 1;
43394381a69SMatthias Ringwald     } else {
43494381a69SMatthias Ringwald         hfp_msbc_read_from_stream(payload_buffer, sco_payload_length);
43594381a69SMatthias Ringwald     }
43694381a69SMatthias Ringwald }
43794381a69SMatthias Ringwald 
438bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){
439bf958e42SMatthias 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);
440bf958e42SMatthias Ringwald }
441bf958e42SMatthias Ringwald 
442bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = {
443bf958e42SMatthias Ringwald         .init         = &sco_demo_msbc_init,
444bf958e42SMatthias Ringwald         .receive      = &sco_demo_msbc_receive,
445bf958e42SMatthias Ringwald         .fill_payload = &sco_demo_msbc_fill_payload,
446bf958e42SMatthias Ringwald         .close        = &sco_demo_msbc_close
447bf958e42SMatthias Ringwald };
448bf958e42SMatthias Ringwald 
44994381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
45094381a69SMatthias Ringwald 
45194381a69SMatthias Ringwald void sco_demo_init(void){
45294381a69SMatthias Ringwald 
45394381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS
45494381a69SMatthias Ringwald     printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n");
45594381a69SMatthias Ringwald     gap_secure_connections_enable(false);
45694381a69SMatthias Ringwald #endif
45794381a69SMatthias Ringwald 
45894381a69SMatthias Ringwald 	// status
45994381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
46094381a69SMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
46194381a69SMatthias Ringwald #endif
46294381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
46394381a69SMatthias Ringwald     if (btstack_audio_sink_get_instance()){
46494381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
46594381a69SMatthias Ringwald     } else {
46694381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, hexdump received data.\n");
46794381a69SMatthias Ringwald     }
46894381a69SMatthias Ringwald #endif
46994381a69SMatthias Ringwald 
47094381a69SMatthias Ringwald     // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode)
47194381a69SMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
47294381a69SMatthias Ringwald }
47394381a69SMatthias Ringwald 
474bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){
47594381a69SMatthias Ringwald     switch (negotiated_codec){
47694381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
477bf958e42SMatthias Ringwald             codec_current = &codec_cvsd;
47894381a69SMatthias Ringwald             break;
47994381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
48094381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
481bf958e42SMatthias Ringwald             codec_current = &codec_msbc;
48294381a69SMatthias Ringwald             break;
48394381a69SMatthias Ringwald #endif
48494381a69SMatthias Ringwald         default:
48594381a69SMatthias Ringwald             btstack_assert(false);
48694381a69SMatthias Ringwald             break;
48794381a69SMatthias Ringwald     }
488bf958e42SMatthias Ringwald 
489bf958e42SMatthias Ringwald     codec_current->init();
49094381a69SMatthias Ringwald }
49194381a69SMatthias Ringwald 
49294381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
49394381a69SMatthias Ringwald     static uint32_t packets = 0;
49494381a69SMatthias Ringwald     static uint32_t crc_errors = 0;
49594381a69SMatthias Ringwald     static uint32_t data_received = 0;
49694381a69SMatthias Ringwald     static uint32_t byte_errors = 0;
49794381a69SMatthias Ringwald 
49894381a69SMatthias Ringwald     count_received++;
49994381a69SMatthias Ringwald 
50094381a69SMatthias Ringwald     data_received += size - 3;
50194381a69SMatthias Ringwald     packets++;
50294381a69SMatthias Ringwald     if (data_received > 100000){
50394381a69SMatthias 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);
50494381a69SMatthias Ringwald         crc_errors = 0;
50594381a69SMatthias Ringwald         byte_errors = 0;
50694381a69SMatthias Ringwald         data_received = 0;
50794381a69SMatthias Ringwald         packets = 0;
50894381a69SMatthias Ringwald     }
50994381a69SMatthias Ringwald 
510bf958e42SMatthias Ringwald     codec_current->receive(packet, size);
51194381a69SMatthias Ringwald }
51294381a69SMatthias Ringwald 
51394381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
51494381a69SMatthias Ringwald 
51594381a69SMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
51694381a69SMatthias Ringwald 
51794381a69SMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
51894381a69SMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
51994381a69SMatthias Ringwald 
52094381a69SMatthias Ringwald     hci_reserve_packet_buffer();
52194381a69SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
52294381a69SMatthias Ringwald 
523bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
524bf958e42SMatthias Ringwald     #define REFILL_SAMPLES 16
525bf958e42SMatthias Ringwald     // re-fill audio buffer
526bf958e42SMatthias Ringwald     uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2;
527bf958e42SMatthias Ringwald     while (samples_free > 0){
528bf958e42SMatthias Ringwald         int16_t samples_buffer[REFILL_SAMPLES];
529bf958e42SMatthias Ringwald         uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES);
530bf958e42SMatthias Ringwald         (*sco_demo_audio_generator)(samples_to_add, samples_buffer);
531bf958e42SMatthias Ringwald         btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2);
532bf958e42SMatthias Ringwald         samples_free -= samples_to_add;
53394381a69SMatthias Ringwald     }
534bf958e42SMatthias Ringwald #endif
535bf958e42SMatthias Ringwald 
536bf958e42SMatthias Ringwald     // resume if pre-buffer is filled
537bf958e42SMatthias Ringwald     if (audio_input_paused){
538bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){
539bf958e42SMatthias Ringwald             // resume sending
540bf958e42SMatthias Ringwald             audio_input_paused = 0;
541bf958e42SMatthias Ringwald         }
542bf958e42SMatthias Ringwald     }
543bf958e42SMatthias Ringwald 
544bf958e42SMatthias Ringwald     // fill payload by codec
545bf958e42SMatthias Ringwald     codec_current->fill_payload(&sco_packet[3], sco_payload_length);
5462b89dbfcSMatthias Ringwald 
547c4e666bcSMatthias Ringwald     // set handle + flags
548c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
549c4e666bcSMatthias Ringwald     // set len
550c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
551c4e666bcSMatthias Ringwald     // finally send packet
552f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
553f7c85330SMatthias Ringwald 
554f7c85330SMatthias Ringwald     // request another send event
555f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
556f7c85330SMatthias Ringwald 
5574a96141eSMatthias Ringwald     count_sent++;
55894381a69SMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) {
55994381a69SMatthias Ringwald         printf("SCO: sent %u, received %u\n", count_sent, count_received);
56094381a69SMatthias Ringwald     }
561f7c85330SMatthias Ringwald }
562f7c85330SMatthias Ringwald 
56394381a69SMatthias Ringwald void sco_demo_close(void){
56494381a69SMatthias Ringwald     printf("SCO demo close\n");
5651a919128SMatthias Ringwald 
56694381a69SMatthias Ringwald     printf("SCO demo statistics: ");
567bf958e42SMatthias Ringwald     codec_current->close();
568bf958e42SMatthias Ringwald     codec_current = NULL;
56994381a69SMatthias Ringwald 
57094381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
57194381a69SMatthias Ringwald     wav_writer_close();
5728b29cfc6SMatthias Ringwald #endif
5738b29cfc6SMatthias Ringwald 
57494381a69SMatthias Ringwald     audio_terminate();
575f7c85330SMatthias Ringwald }
576