xref: /btstack/example/sco_demo_util.c (revision 94381a697821095e6e0bfd686d9c2a71486b6ac0)
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
67*94381a69SMatthias 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
104379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
105379c5f5fSMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2*8000];  // full second input buffer
106379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
107f7c85330SMatthias Ringwald #endif
108f7c85330SMatthias Ringwald 
109fcb08cdbSMilanka Ringwald static int count_sent = 0;
110fcb08cdbSMilanka Ringwald static int count_received = 0;
111c4e666bcSMatthias Ringwald static int negotiated_codec = -1;
112c4e666bcSMatthias Ringwald 
1131bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
114379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
1151bbecc2bSMatthias Ringwald #endif
1161bbecc2bSMatthias Ringwald 
117379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
118379c5f5fSMatthias Ringwald 
119379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8)
120fcb08cdbSMilanka Ringwald 
1212b89dbfcSMatthias Ringwald int num_samples_to_write;
1222b89dbfcSMatthias Ringwald int num_audio_frames;
1232b89dbfcSMatthias Ringwald 
124f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
125d6a06398SMatthias Ringwald 
126*94381a69SMatthias Ringwald unsigned int phase;
127*94381a69SMatthias Ringwald 
1287556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz
129c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
1307556ab9fSMatthias Ringwald      0,   3135,   6237,   9270,  12202,  14999,  17633,  20073,  22294,  24270,
1317556ab9fSMatthias Ringwald  25980,  27406,  28531,  29344,  29835,  30000,  29835,  29344,  28531,  27406,
1327556ab9fSMatthias Ringwald  25980,  24270,  22294,  20073,  17633,  14999,  12202,   9270,   6237,   3135,
1337556ab9fSMatthias Ringwald      0,  -3135,  -6237,  -9270, -12202, -14999, -17633, -20073, -22294, -24270,
1347556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406,
1357556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202,  -9270,  -6237,  -3135,
13635fd3fb9SMatthias Ringwald };
13735fd3fb9SMatthias Ringwald 
13859c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian
139adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){
140249d94cfSMatthias Ringwald     unsigned int i;
14159c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
14259c97ae1SMatthias Ringwald         int16_t sample = sine_int16_at_16000hz[phase];
143adaba9f3SMatthias Ringwald         little_endian_store_16(data, i * 2, sample);
14459c97ae1SMatthias Ringwald         // ony use every second sample from 16khz table to get 8khz
14559c97ae1SMatthias Ringwald         phase += 2;
146c4e666bcSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
14735fd3fb9SMatthias Ringwald             phase = 0;
14835fd3fb9SMatthias Ringwald         }
14935fd3fb9SMatthias Ringwald     }
15035fd3fb9SMatthias Ringwald }
15135fd3fb9SMatthias Ringwald 
1521bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess
1531bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
154249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){
155249d94cfSMatthias Ringwald     unsigned int i;
1561bbecc2bSMatthias Ringwald     for (i=0; i < num_samples; i++){
1571bbecc2bSMatthias Ringwald         data[i] = sine_int16_at_16000hz[phase++];
1581bbecc2bSMatthias Ringwald         if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1591bbecc2bSMatthias Ringwald             phase = 0;
1601bbecc2bSMatthias Ringwald         }
1611bbecc2bSMatthias Ringwald     }
1621bbecc2bSMatthias Ringwald }
1632b89dbfcSMatthias Ringwald #endif
1641bbecc2bSMatthias Ringwald #endif
165dbb41bfeSMilanka Ringwald 
166*94381a69SMatthias Ringwald // Audio Playback / Recording
167d861f4bfSMatthias Ringwald 
168*94381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){
1692b89dbfcSMatthias Ringwald 
170be030f50SMilanka Ringwald     uint32_t prebuffer_bytes;
171c4e666bcSMatthias Ringwald     switch (negotiated_codec){
172c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
173c4e666bcSMatthias Ringwald             prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES;
174c4e666bcSMatthias Ringwald             break;
175c4e666bcSMatthias Ringwald         case HFP_CODEC_CVSD:
176c4e666bcSMatthias Ringwald         default:
177379c5f5fSMatthias Ringwald             prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES;
178c4e666bcSMatthias Ringwald             break;
179dbb41bfeSMilanka Ringwald     }
180dbb41bfeSMilanka Ringwald 
181c4e666bcSMatthias Ringwald     // fill with silence while paused
182379c5f5fSMatthias Ringwald     if (audio_output_paused){
183379c5f5fSMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){
184f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
185379c5f5fSMatthias Ringwald            return;
186dbb41bfeSMilanka Ringwald         } else {
187c4e666bcSMatthias Ringwald             // resume playback
188379c5f5fSMatthias Ringwald             audio_output_paused = 0;
189dbb41bfeSMilanka Ringwald         }
190c4e666bcSMatthias Ringwald     }
191c4e666bcSMatthias Ringwald 
192c4e666bcSMatthias Ringwald     // get data from ringbuffer
193c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
194f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
195f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
196f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
197c4e666bcSMatthias Ringwald 
198c4e666bcSMatthias Ringwald     // fill with 0 if not enough
199f55ac442SMatthias Ringwald     if (num_samples){
200f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
201379c5f5fSMatthias Ringwald         audio_output_paused = 1;
202c4e666bcSMatthias Ringwald     }
203379c5f5fSMatthias Ringwald }
2048b29cfc6SMatthias Ringwald 
205379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
206*94381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){
207379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
208c4e666bcSMatthias Ringwald }
209379c5f5fSMatthias Ringwald #endif
210c4e666bcSMatthias Ringwald 
211c4e666bcSMatthias Ringwald // return 1 if ok
212379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
213c4e666bcSMatthias Ringwald 
214d365bb51SMatthias Ringwald     // -- output -- //
215d365bb51SMatthias Ringwald 
216379c5f5fSMatthias Ringwald     // init buffers
217379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
218379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2192b89dbfcSMatthias Ringwald 
220d365bb51SMatthias Ringwald     // config and setup audio playback
221d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
222d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2232b89dbfcSMatthias Ringwald 
224*94381a69SMatthias Ringwald     audio_sink->init(1, sample_rate, &audio_playback_callback);
225d365bb51SMatthias Ringwald     audio_sink->start_stream();
226379c5f5fSMatthias Ringwald 
227379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
228d365bb51SMatthias Ringwald 
229d365bb51SMatthias Ringwald     // -- input -- //
230d365bb51SMatthias Ringwald 
231379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
232d365bb51SMatthias Ringwald     // init buffers
233d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
234d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
235d365bb51SMatthias Ringwald 
236d365bb51SMatthias Ringwald     // config and setup audio recording
237d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
238d365bb51SMatthias Ringwald     if (!audio_source) return 0;
239d365bb51SMatthias Ringwald 
240*94381a69SMatthias Ringwald     audio_source->init(1, sample_rate, &audio_recording_callback);
241d365bb51SMatthias Ringwald     audio_source->start_stream();
242d365bb51SMatthias Ringwald 
243379c5f5fSMatthias Ringwald     audio_input_paused  = 1;
2442b89dbfcSMatthias Ringwald #endif
2452b89dbfcSMatthias Ringwald 
246c4e666bcSMatthias Ringwald     return 1;
247c4e666bcSMatthias Ringwald }
2482b89dbfcSMatthias Ringwald 
249379c5f5fSMatthias Ringwald static void audio_terminate(void){
250d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
251d365bb51SMatthias Ringwald     if (!audio_sink) return;
252d365bb51SMatthias Ringwald     audio_sink->close();
253d365bb51SMatthias Ringwald 
254d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
255d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
256d365bb51SMatthias Ringwald     if (!audio_source) return;
257d365bb51SMatthias Ringwald     audio_source->close();
258d365bb51SMatthias Ringwald #endif
2592b89dbfcSMatthias Ringwald }
260c4e666bcSMatthias Ringwald 
261d861f4bfSMatthias Ringwald 
262*94381a69SMatthias Ringwald // CVSD - 8 kHz
263fcb08cdbSMilanka Ringwald 
264fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
265c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
266c4e666bcSMatthias Ringwald 
267fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
268c4e666bcSMatthias Ringwald 
2692c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
270c4e666bcSMatthias Ringwald     num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
2712c7ae6e1SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE);
2722c7ae6e1SMatthias Ringwald #endif
273dbb41bfeSMilanka Ringwald 
274379c5f5fSMatthias Ringwald     audio_initialize(CVSD_SAMPLE_RATE);
275fbc7c9f2SMilanka Ringwald }
276fbc7c9f2SMilanka Ringwald 
277fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
2782c7ae6e1SMatthias Ringwald 
2795303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
2801f8694ccSMatthias Ringwald 
2811f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
2821f8694ccSMatthias Ringwald         printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n");
2831f8694ccSMatthias Ringwald         return;
2841f8694ccSMatthias Ringwald     }
2852c7ae6e1SMatthias Ringwald 
286c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
287379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
2885303ddeeSMatthias Ringwald 
2895303ddeeSMatthias Ringwald     // convert into host endian
2905303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
2915303ddeeSMatthias Ringwald     int i;
2925303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
2935303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
2945303ddeeSMatthias Ringwald     }
2955303ddeeSMatthias Ringwald 
2965f4f94c7SMatthias Ringwald     // treat packet as bad frame if controller does not report 'all good'
2975f4f94c7SMatthias Ringwald     bool bad_frame = (packet[1] & 0x30) != 0;
2985f4f94c7SMatthias Ringwald 
2995f4f94c7SMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out);
3005303ddeeSMatthias Ringwald 
3012c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3022c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3032c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3042c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3052c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3062c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3072c7ae6e1SMatthias Ringwald         wav_writer_close();
3082c7ae6e1SMatthias Ringwald     }
3092c7ae6e1SMatthias Ringwald #endif
3102c7ae6e1SMatthias Ringwald 
311379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
312fcb08cdbSMilanka Ringwald }
313fcb08cdbSMilanka Ringwald 
314*94381a69SMatthias Ringwald void sco_demo_fill_payload_CVSD(uint8_t * payload_buffer, uint16_t sco_payload_length){
3152c7ae6e1SMatthias Ringwald 
316f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
317379c5f5fSMatthias Ringwald     const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME;
318*94381a69SMatthias Ringwald     sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, payload_buffer);
3191a919128SMatthias Ringwald #endif
3202b89dbfcSMatthias Ringwald 
3212b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
3221befbc1eSMatthias Ringwald     if (btstack_audio_source_get_instance()){
3232b89dbfcSMatthias Ringwald         // CVSD
324abf7f0baSMatthias 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));
3252b89dbfcSMatthias Ringwald         // fill with silence while paused
3262b89dbfcSMatthias Ringwald         int bytes_to_copy = sco_payload_length;
327379c5f5fSMatthias Ringwald         if (audio_input_paused){
328379c5f5fSMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
3292b89dbfcSMatthias Ringwald                 // resume sending
330379c5f5fSMatthias Ringwald                 audio_input_paused = 0;
3312b89dbfcSMatthias Ringwald             }
3322b89dbfcSMatthias Ringwald         }
3332b89dbfcSMatthias Ringwald 
3342b89dbfcSMatthias Ringwald         // get data from ringbuffer
3352b89dbfcSMatthias Ringwald         uint16_t pos = 0;
336*94381a69SMatthias Ringwald         uint8_t * sample_data = payload_buffer;
337379c5f5fSMatthias Ringwald         if (!audio_input_paused){
3382b89dbfcSMatthias Ringwald             uint32_t bytes_read = 0;
339379c5f5fSMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
3408fd6902dSMatthias Ringwald             // flip 16 on big endian systems
3418fd6902dSMatthias Ringwald             // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
3428fd6902dSMatthias Ringwald             if (btstack_is_big_endian()){
3438d3be402SMatthias Ringwald                 unsigned int i;
3448fd6902dSMatthias Ringwald                 for (i=0;i<bytes_read;i+=2){
3458fd6902dSMatthias Ringwald                     uint8_t tmp        = sample_data[i*2];
3468fd6902dSMatthias Ringwald                     sample_data[i*2]   = sample_data[i*2+1];
3478fd6902dSMatthias Ringwald                     sample_data[i*2+1] = tmp;
3488fd6902dSMatthias Ringwald                 }
3498fd6902dSMatthias Ringwald             }
3502b89dbfcSMatthias Ringwald             bytes_to_copy -= bytes_read;
3512b89dbfcSMatthias Ringwald             pos           += bytes_read;
3522b89dbfcSMatthias Ringwald         }
3532b89dbfcSMatthias Ringwald 
3542b89dbfcSMatthias Ringwald         // fill with 0 if not enough
3552b89dbfcSMatthias Ringwald         if (bytes_to_copy){
3568fd6902dSMatthias Ringwald             memset(sample_data + pos, 0, bytes_to_copy);
357379c5f5fSMatthias Ringwald             audio_input_paused = 1;
3582b89dbfcSMatthias Ringwald         }
3592b89dbfcSMatthias Ringwald     }
3601befbc1eSMatthias Ringwald     else {
3612b89dbfcSMatthias Ringwald         // just send '0's
362*94381a69SMatthias Ringwald         memset(payload_buffer, 0, sco_payload_length);
363*94381a69SMatthias Ringwald     }
364*94381a69SMatthias Ringwald #endif
365*94381a69SMatthias Ringwald }
366*94381a69SMatthias Ringwald 
367*94381a69SMatthias Ringwald // mSBC - 16 kHz
368*94381a69SMatthias Ringwald 
369*94381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
370*94381a69SMatthias Ringwald 
371*94381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
372*94381a69SMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){
373*94381a69SMatthias Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
374*94381a69SMatthias Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
375*94381a69SMatthias Ringwald     if (num_samples > MAX_NUM_MSBC_SAMPLES) return;
376*94381a69SMatthias Ringwald     int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
377*94381a69SMatthias Ringwald     sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer);
378*94381a69SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
379*94381a69SMatthias Ringwald     num_audio_frames++;
3801befbc1eSMatthias Ringwald }
3812b89dbfcSMatthias Ringwald #endif
3822b89dbfcSMatthias Ringwald 
383*94381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
384*94381a69SMatthias Ringwald     UNUSED(context);
385*94381a69SMatthias Ringwald     UNUSED(sample_rate);
386*94381a69SMatthias Ringwald     UNUSED(data);
387*94381a69SMatthias Ringwald     UNUSED(num_samples);
388*94381a69SMatthias Ringwald     UNUSED(num_channels);
389*94381a69SMatthias Ringwald 
390*94381a69SMatthias Ringwald     // samples in callback in host endianess, ready for playback
391*94381a69SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
392*94381a69SMatthias Ringwald 
393*94381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
394*94381a69SMatthias Ringwald     if (!num_samples_to_write) return;
395*94381a69SMatthias Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
396*94381a69SMatthias Ringwald     num_samples_to_write -= num_samples;
397*94381a69SMatthias Ringwald     wav_writer_write_int16(num_samples, data);
398*94381a69SMatthias Ringwald     if (num_samples_to_write == 0){
399*94381a69SMatthias Ringwald         wav_writer_close();
400f7c85330SMatthias Ringwald     }
401*94381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
4021a919128SMatthias Ringwald }
403*94381a69SMatthias Ringwald 
404*94381a69SMatthias Ringwald static void sco_demo_init_mSBC(void){
405*94381a69SMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
406*94381a69SMatthias Ringwald 
407*94381a69SMatthias Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
408*94381a69SMatthias Ringwald     hfp_msbc_init();
409*94381a69SMatthias Ringwald 
410*94381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
411*94381a69SMatthias Ringwald     num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
412*94381a69SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE);
413f7c85330SMatthias Ringwald #endif
414220eb563SMilanka Ringwald 
415*94381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
416*94381a69SMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
417*94381a69SMatthias Ringwald #endif
418*94381a69SMatthias Ringwald 
419*94381a69SMatthias Ringwald     audio_initialize(MSBC_SAMPLE_RATE);
420*94381a69SMatthias Ringwald }
421*94381a69SMatthias Ringwald 
422*94381a69SMatthias Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
423*94381a69SMatthias Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
424*94381a69SMatthias Ringwald }
425*94381a69SMatthias Ringwald 
426*94381a69SMatthias Ringwald void sco_demo_fill_payload_mSBC(uint8_t * payload_buffer, uint16_t sco_payload_length){
427*94381a69SMatthias Ringwald 
428*94381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
429*94381a69SMatthias Ringwald     if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
430*94381a69SMatthias Ringwald         log_error("mSBC stream is empty.");
431*94381a69SMatthias Ringwald     }
432*94381a69SMatthias Ringwald     hfp_msbc_read_from_stream(payload_buffer, sco_payload_length);
433*94381a69SMatthias Ringwald     sco_demo_msbc_fill_sine_audio_frame();
434*94381a69SMatthias Ringwald #endif
435*94381a69SMatthias Ringwald 
436*94381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
437*94381a69SMatthias Ringwald     if (btstack_audio_source_get_instance()){
438*94381a69SMatthias Ringwald         // mSBC
439*94381a69SMatthias Ringwald         if (audio_input_paused){
440*94381a69SMatthias Ringwald             if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
441*94381a69SMatthias Ringwald                 // resume sending
442*94381a69SMatthias Ringwald                 audio_input_paused = 0;
443*94381a69SMatthias Ringwald             }
444*94381a69SMatthias Ringwald         }
445*94381a69SMatthias Ringwald         if (!audio_input_paused){
446*94381a69SMatthias Ringwald             int num_samples = hfp_msbc_num_audio_samples_per_frame();
447*94381a69SMatthias Ringwald             if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert
448*94381a69SMatthias 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)){
449*94381a69SMatthias Ringwald                 int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES];
450*94381a69SMatthias Ringwald                 uint32_t bytes_read;
451*94381a69SMatthias Ringwald                 btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
452*94381a69SMatthias Ringwald                 hfp_msbc_encode_audio_frame(sample_buffer);
453*94381a69SMatthias Ringwald                 num_audio_frames++;
454*94381a69SMatthias Ringwald             }
455*94381a69SMatthias Ringwald             if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
456*94381a69SMatthias Ringwald                 log_error("mSBC stream should not be empty.");
457*94381a69SMatthias Ringwald             }
458*94381a69SMatthias Ringwald         }
459*94381a69SMatthias Ringwald     }
460*94381a69SMatthias Ringwald     if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
461*94381a69SMatthias Ringwald         // just send '0's
462*94381a69SMatthias Ringwald         memset(payload_buffer, 0, sco_payload_length);
463*94381a69SMatthias Ringwald         audio_input_paused = 1;
464*94381a69SMatthias Ringwald     } else {
465*94381a69SMatthias Ringwald         hfp_msbc_read_from_stream(payload_buffer, sco_payload_length);
466*94381a69SMatthias Ringwald     }
467*94381a69SMatthias Ringwald #endif
468*94381a69SMatthias Ringwald }
469*94381a69SMatthias Ringwald 
470*94381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
471*94381a69SMatthias Ringwald 
472*94381a69SMatthias Ringwald void sco_demo_init(void){
473*94381a69SMatthias Ringwald 
474*94381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS
475*94381a69SMatthias Ringwald     printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n");
476*94381a69SMatthias Ringwald     gap_secure_connections_enable(false);
477*94381a69SMatthias Ringwald #endif
478*94381a69SMatthias Ringwald 
479*94381a69SMatthias Ringwald 	// status
480*94381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
481*94381a69SMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
482*94381a69SMatthias Ringwald #endif
483*94381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
484*94381a69SMatthias Ringwald     if (btstack_audio_sink_get_instance()){
485*94381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
486*94381a69SMatthias Ringwald     } else {
487*94381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, hexdump received data.\n");
488*94381a69SMatthias Ringwald     }
489*94381a69SMatthias Ringwald #endif
490*94381a69SMatthias Ringwald 
491*94381a69SMatthias Ringwald     // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode)
492*94381a69SMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
493*94381a69SMatthias Ringwald }
494*94381a69SMatthias Ringwald 
495*94381a69SMatthias Ringwald void sco_demo_set_codec(uint8_t codec){
496*94381a69SMatthias Ringwald     if (negotiated_codec == codec) return;
497*94381a69SMatthias Ringwald     negotiated_codec = codec;
498*94381a69SMatthias Ringwald 
499*94381a69SMatthias Ringwald     switch (negotiated_codec){
500*94381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
501*94381a69SMatthias Ringwald             sco_demo_init_CVSD();
502*94381a69SMatthias Ringwald             break;
503*94381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
504*94381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
505*94381a69SMatthias Ringwald             sco_demo_init_mSBC();
506*94381a69SMatthias Ringwald             break;
507*94381a69SMatthias Ringwald #endif
508*94381a69SMatthias Ringwald         default:
509*94381a69SMatthias Ringwald             btstack_assert(false);
510*94381a69SMatthias Ringwald             break;
511*94381a69SMatthias Ringwald     }
512*94381a69SMatthias Ringwald }
513*94381a69SMatthias Ringwald 
514*94381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
515*94381a69SMatthias Ringwald     static uint32_t packets = 0;
516*94381a69SMatthias Ringwald     static uint32_t crc_errors = 0;
517*94381a69SMatthias Ringwald     static uint32_t data_received = 0;
518*94381a69SMatthias Ringwald     static uint32_t byte_errors = 0;
519*94381a69SMatthias Ringwald 
520*94381a69SMatthias Ringwald     count_received++;
521*94381a69SMatthias Ringwald 
522*94381a69SMatthias Ringwald     data_received += size - 3;
523*94381a69SMatthias Ringwald     packets++;
524*94381a69SMatthias Ringwald     if (data_received > 100000){
525*94381a69SMatthias 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);
526*94381a69SMatthias Ringwald         crc_errors = 0;
527*94381a69SMatthias Ringwald         byte_errors = 0;
528*94381a69SMatthias Ringwald         data_received = 0;
529*94381a69SMatthias Ringwald         packets = 0;
530*94381a69SMatthias Ringwald     }
531*94381a69SMatthias Ringwald 
532*94381a69SMatthias Ringwald     switch (negotiated_codec){
533*94381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
534*94381a69SMatthias Ringwald             sco_demo_receive_CVSD(packet, size);
535*94381a69SMatthias Ringwald             break;
536*94381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
537*94381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
538*94381a69SMatthias Ringwald             sco_demo_receive_mSBC(packet, size);
539*94381a69SMatthias Ringwald             break;
540*94381a69SMatthias Ringwald #endif
541*94381a69SMatthias Ringwald         default:
542*94381a69SMatthias Ringwald             btstack_assert(false);
543*94381a69SMatthias Ringwald             break;
544*94381a69SMatthias Ringwald     }
545*94381a69SMatthias Ringwald }
546*94381a69SMatthias Ringwald 
547*94381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
548*94381a69SMatthias Ringwald 
549*94381a69SMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
550*94381a69SMatthias Ringwald 
551*94381a69SMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
552*94381a69SMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
553*94381a69SMatthias Ringwald 
554*94381a69SMatthias Ringwald     hci_reserve_packet_buffer();
555*94381a69SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
556*94381a69SMatthias Ringwald 
557*94381a69SMatthias Ringwald     switch (negotiated_codec){
558*94381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
559*94381a69SMatthias Ringwald             sco_demo_fill_payload_CVSD(&sco_packet[3], sco_payload_length);
560*94381a69SMatthias Ringwald             break;
561*94381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
562*94381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
563*94381a69SMatthias Ringwald             sco_demo_fill_payload_mSBC(&sco_packet[3], sco_payload_length);
564*94381a69SMatthias Ringwald             break;
565*94381a69SMatthias Ringwald #endif
566*94381a69SMatthias Ringwald         default:
567*94381a69SMatthias Ringwald             btstack_assert(false);
568*94381a69SMatthias Ringwald             break;
569*94381a69SMatthias Ringwald     }
5702b89dbfcSMatthias Ringwald 
571c4e666bcSMatthias Ringwald     // set handle + flags
572c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
573c4e666bcSMatthias Ringwald     // set len
574c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
575c4e666bcSMatthias Ringwald     // finally send packet
576f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
577f7c85330SMatthias Ringwald 
578f7c85330SMatthias Ringwald     // request another send event
579f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
580f7c85330SMatthias Ringwald 
5814a96141eSMatthias Ringwald     count_sent++;
582*94381a69SMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) {
583*94381a69SMatthias Ringwald         printf("SCO: sent %u, received %u\n", count_sent, count_received);
584*94381a69SMatthias Ringwald     }
585f7c85330SMatthias Ringwald }
586f7c85330SMatthias Ringwald 
587*94381a69SMatthias Ringwald void sco_demo_close(void){
588*94381a69SMatthias Ringwald     printf("SCO demo close\n");
5891a919128SMatthias Ringwald 
590*94381a69SMatthias Ringwald     printf("SCO demo statistics: ");
591c4e666bcSMatthias Ringwald     switch (negotiated_codec){
592*94381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
593*94381a69SMatthias 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);
594*94381a69SMatthias Ringwald             break;
5951bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
596c4e666bcSMatthias Ringwald         case HFP_CODEC_MSBC:
597*94381a69SMatthias 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);
598c4e666bcSMatthias Ringwald             break;
5991bbecc2bSMatthias Ringwald #endif
600c4e666bcSMatthias Ringwald         default:
601*94381a69SMatthias Ringwald             btstack_assert(false);
602c4e666bcSMatthias Ringwald             break;
6038b29cfc6SMatthias Ringwald     }
604*94381a69SMatthias Ringwald 
605*94381a69SMatthias Ringwald     negotiated_codec = -1;
606*94381a69SMatthias Ringwald 
607*94381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
608*94381a69SMatthias Ringwald     wav_writer_close();
6098b29cfc6SMatthias Ringwald #endif
6108b29cfc6SMatthias Ringwald 
611*94381a69SMatthias Ringwald     audio_terminate();
612f7c85330SMatthias Ringwald }
613