xref: /btstack/example/sco_demo_util.c (revision 3cf06407e62e69a1fbc5f1a3a039b544e87dbd75)
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 
82220eb563SMilanka Ringwald 
83c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
84c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS    50
85c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS    50
868b29cfc6SMatthias Ringwald 
87c4e666bcSMatthias Ringwald // constants
88c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
89c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE        8000
90c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE        16000
91379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
92f7c85330SMatthias Ringwald 
93379c5f5fSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
94379c5f5fSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME)
95f7c85330SMatthias Ringwald 
962b89dbfcSMatthias Ringwald // output
97d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
98379c5f5fSMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
99379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
1002b89dbfcSMatthias Ringwald 
1012b89dbfcSMatthias Ringwald // input
1022b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
103379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
104*3cf06407SMatthias Ringwald #else
105*3cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR
106*3cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data);
1076fb1424bSMatthias Ringwald #endif
108379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
109379c5f5fSMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2*8000];  // full second input buffer
110379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
111f7c85330SMatthias Ringwald 
112fcb08cdbSMilanka Ringwald static int count_sent = 0;
113fcb08cdbSMilanka Ringwald static int count_received = 0;
114c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
115c4e666bcSMatthias Ringwald 
1161bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
117379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
1181bbecc2bSMatthias Ringwald #endif
1191bbecc2bSMatthias Ringwald 
120379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
121379c5f5fSMatthias Ringwald 
122379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8)
123fcb08cdbSMilanka Ringwald 
1242b89dbfcSMatthias Ringwald int num_samples_to_write;
1252b89dbfcSMatthias Ringwald int num_audio_frames;
1262b89dbfcSMatthias Ringwald 
127*3cf06407SMatthias Ringwald // sine generator
128d6a06398SMatthias Ringwald 
129*3cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
130*3cf06407SMatthias Ringwald static unsigned int phase;
13194381a69SMatthias Ringwald 
1327556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz
133c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
1347556ab9fSMatthias Ringwald      0,   3135,   6237,   9270,  12202,  14999,  17633,  20073,  22294,  24270,
1357556ab9fSMatthias Ringwald  25980,  27406,  28531,  29344,  29835,  30000,  29835,  29344,  28531,  27406,
1367556ab9fSMatthias Ringwald  25980,  24270,  22294,  20073,  17633,  14999,  12202,   9270,   6237,   3135,
1377556ab9fSMatthias Ringwald      0,  -3135,  -6237,  -9270, -12202, -14999, -17633, -20073, -22294, -24270,
1387556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406,
1397556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202,  -9270,  -6237,  -3135,
14035fd3fb9SMatthias Ringwald };
14135fd3fb9SMatthias Ringwald 
14259c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
143*3cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_host_endian(uint16_t num_samples, int16_t * data){
144249d94cfSMatthias Ringwald     unsigned int i;
14559c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
1466fb1424bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase];
14759c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
14859c97ae1SMatthias Ringwald         phase += 2;
149c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
15035fd3fb9SMatthias Ringwald             phase = 0;
15135fd3fb9SMatthias Ringwald         }
15235fd3fb9SMatthias Ringwald     }
15335fd3fb9SMatthias Ringwald }
15435fd3fb9SMatthias Ringwald 
1551bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
1561bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
157*3cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(uint16_t num_samples, int16_t * data){
158249d94cfSMatthias Ringwald     unsigned int i;
1591bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
1601bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
1611bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1621bbecc2bSMatthias Ringwald             phase = 0;
1631bbecc2bSMatthias Ringwald         }
1641bbecc2bSMatthias Ringwald     }
1651bbecc2bSMatthias Ringwald }
1662b89dbfcSMatthias Ringwald #endif
1671bbecc2bSMatthias Ringwald #endif
168dbb41bfeSMilanka Ringwald 
16994381a69SMatthias Ringwald // Audio Playback / Recording
170d861f4bfSMatthias Ringwald 
17194381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){
1722b89dbfcSMatthias Ringwald 
173be030f50SMilanka Ringwald     uint32_t prebuffer_bytes;
174c4e666bcSMatthias Ringwald     switch (negotiated_codec){
175c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
176c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
177c4e666bcSMatthias Ringwald             break;
178c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
179c4e666bcSMatthias Ringwald         default:
180379c5f5fSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
181c4e666bcSMatthias Ringwald             break;
182dbb41bfeSMilanka Ringwald     }
183dbb41bfeSMilanka Ringwald 
184c4e666bcSMatthias Ringwald     // fill with silence while paused
185379c5f5fSMatthias Ringwald     if (audio_output_paused){
186379c5f5fSMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){
187f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
188379c5f5fSMatthias Ringwald            return;
189dbb41bfeSMilanka Ringwald         } else {
190c4e666bcSMatthias Ringwald             // resume playback
191379c5f5fSMatthias Ringwald             audio_output_paused = 0;
192dbb41bfeSMilanka Ringwald         }
193c4e666bcSMatthias Ringwald     }
194c4e666bcSMatthias Ringwald 
195c4e666bcSMatthias Ringwald     // get data from ringbuffer
196c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
197f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
198f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
199f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
200c4e666bcSMatthias Ringwald 
201c4e666bcSMatthias Ringwald     // fill with 0 if not enough
202f55ac442SMatthias Ringwald     if (num_samples){
203f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
204379c5f5fSMatthias Ringwald         audio_output_paused = 1;
205c4e666bcSMatthias Ringwald     }
206379c5f5fSMatthias Ringwald }
2078b29cfc6SMatthias Ringwald 
208379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
20994381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){
210379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
211c4e666bcSMatthias Ringwald }
212379c5f5fSMatthias Ringwald #endif
213c4e666bcSMatthias Ringwald 
214c4e666bcSMatthias Ringwald // return 1 if ok
215379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
216c4e666bcSMatthias Ringwald 
217d365bb51SMatthias Ringwald     // -- output -- //
218d365bb51SMatthias Ringwald 
219379c5f5fSMatthias Ringwald     // init buffers
220379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
221379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2222b89dbfcSMatthias Ringwald 
223d365bb51SMatthias Ringwald     // config and setup audio playback
224d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
225d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2262b89dbfcSMatthias Ringwald 
22794381a69SMatthias Ringwald     audio_sink->init(1, sample_rate, &audio_playback_callback);
228d365bb51SMatthias Ringwald     audio_sink->start_stream();
229379c5f5fSMatthias Ringwald 
230379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
231d365bb51SMatthias Ringwald 
232d365bb51SMatthias Ringwald     // -- input -- //
233d365bb51SMatthias Ringwald 
234d365bb51SMatthias Ringwald     // init buffers
235d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
236d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
2376fb1424bSMatthias Ringwald     audio_input_paused  = 1;
238d365bb51SMatthias Ringwald 
2396fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT
240d365bb51SMatthias Ringwald     // config and setup audio recording
241d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
242d365bb51SMatthias Ringwald     if (!audio_source) return 0;
243d365bb51SMatthias Ringwald 
24494381a69SMatthias Ringwald     audio_source->init(1, sample_rate, &audio_recording_callback);
245d365bb51SMatthias Ringwald     audio_source->start_stream();
2462b89dbfcSMatthias Ringwald #endif
2472b89dbfcSMatthias Ringwald 
248c4e666bcSMatthias Ringwald     return 1;
249c4e666bcSMatthias Ringwald }
2502b89dbfcSMatthias Ringwald 
251379c5f5fSMatthias Ringwald static void audio_terminate(void){
252d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
253d365bb51SMatthias Ringwald     if (!audio_sink) return;
254d365bb51SMatthias Ringwald     audio_sink->close();
255d365bb51SMatthias Ringwald 
256d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
257d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
258d365bb51SMatthias Ringwald     if (!audio_source) return;
259d365bb51SMatthias Ringwald     audio_source->close();
260d365bb51SMatthias Ringwald #endif
2612b89dbfcSMatthias Ringwald }
262c4e666bcSMatthias Ringwald 
263d861f4bfSMatthias Ringwald 
26494381a69SMatthias Ringwald // CVSD - 8 kHz
265fcb08cdbSMilanka Ringwald 
266fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
267c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
268c4e666bcSMatthias Ringwald 
269fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
270c4e666bcSMatthias Ringwald 
2712c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
272c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
2732c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
2742c7ae6e1SMatthias Ringwald #endif
275dbb41bfeSMilanka Ringwald 
276379c5f5fSMatthias Ringwald     audio_initialize(CVSD_SAMPLE_RATE);
277fbc7c9f2SMilanka Ringwald }
278fbc7c9f2SMilanka Ringwald 
279fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
2802c7ae6e1SMatthias Ringwald 
2815303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
2821f8694ccSMatthias Ringwald 
2831f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
2841f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
2851f8694ccSMatthias Ringwald         return;
2861f8694ccSMatthias Ringwald     }
2872c7ae6e1SMatthias Ringwald 
288c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
289379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
2905303ddeeSMatthias Ringwald 
2915303ddeeSMatthias Ringwald     // convert into host endian
2925303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
2935303ddeeSMatthias Ringwald     int i;
2945303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
2955303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
2965303ddeeSMatthias Ringwald     }
2975303ddeeSMatthias Ringwald 
2985f4f94c7SMatthias Ringwald     // treat packet as bad frame if controller does not report 'all good'
2995f4f94c7SMatthias Ringwald     bool bad_frame = (packet[1] & 0x30) != 0;
3005f4f94c7SMatthias Ringwald 
3015f4f94c7SMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out);
3025303ddeeSMatthias Ringwald 
3032c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3042c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3052c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3062c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3072c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3082c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3092c7ae6e1SMatthias Ringwald         wav_writer_close();
3102c7ae6e1SMatthias Ringwald     }
3112c7ae6e1SMatthias Ringwald #endif
3122c7ae6e1SMatthias Ringwald 
313379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
314fcb08cdbSMilanka Ringwald }
315fcb08cdbSMilanka Ringwald 
31694381a69SMatthias Ringwald void sco_demo_fill_payload_CVSD(uint8_t * payload_buffer, uint16_t sco_payload_length){
3172c7ae6e1SMatthias Ringwald 
318*3cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
3196fb1424bSMatthias Ringwald #define REFILL_SAMPLES 16
3206fb1424bSMatthias Ringwald     // re-fill with sine
3216fb1424bSMatthias Ringwald     uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2;
3226fb1424bSMatthias Ringwald     while (samples_free > 0){
3236fb1424bSMatthias Ringwald         int16_t samples_buffer[REFILL_SAMPLES];
3246fb1424bSMatthias Ringwald         uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES);
325*3cf06407SMatthias Ringwald         (*sco_demo_audio_generator)(samples_to_add, samples_buffer);
3266fb1424bSMatthias Ringwald         btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2);
3276fb1424bSMatthias Ringwald         samples_free -= samples_to_add;
3286fb1424bSMatthias Ringwald     }
3291a919128SMatthias Ringwald #endif
3302b89dbfcSMatthias Ringwald 
3316fb1424bSMatthias Ringwald     // resume if pre-buffer is filled
332379c5f5fSMatthias Ringwald     if (audio_input_paused){
333379c5f5fSMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
3342b89dbfcSMatthias Ringwald             // resume sending
335379c5f5fSMatthias Ringwald             audio_input_paused = 0;
3362b89dbfcSMatthias Ringwald         }
3372b89dbfcSMatthias Ringwald     }
3382b89dbfcSMatthias Ringwald 
3396fb1424bSMatthias Ringwald     uint16_t bytes_to_copy = sco_payload_length;
3406fb1424bSMatthias Ringwald 
3412b89dbfcSMatthias Ringwald     // get data from ringbuffer
3422b89dbfcSMatthias Ringwald     uint16_t pos = 0;
343379c5f5fSMatthias Ringwald     if (!audio_input_paused){
3446fb1424bSMatthias Ringwald         uint16_t samples_to_copy = sco_payload_length / 2;
3452b89dbfcSMatthias Ringwald         uint32_t bytes_read = 0;
3466fb1424bSMatthias Ringwald         btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read);
3478fd6902dSMatthias Ringwald         // flip 16 on big endian systems
3488fd6902dSMatthias Ringwald         // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
3498fd6902dSMatthias Ringwald         if (btstack_is_big_endian()){
3506fb1424bSMatthias Ringwald             uint16_t i;
3516fb1424bSMatthias Ringwald             for (i=0;i<samples_to_copy/2;i+=2){
3526fb1424bSMatthias Ringwald                 uint8_t tmp           = payload_buffer[i*2];
3536fb1424bSMatthias Ringwald                 payload_buffer[i*2]   = payload_buffer[i*2+1];
3546fb1424bSMatthias Ringwald                 payload_buffer[i*2+1] = tmp;
3558fd6902dSMatthias Ringwald             }
3568fd6902dSMatthias Ringwald         }
3572b89dbfcSMatthias Ringwald         bytes_to_copy -= bytes_read;
3582b89dbfcSMatthias Ringwald         pos           += bytes_read;
3592b89dbfcSMatthias Ringwald     }
3602b89dbfcSMatthias Ringwald 
3612b89dbfcSMatthias Ringwald     // fill with 0 if not enough
3622b89dbfcSMatthias Ringwald     if (bytes_to_copy){
3636fb1424bSMatthias Ringwald         memset(payload_buffer + pos, 0, bytes_to_copy);
364379c5f5fSMatthias Ringwald         audio_input_paused = 1;
3652b89dbfcSMatthias Ringwald     }
3662b89dbfcSMatthias Ringwald }
36794381a69SMatthias Ringwald 
36894381a69SMatthias Ringwald // mSBC - 16 kHz
36994381a69SMatthias Ringwald 
37094381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
37194381a69SMatthias Ringwald 
37294381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
37394381a69SMatthias Ringwald     UNUSED(context);
37494381a69SMatthias Ringwald     UNUSED(sample_rate);
37594381a69SMatthias Ringwald     UNUSED(data);
37694381a69SMatthias Ringwald     UNUSED(num_samples);
37794381a69SMatthias Ringwald     UNUSED(num_channels);
37894381a69SMatthias Ringwald 
37994381a69SMatthias Ringwald     // samples in callback in host endianess, ready for playback
38094381a69SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
38194381a69SMatthias Ringwald 
38294381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
38394381a69SMatthias Ringwald     if (!num_samples_to_write) return;
38494381a69SMatthias Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
38594381a69SMatthias Ringwald     num_samples_to_write -= num_samples;
38694381a69SMatthias Ringwald     wav_writer_write_int16(num_samples, data);
38794381a69SMatthias Ringwald     if (num_samples_to_write == 0){
38894381a69SMatthias Ringwald         wav_writer_close();
389f7c85330SMatthias Ringwald     }
39094381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3911a919128SMatthias Ringwald }
39294381a69SMatthias Ringwald 
39394381a69SMatthias Ringwald static void sco_demo_init_mSBC(void){
39494381a69SMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
39594381a69SMatthias Ringwald 
39694381a69SMatthias Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
39794381a69SMatthias Ringwald     hfp_msbc_init();
39894381a69SMatthias Ringwald 
39994381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
40094381a69SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
40194381a69SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
402f7c85330SMatthias Ringwald #endif
403220eb563SMilanka Ringwald 
40494381a69SMatthias Ringwald     audio_initialize(MSBC_SAMPLE_RATE);
40594381a69SMatthias Ringwald }
40694381a69SMatthias Ringwald 
40794381a69SMatthias Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
40894381a69SMatthias Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
40994381a69SMatthias Ringwald }
41094381a69SMatthias Ringwald 
41194381a69SMatthias Ringwald void sco_demo_fill_payload_mSBC(uint8_t * payload_buffer, uint16_t sco_payload_length){
41294381a69SMatthias Ringwald 
413*3cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
414b89b876fSMatthias Ringwald #define REFILL_SAMPLES 16
415b89b876fSMatthias Ringwald     // re-fill with sine
416b89b876fSMatthias Ringwald     uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2;
417b89b876fSMatthias Ringwald     while (samples_free > 0){
418b89b876fSMatthias Ringwald         int16_t samples_buffer[REFILL_SAMPLES];
419b89b876fSMatthias Ringwald         uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES);
420*3cf06407SMatthias Ringwald         (*sco_demo_audio_generator)(samples_to_add, samples_buffer);
421b89b876fSMatthias Ringwald         btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2);
422b89b876fSMatthias Ringwald         samples_free -= samples_to_add;
42394381a69SMatthias Ringwald     }
42494381a69SMatthias Ringwald #endif
42594381a69SMatthias Ringwald 
426b89b876fSMatthias Ringwald     // resume if pre-buffer is filled
42794381a69SMatthias Ringwald     if (audio_input_paused){
42894381a69SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
42994381a69SMatthias Ringwald             // resume sending
43094381a69SMatthias Ringwald             audio_input_paused = 0;
43194381a69SMatthias Ringwald         }
43294381a69SMatthias Ringwald     }
43394381a69SMatthias Ringwald     if (!audio_input_paused){
43494381a69SMatthias Ringwald         int num_samples = hfp_msbc_num_audio_samples_per_frame();
435b89b876fSMatthias Ringwald         btstack_assert(num_samples <= MAX_NUM_MSBC_SAMPLES);
43694381a69SMatthias 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)){
43794381a69SMatthias Ringwald             int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
43894381a69SMatthias Ringwald             uint32_t bytes_read;
43994381a69SMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
44094381a69SMatthias Ringwald             hfp_msbc_encode_audio_frame(sample_buffer);
44194381a69SMatthias Ringwald             num_audio_frames++;
44294381a69SMatthias Ringwald         }
443b89b876fSMatthias Ringwald         btstack_assert(hfp_msbc_num_bytes_in_stream() >= sco_payload_length);
44494381a69SMatthias Ringwald     }
445b89b876fSMatthias Ringwald 
446b89b876fSMatthias Ringwald     // get data from encoder, fill with 0 if not enough
44794381a69SMatthias Ringwald     if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
44894381a69SMatthias Ringwald         // just send '0's
44994381a69SMatthias Ringwald         memset(payload_buffer, 0, sco_payload_length);
45094381a69SMatthias Ringwald         audio_input_paused = 1;
45194381a69SMatthias Ringwald     } else {
45294381a69SMatthias Ringwald         hfp_msbc_read_from_stream(payload_buffer, sco_payload_length);
45394381a69SMatthias Ringwald     }
45494381a69SMatthias Ringwald }
45594381a69SMatthias Ringwald 
45694381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
45794381a69SMatthias Ringwald 
45894381a69SMatthias Ringwald void sco_demo_init(void){
45994381a69SMatthias Ringwald 
46094381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS
46194381a69SMatthias Ringwald     printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n");
46294381a69SMatthias Ringwald     gap_secure_connections_enable(false);
46394381a69SMatthias Ringwald #endif
46494381a69SMatthias Ringwald 
46594381a69SMatthias Ringwald 	// status
46694381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
46794381a69SMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
46894381a69SMatthias Ringwald #endif
46994381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
47094381a69SMatthias Ringwald     if (btstack_audio_sink_get_instance()){
47194381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
47294381a69SMatthias Ringwald     } else {
47394381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, hexdump received data.\n");
47494381a69SMatthias Ringwald     }
47594381a69SMatthias Ringwald #endif
47694381a69SMatthias Ringwald 
47794381a69SMatthias Ringwald     // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode)
47894381a69SMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
47994381a69SMatthias Ringwald }
48094381a69SMatthias Ringwald 
48194381a69SMatthias Ringwald void sco_demo_set_codec(uint8_t codec){
48294381a69SMatthias Ringwald     if (negotiated_codec == codec) return;
48394381a69SMatthias Ringwald     negotiated_codec = codec;
48494381a69SMatthias Ringwald 
48594381a69SMatthias Ringwald     switch (negotiated_codec){
48694381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
487*3cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
488*3cf06407SMatthias Ringwald             sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_8000_hz_host_endian;
489*3cf06407SMatthias Ringwald #endif
49094381a69SMatthias Ringwald             sco_demo_init_CVSD();
49194381a69SMatthias Ringwald             break;
49294381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
49394381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
494*3cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
495*3cf06407SMatthias Ringwald             sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_16000_hz_host_endian;
496*3cf06407SMatthias Ringwald #endif
49794381a69SMatthias Ringwald             sco_demo_init_mSBC();
49894381a69SMatthias Ringwald             break;
49994381a69SMatthias Ringwald #endif
50094381a69SMatthias Ringwald         default:
50194381a69SMatthias Ringwald             btstack_assert(false);
50294381a69SMatthias Ringwald             break;
50394381a69SMatthias Ringwald     }
50494381a69SMatthias Ringwald }
50594381a69SMatthias Ringwald 
50694381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
50794381a69SMatthias Ringwald     static uint32_t packets = 0;
50894381a69SMatthias Ringwald     static uint32_t crc_errors = 0;
50994381a69SMatthias Ringwald     static uint32_t data_received = 0;
51094381a69SMatthias Ringwald     static uint32_t byte_errors = 0;
51194381a69SMatthias Ringwald 
51294381a69SMatthias Ringwald     count_received++;
51394381a69SMatthias Ringwald 
51494381a69SMatthias Ringwald     data_received += size - 3;
51594381a69SMatthias Ringwald     packets++;
51694381a69SMatthias Ringwald     if (data_received > 100000){
51794381a69SMatthias 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);
51894381a69SMatthias Ringwald         crc_errors = 0;
51994381a69SMatthias Ringwald         byte_errors = 0;
52094381a69SMatthias Ringwald         data_received = 0;
52194381a69SMatthias Ringwald         packets = 0;
52294381a69SMatthias Ringwald     }
52394381a69SMatthias Ringwald 
52494381a69SMatthias Ringwald     switch (negotiated_codec){
52594381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
52694381a69SMatthias Ringwald             sco_demo_receive_CVSD(packet, size);
52794381a69SMatthias Ringwald             break;
52894381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
52994381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
53094381a69SMatthias Ringwald             sco_demo_receive_mSBC(packet, size);
53194381a69SMatthias Ringwald             break;
53294381a69SMatthias Ringwald #endif
53394381a69SMatthias Ringwald         default:
53494381a69SMatthias Ringwald             btstack_assert(false);
53594381a69SMatthias Ringwald             break;
53694381a69SMatthias Ringwald     }
53794381a69SMatthias Ringwald }
53894381a69SMatthias Ringwald 
53994381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
54094381a69SMatthias Ringwald 
54194381a69SMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
54294381a69SMatthias Ringwald 
54394381a69SMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
54494381a69SMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
54594381a69SMatthias Ringwald 
54694381a69SMatthias Ringwald     hci_reserve_packet_buffer();
54794381a69SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
54894381a69SMatthias Ringwald 
54994381a69SMatthias Ringwald     switch (negotiated_codec){
55094381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
55194381a69SMatthias Ringwald             sco_demo_fill_payload_CVSD(&sco_packet[3], sco_payload_length);
55294381a69SMatthias Ringwald             break;
55394381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
55494381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
55594381a69SMatthias Ringwald             sco_demo_fill_payload_mSBC(&sco_packet[3], sco_payload_length);
55694381a69SMatthias Ringwald             break;
55794381a69SMatthias Ringwald #endif
55894381a69SMatthias Ringwald         default:
55994381a69SMatthias Ringwald             btstack_assert(false);
56094381a69SMatthias Ringwald             break;
56194381a69SMatthias Ringwald     }
5622b89dbfcSMatthias Ringwald 
563c4e666bcSMatthias Ringwald     // set handle + flags
564c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
565c4e666bcSMatthias Ringwald     // set len
566c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
567c4e666bcSMatthias Ringwald     // finally send packet
568f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
569f7c85330SMatthias Ringwald 
570f7c85330SMatthias Ringwald     // request another send event
571f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
572f7c85330SMatthias Ringwald 
5734a96141eSMatthias Ringwald     count_sent++;
57494381a69SMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) {
57594381a69SMatthias Ringwald         printf("SCO: sent %u, received %u\n", count_sent, count_received);
57694381a69SMatthias Ringwald     }
577f7c85330SMatthias Ringwald }
578f7c85330SMatthias Ringwald 
57994381a69SMatthias Ringwald void sco_demo_close(void){
58094381a69SMatthias Ringwald     printf("SCO demo close\n");
5811a919128SMatthias Ringwald 
58294381a69SMatthias Ringwald     printf("SCO demo statistics: ");
583c4e666bcSMatthias Ringwald     switch (negotiated_codec){
58494381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
58594381a69SMatthias 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);
58694381a69SMatthias Ringwald             break;
5871bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
588c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
58994381a69SMatthias 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);
590c4e666bcSMatthias Ringwald             break;
5911bbecc2bSMatthias Ringwald #endif
592c4e666bcSMatthias Ringwald         default:
59394381a69SMatthias Ringwald             btstack_assert(false);
594c4e666bcSMatthias Ringwald             break;
5958b29cfc6SMatthias Ringwald     }
59694381a69SMatthias Ringwald 
59794381a69SMatthias Ringwald     negotiated_codec = -1;
59894381a69SMatthias Ringwald 
59994381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
60094381a69SMatthias Ringwald     wav_writer_close();
6018b29cfc6SMatthias Ringwald #endif
6028b29cfc6SMatthias Ringwald 
60394381a69SMatthias Ringwald     audio_terminate();
604f7c85330SMatthias Ringwald }
605