xref: /btstack/example/sco_demo_util.c (revision f0d95bdc335cbf6a1c209a0b20281540b92c2e60)
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"
54*f0d95bdcSMatthias Ringwald #include "classic/hfp_codec.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
681762039cSMatthias Ringwald #define SCO_DEMO_MODE_MODPLAYER  2
69f7c85330SMatthias Ringwald 
70f7c85330SMatthias Ringwald // SCO demo configuration
71d365bb51SMatthias Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_MICROPHONE
72c4e666bcSMatthias Ringwald 
73c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console
74f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD           100
75f7c85330SMatthias Ringwald 
76f55ac442SMatthias Ringwald 
77d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
782c7ae6e1SMatthias Ringwald // length and name of wav file on disk
79c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
808b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
81859f2bc5SMatthias Ringwald #endif
82859f2bc5SMatthias Ringwald 
83c4e666bcSMatthias Ringwald // constants
84c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
85b150a479SMatthias Ringwald #define SAMPLE_RATE_8KHZ        8000
86b150a479SMatthias Ringwald #define SAMPLE_RATE_16KHZ       16000
87379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
88f7c85330SMatthias Ringwald 
89b150a479SMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
90b150a479SMatthias Ringwald #define SCO_PREBUFFER_MS      50
91b150a479SMatthias Ringwald #define PREBUFFER_BYTES_8KHZ  (SCO_PREBUFFER_MS *  SAMPLE_RATE_8KHZ/1000 * BYTES_PER_FRAME)
92b150a479SMatthias Ringwald #define PREBUFFER_BYTES_16KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_16KHZ/1000 * BYTES_PER_FRAME)
93f7c85330SMatthias Ringwald 
949582ae64SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH)
959582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_16KHZ
96*f0d95bdcSMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 120
979582ae64SMatthias Ringwald #else
989582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_8KHZ
99*f0d95bdcSMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 60
1009582ae64SMatthias Ringwald #endif
1019582ae64SMatthias Ringwald 
102bf958e42SMatthias Ringwald static uint16_t              audio_prebuffer_bytes;
103bf958e42SMatthias Ringwald 
1042b89dbfcSMatthias Ringwald // output
105d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
1069582ae64SMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
107379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
1082b89dbfcSMatthias Ringwald 
1092b89dbfcSMatthias Ringwald // input
1102b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
111379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
1123cf06407SMatthias Ringwald #else
1133cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR
1143cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data);
1156fb1424bSMatthias Ringwald #endif
116379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
1179582ae64SMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
118379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
119f7c85330SMatthias Ringwald 
1201762039cSMatthias Ringwald // mod player
1211762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
1221762039cSMatthias Ringwald #include "hxcmod.h"
1231762039cSMatthias Ringwald #include "mods/mod.h"
1241762039cSMatthias Ringwald static modcontext mod_context;
1251762039cSMatthias Ringwald #endif
1261762039cSMatthias Ringwald 
127fcb08cdbSMilanka Ringwald static int count_sent = 0;
128fcb08cdbSMilanka Ringwald static int count_received = 0;
129c4e666bcSMatthias Ringwald 
1301bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
13179cc780fSMatthias Ringwald #define MSBC_MAX_NUM_SAMPLES (16*8)
132379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
1331bbecc2bSMatthias Ringwald #endif
1341bbecc2bSMatthias Ringwald 
135379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
136379c5f5fSMatthias Ringwald 
1372b89dbfcSMatthias Ringwald int num_samples_to_write;
1382b89dbfcSMatthias Ringwald int num_audio_frames;
1392b89dbfcSMatthias Ringwald 
140bf958e42SMatthias Ringwald // generic codec support
141bf958e42SMatthias Ringwald typedef struct {
142bf958e42SMatthias Ringwald     void (*init)(void);
143bf958e42SMatthias Ringwald     void(*receive)(const uint8_t * packet, uint16_t size);
144bf958e42SMatthias Ringwald     void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length);
145bf958e42SMatthias Ringwald     void (*close)(void);
14679cc780fSMatthias Ringwald     //
14779cc780fSMatthias Ringwald     uint16_t sample_rate;
148bf958e42SMatthias Ringwald } codec_support_t;
14979cc780fSMatthias Ringwald 
15079cc780fSMatthias Ringwald // current configuration
151bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL;
152bf958e42SMatthias Ringwald 
153*f0d95bdcSMatthias Ringwald // hfp_codec
154*f0d95bdcSMatthias Ringwald static hfp_codec_t hfp_codec;
155d6a06398SMatthias Ringwald 
1569ad691b0SMatthias Ringwald // Sine Wave
1579ad691b0SMatthias Ringwald 
1589ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
1599ad691b0SMatthias Ringwald static uint16_t sine_wave_phase;
1609ad691b0SMatthias Ringwald static uint16_t sine_wave_steps_per_sample;
1619ad691b0SMatthias Ringwald #define SINE_WAVE_SAMPLE_RATE SAMPLE_RATE_16KHZ
16294381a69SMatthias Ringwald 
1637556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz
164c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
1657556ab9fSMatthias Ringwald      0,   3135,   6237,   9270,  12202,  14999,  17633,  20073,  22294,  24270,
1667556ab9fSMatthias Ringwald  25980,  27406,  28531,  29344,  29835,  30000,  29835,  29344,  28531,  27406,
1677556ab9fSMatthias Ringwald  25980,  24270,  22294,  20073,  17633,  14999,  12202,   9270,   6237,   3135,
1687556ab9fSMatthias Ringwald      0,  -3135,  -6237,  -9270, -12202, -14999, -17633, -20073, -22294, -24270,
1697556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406,
1707556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202,  -9270,  -6237,  -3135,
17135fd3fb9SMatthias Ringwald };
17235fd3fb9SMatthias Ringwald 
1739ad691b0SMatthias Ringwald static void sco_demo_sine_wave_host_endian(uint16_t num_samples, int16_t * data){
174249d94cfSMatthias Ringwald     unsigned int i;
17559c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
1769ad691b0SMatthias Ringwald         data[i] = sine_int16_at_16000hz[sine_wave_phase];
1779ad691b0SMatthias Ringwald         sine_wave_phase += sine_wave_steps_per_sample;
1789ad691b0SMatthias Ringwald         if (sine_wave_phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
1799ad691b0SMatthias Ringwald             sine_wave_phase = 0;
18035fd3fb9SMatthias Ringwald         }
18135fd3fb9SMatthias Ringwald     }
18235fd3fb9SMatthias Ringwald }
1831bbecc2bSMatthias Ringwald #endif
184dbb41bfeSMilanka Ringwald 
1851762039cSMatthias Ringwald // Mod Player
1861762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
1871762039cSMatthias Ringwald #define NUM_SAMPLES_GENERATOR_BUFFER 30
1881762039cSMatthias Ringwald static void sco_demo_modplayer(uint16_t num_samples, int16_t * data){
1891762039cSMatthias Ringwald     // mix down stereo
1901762039cSMatthias Ringwald     signed short samples[NUM_SAMPLES_GENERATOR_BUFFER * 2];
1911762039cSMatthias Ringwald     while (num_samples > 0){
1921762039cSMatthias Ringwald         uint16_t next_samples = btstack_min(num_samples, NUM_SAMPLES_GENERATOR_BUFFER);
1931762039cSMatthias Ringwald     	hxcmod_fillbuffer(&mod_context, (unsigned short *) samples, next_samples, NULL);
1941762039cSMatthias Ringwald         num_samples -= next_samples;
1951762039cSMatthias Ringwald         uint16_t i;
1961762039cSMatthias Ringwald         for (i=0;i<next_samples;i++){
1971762039cSMatthias Ringwald             int32_t left  = samples[2*i + 0];
1981762039cSMatthias Ringwald             int32_t right = samples[2*i + 1];
1991762039cSMatthias Ringwald             data[i] = (int16_t)((left + right) / 2);
2001762039cSMatthias Ringwald         }
2011762039cSMatthias Ringwald     }
2021762039cSMatthias Ringwald }
2031762039cSMatthias Ringwald #endif
2041762039cSMatthias Ringwald 
20594381a69SMatthias Ringwald // Audio Playback / Recording
206d861f4bfSMatthias Ringwald 
20794381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){
2082b89dbfcSMatthias Ringwald 
209c4e666bcSMatthias Ringwald     // fill with silence while paused
210379c5f5fSMatthias Ringwald     if (audio_output_paused){
211bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){
212f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
213379c5f5fSMatthias Ringwald            return;
214dbb41bfeSMilanka Ringwald         } else {
215c4e666bcSMatthias Ringwald             // resume playback
216379c5f5fSMatthias Ringwald             audio_output_paused = 0;
217dbb41bfeSMilanka Ringwald         }
218c4e666bcSMatthias Ringwald     }
219c4e666bcSMatthias Ringwald 
220c4e666bcSMatthias Ringwald     // get data from ringbuffer
221c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
222f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
223f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
224f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
225c4e666bcSMatthias Ringwald 
226c4e666bcSMatthias Ringwald     // fill with 0 if not enough
227f55ac442SMatthias Ringwald     if (num_samples){
228f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
229379c5f5fSMatthias Ringwald         audio_output_paused = 1;
230c4e666bcSMatthias Ringwald     }
231379c5f5fSMatthias Ringwald }
2328b29cfc6SMatthias Ringwald 
233379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
23494381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){
235379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
236c4e666bcSMatthias Ringwald }
237379c5f5fSMatthias Ringwald #endif
238c4e666bcSMatthias Ringwald 
239c4e666bcSMatthias Ringwald // return 1 if ok
240379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
241c4e666bcSMatthias Ringwald 
242d365bb51SMatthias Ringwald     // -- output -- //
243d365bb51SMatthias Ringwald 
244379c5f5fSMatthias Ringwald     // init buffers
245379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
246379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2472b89dbfcSMatthias Ringwald 
248d365bb51SMatthias Ringwald     // config and setup audio playback
249d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
250d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2512b89dbfcSMatthias Ringwald 
25294381a69SMatthias Ringwald     audio_sink->init(1, sample_rate, &audio_playback_callback);
253d365bb51SMatthias Ringwald     audio_sink->start_stream();
254379c5f5fSMatthias Ringwald 
255379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
256d365bb51SMatthias Ringwald 
257d365bb51SMatthias Ringwald     // -- input -- //
258d365bb51SMatthias Ringwald 
259d365bb51SMatthias Ringwald     // init buffers
260d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
261d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
2626fb1424bSMatthias Ringwald     audio_input_paused  = 1;
263d365bb51SMatthias Ringwald 
2646fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT
265d365bb51SMatthias Ringwald     // config and setup audio recording
266d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
267d365bb51SMatthias Ringwald     if (!audio_source) return 0;
268d365bb51SMatthias Ringwald 
26994381a69SMatthias Ringwald     audio_source->init(1, sample_rate, &audio_recording_callback);
270d365bb51SMatthias Ringwald     audio_source->start_stream();
2712b89dbfcSMatthias Ringwald #endif
2722b89dbfcSMatthias Ringwald 
273c4e666bcSMatthias Ringwald     return 1;
274c4e666bcSMatthias Ringwald }
2752b89dbfcSMatthias Ringwald 
276379c5f5fSMatthias Ringwald static void audio_terminate(void){
277d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
278d365bb51SMatthias Ringwald     if (!audio_sink) return;
279d365bb51SMatthias Ringwald     audio_sink->close();
280d365bb51SMatthias Ringwald 
281d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
282d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
283d365bb51SMatthias Ringwald     if (!audio_source) return;
284d365bb51SMatthias Ringwald     audio_source->close();
285d365bb51SMatthias Ringwald #endif
2862b89dbfcSMatthias Ringwald }
287c4e666bcSMatthias Ringwald 
288d861f4bfSMatthias Ringwald 
28994381a69SMatthias Ringwald // CVSD - 8 kHz
290fcb08cdbSMilanka Ringwald 
291bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){
292c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
293fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
294fbc7c9f2SMilanka Ringwald }
295fbc7c9f2SMilanka Ringwald 
296bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){
2972c7ae6e1SMatthias Ringwald 
2985303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
2991f8694ccSMatthias Ringwald 
3001f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
301bf958e42SMatthias Ringwald         printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n");
3021f8694ccSMatthias Ringwald         return;
3031f8694ccSMatthias Ringwald     }
3042c7ae6e1SMatthias Ringwald 
305c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
306379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
3075303ddeeSMatthias Ringwald 
3085303ddeeSMatthias Ringwald     // convert into host endian
3095303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
3105303ddeeSMatthias Ringwald     int i;
3115303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
3125303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
3135303ddeeSMatthias Ringwald     }
3145303ddeeSMatthias Ringwald 
3155f4f94c7SMatthias Ringwald     // treat packet as bad frame if controller does not report 'all good'
3165f4f94c7SMatthias Ringwald     bool bad_frame = (packet[1] & 0x30) != 0;
3175f4f94c7SMatthias Ringwald 
3185f4f94c7SMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out);
3195303ddeeSMatthias Ringwald 
3202c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3212c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3222c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3232c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3242c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3252c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3262c7ae6e1SMatthias Ringwald         wav_writer_close();
3272c7ae6e1SMatthias Ringwald     }
3282c7ae6e1SMatthias Ringwald #endif
3292c7ae6e1SMatthias Ringwald 
330379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
331fcb08cdbSMilanka Ringwald }
332fcb08cdbSMilanka Ringwald 
333bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
3346fb1424bSMatthias Ringwald     uint16_t bytes_to_copy = sco_payload_length;
3356fb1424bSMatthias Ringwald 
3362b89dbfcSMatthias Ringwald     // get data from ringbuffer
3372b89dbfcSMatthias Ringwald     uint16_t pos = 0;
338379c5f5fSMatthias Ringwald     if (!audio_input_paused){
3396fb1424bSMatthias Ringwald         uint16_t samples_to_copy = sco_payload_length / 2;
3402b89dbfcSMatthias Ringwald         uint32_t bytes_read = 0;
3416fb1424bSMatthias Ringwald         btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read);
3428fd6902dSMatthias Ringwald         // flip 16 on big endian systems
3438fd6902dSMatthias Ringwald         // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
3448fd6902dSMatthias Ringwald         if (btstack_is_big_endian()){
3456fb1424bSMatthias Ringwald             uint16_t i;
3466fb1424bSMatthias Ringwald             for (i=0;i<samples_to_copy/2;i+=2){
3476fb1424bSMatthias Ringwald                 uint8_t tmp           = payload_buffer[i*2];
3486fb1424bSMatthias Ringwald                 payload_buffer[i*2]   = payload_buffer[i*2+1];
3496fb1424bSMatthias Ringwald                 payload_buffer[i*2+1] = tmp;
3508fd6902dSMatthias Ringwald             }
3518fd6902dSMatthias Ringwald         }
3522b89dbfcSMatthias Ringwald         bytes_to_copy -= bytes_read;
3532b89dbfcSMatthias Ringwald         pos           += bytes_read;
3542b89dbfcSMatthias Ringwald     }
3552b89dbfcSMatthias Ringwald 
3562b89dbfcSMatthias Ringwald     // fill with 0 if not enough
3572b89dbfcSMatthias Ringwald     if (bytes_to_copy){
3586fb1424bSMatthias Ringwald         memset(payload_buffer + pos, 0, bytes_to_copy);
359379c5f5fSMatthias Ringwald         audio_input_paused = 1;
3602b89dbfcSMatthias Ringwald     }
3612b89dbfcSMatthias Ringwald }
36294381a69SMatthias Ringwald 
363bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){
364bf958e42SMatthias 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);
365bf958e42SMatthias Ringwald }
366bf958e42SMatthias Ringwald 
367bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = {
368bf958e42SMatthias Ringwald         .init         = &sco_demo_cvsd_init,
369bf958e42SMatthias Ringwald         .receive      = &sco_demo_cvsd_receive,
370bf958e42SMatthias Ringwald         .fill_payload = &sco_demo_cvsd_fill_payload,
37179cc780fSMatthias Ringwald         .close        = &sco_demo_cvsd_close,
37279cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_8KHZ
373bf958e42SMatthias Ringwald };
374bf958e42SMatthias Ringwald 
37594381a69SMatthias Ringwald // mSBC - 16 kHz
37694381a69SMatthias Ringwald 
37794381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
37894381a69SMatthias Ringwald 
37994381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
38094381a69SMatthias Ringwald     UNUSED(context);
38194381a69SMatthias Ringwald     UNUSED(sample_rate);
38294381a69SMatthias Ringwald     UNUSED(data);
38394381a69SMatthias Ringwald     UNUSED(num_samples);
38494381a69SMatthias Ringwald     UNUSED(num_channels);
38594381a69SMatthias Ringwald 
38694381a69SMatthias Ringwald     // samples in callback in host endianess, ready for playback
38794381a69SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
38894381a69SMatthias Ringwald 
38994381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
39094381a69SMatthias Ringwald     if (!num_samples_to_write) return;
39194381a69SMatthias Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
39294381a69SMatthias Ringwald     num_samples_to_write -= num_samples;
39394381a69SMatthias Ringwald     wav_writer_write_int16(num_samples, data);
39494381a69SMatthias Ringwald     if (num_samples_to_write == 0){
39594381a69SMatthias Ringwald         wav_writer_close();
396f7c85330SMatthias Ringwald     }
39794381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3981a919128SMatthias Ringwald }
39994381a69SMatthias Ringwald 
400bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){
40194381a69SMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
40294381a69SMatthias Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
403*f0d95bdcSMatthias Ringwald     hfp_codec_init(&hfp_codec, HFP_CODEC_MSBC);
40494381a69SMatthias Ringwald }
40594381a69SMatthias Ringwald 
406bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){
40794381a69SMatthias Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
40894381a69SMatthias Ringwald }
40994381a69SMatthias Ringwald 
410bf958e42SMatthias Ringwald void sco_demo_msbc_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
41194381a69SMatthias Ringwald     if (!audio_input_paused){
412*f0d95bdcSMatthias Ringwald         int num_samples = hfp_codec_num_audio_samples_per_frame(&hfp_codec);
413*f0d95bdcSMatthias Ringwald         btstack_assert(num_samples <= SAMPLES_PER_FRAME_MAX);
414*f0d95bdcSMatthias Ringwald         uint16_t samples_available = btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) / BYTES_PER_FRAME;
415*f0d95bdcSMatthias Ringwald         if (hfp_codec_can_encode_audio_frame_now(&hfp_codec) && samples_available >= num_samples){
416*f0d95bdcSMatthias Ringwald             int16_t sample_buffer[SAMPLES_PER_FRAME_MAX];
41794381a69SMatthias Ringwald             uint32_t bytes_read;
41894381a69SMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
419*f0d95bdcSMatthias Ringwald             hfp_codec_encode_audio_frame(&hfp_codec, sample_buffer);
42094381a69SMatthias Ringwald             num_audio_frames++;
42194381a69SMatthias Ringwald         }
42294381a69SMatthias Ringwald     }
423b89b876fSMatthias Ringwald 
424b89b876fSMatthias Ringwald     // get data from encoder, fill with 0 if not enough
425*f0d95bdcSMatthias Ringwald     if (audio_input_paused || hfp_codec_num_bytes_available(&hfp_codec) < sco_payload_length){
42694381a69SMatthias Ringwald         // just send '0's
42794381a69SMatthias Ringwald         memset(payload_buffer, 0, sco_payload_length);
42894381a69SMatthias Ringwald         audio_input_paused = 1;
42994381a69SMatthias Ringwald     } else {
430*f0d95bdcSMatthias Ringwald         hfp_codec_read_from_stream(&hfp_codec, payload_buffer, sco_payload_length);
43194381a69SMatthias Ringwald     }
43294381a69SMatthias Ringwald }
43394381a69SMatthias Ringwald 
434bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){
435bf958e42SMatthias 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);
436bf958e42SMatthias Ringwald }
437bf958e42SMatthias Ringwald 
438bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = {
439bf958e42SMatthias Ringwald         .init         = &sco_demo_msbc_init,
440bf958e42SMatthias Ringwald         .receive      = &sco_demo_msbc_receive,
441bf958e42SMatthias Ringwald         .fill_payload = &sco_demo_msbc_fill_payload,
44279cc780fSMatthias Ringwald         .close        = &sco_demo_msbc_close,
44379cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_16KHZ
444bf958e42SMatthias Ringwald };
445bf958e42SMatthias Ringwald 
44694381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
44794381a69SMatthias Ringwald 
44894381a69SMatthias Ringwald void sco_demo_init(void){
44994381a69SMatthias Ringwald 
45094381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS
45194381a69SMatthias Ringwald     printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n");
45294381a69SMatthias Ringwald     gap_secure_connections_enable(false);
45394381a69SMatthias Ringwald #endif
45494381a69SMatthias Ringwald 
45594381a69SMatthias Ringwald 	// status
45694381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
45794381a69SMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
45894381a69SMatthias Ringwald #endif
45994381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
46094381a69SMatthias Ringwald     if (btstack_audio_sink_get_instance()){
46194381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
46294381a69SMatthias Ringwald     } else {
46394381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, hexdump received data.\n");
46494381a69SMatthias Ringwald     }
46594381a69SMatthias Ringwald #endif
46694381a69SMatthias Ringwald 
46794381a69SMatthias Ringwald     // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode)
46894381a69SMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
4691762039cSMatthias Ringwald 
4701762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
4711762039cSMatthias Ringwald     // init mod
4721762039cSMatthias Ringwald     int hxcmod_initialized = hxcmod_init(&mod_context);
4731762039cSMatthias Ringwald     btstack_assert(hxcmod_initialized != 0);
4741762039cSMatthias Ringwald #endif
47594381a69SMatthias Ringwald }
47694381a69SMatthias Ringwald 
477bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){
47894381a69SMatthias Ringwald     switch (negotiated_codec){
47994381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
480bf958e42SMatthias Ringwald             codec_current = &codec_cvsd;
48194381a69SMatthias Ringwald             break;
48294381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
48394381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
484bf958e42SMatthias Ringwald             codec_current = &codec_msbc;
48594381a69SMatthias Ringwald             break;
48694381a69SMatthias Ringwald #endif
48794381a69SMatthias Ringwald         default:
48894381a69SMatthias Ringwald             btstack_assert(false);
48994381a69SMatthias Ringwald             break;
49094381a69SMatthias Ringwald     }
491bf958e42SMatthias Ringwald 
492bf958e42SMatthias Ringwald     codec_current->init();
4939ad691b0SMatthias Ringwald 
4949ad691b0SMatthias Ringwald     audio_initialize(codec_current->sample_rate);
4959ad691b0SMatthias Ringwald 
4969ad691b0SMatthias Ringwald     audio_prebuffer_bytes = SCO_PREBUFFER_MS * (codec_current->sample_rate/1000) * BYTES_PER_FRAME;
4979ad691b0SMatthias Ringwald 
4989ad691b0SMatthias Ringwald #ifdef SCO_WAV_FILENAME
4999ad691b0SMatthias Ringwald     num_samples_to_write = codec_current->sample_rate * SCO_WAV_DURATION_IN_SECONDS;
5009ad691b0SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, codec_current->sample_rate);
5019ad691b0SMatthias Ringwald #endif
5029ad691b0SMatthias Ringwald 
5039ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
5049ad691b0SMatthias Ringwald     sine_wave_steps_per_sample = SINE_WAVE_SAMPLE_RATE / codec_current->sample_rate;
5059ad691b0SMatthias Ringwald     sco_demo_audio_generator = &sco_demo_sine_wave_host_endian;
5069ad691b0SMatthias Ringwald #endif
5071762039cSMatthias Ringwald 
5081762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
5091762039cSMatthias Ringwald     // load mod
5101762039cSMatthias Ringwald     hxcmod_setcfg(&mod_context, codec_current->sample_rate, 16, 1, 1, 1);
5111762039cSMatthias Ringwald     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
5121762039cSMatthias Ringwald     sco_demo_audio_generator = &sco_demo_modplayer;
5131762039cSMatthias Ringwald #endif
51494381a69SMatthias Ringwald }
51594381a69SMatthias Ringwald 
51694381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
51794381a69SMatthias Ringwald     static uint32_t packets = 0;
51894381a69SMatthias Ringwald     static uint32_t crc_errors = 0;
51994381a69SMatthias Ringwald     static uint32_t data_received = 0;
52094381a69SMatthias Ringwald     static uint32_t byte_errors = 0;
52194381a69SMatthias Ringwald 
52294381a69SMatthias Ringwald     count_received++;
52394381a69SMatthias Ringwald 
52494381a69SMatthias Ringwald     data_received += size - 3;
52594381a69SMatthias Ringwald     packets++;
52694381a69SMatthias Ringwald     if (data_received > 100000){
52794381a69SMatthias 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);
52894381a69SMatthias Ringwald         crc_errors = 0;
52994381a69SMatthias Ringwald         byte_errors = 0;
53094381a69SMatthias Ringwald         data_received = 0;
53194381a69SMatthias Ringwald         packets = 0;
53294381a69SMatthias Ringwald     }
53394381a69SMatthias Ringwald 
534bf958e42SMatthias Ringwald     codec_current->receive(packet, size);
53594381a69SMatthias Ringwald }
53694381a69SMatthias Ringwald 
53794381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
53894381a69SMatthias Ringwald 
53994381a69SMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
54094381a69SMatthias Ringwald 
54194381a69SMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
54294381a69SMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
54394381a69SMatthias Ringwald 
54494381a69SMatthias Ringwald     hci_reserve_packet_buffer();
54594381a69SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
54694381a69SMatthias Ringwald 
547bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
548bf958e42SMatthias Ringwald     #define REFILL_SAMPLES 16
549bf958e42SMatthias Ringwald     // re-fill audio buffer
550bf958e42SMatthias Ringwald     uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2;
551bf958e42SMatthias Ringwald     while (samples_free > 0){
552bf958e42SMatthias Ringwald         int16_t samples_buffer[REFILL_SAMPLES];
553bf958e42SMatthias Ringwald         uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES);
554bf958e42SMatthias Ringwald         (*sco_demo_audio_generator)(samples_to_add, samples_buffer);
555bf958e42SMatthias Ringwald         btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2);
556bf958e42SMatthias Ringwald         samples_free -= samples_to_add;
55794381a69SMatthias Ringwald     }
558bf958e42SMatthias Ringwald #endif
559bf958e42SMatthias Ringwald 
560bf958e42SMatthias Ringwald     // resume if pre-buffer is filled
561bf958e42SMatthias Ringwald     if (audio_input_paused){
562bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){
563bf958e42SMatthias Ringwald             // resume sending
564bf958e42SMatthias Ringwald             audio_input_paused = 0;
565bf958e42SMatthias Ringwald         }
566bf958e42SMatthias Ringwald     }
567bf958e42SMatthias Ringwald 
568bf958e42SMatthias Ringwald     // fill payload by codec
569bf958e42SMatthias Ringwald     codec_current->fill_payload(&sco_packet[3], sco_payload_length);
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++;
58294381a69SMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) {
58394381a69SMatthias Ringwald         printf("SCO: sent %u, received %u\n", count_sent, count_received);
58494381a69SMatthias Ringwald     }
585f7c85330SMatthias Ringwald }
586f7c85330SMatthias Ringwald 
58794381a69SMatthias Ringwald void sco_demo_close(void){
58894381a69SMatthias Ringwald     printf("SCO demo close\n");
5891a919128SMatthias Ringwald 
59094381a69SMatthias Ringwald     printf("SCO demo statistics: ");
591bf958e42SMatthias Ringwald     codec_current->close();
592bf958e42SMatthias Ringwald     codec_current = NULL;
59394381a69SMatthias Ringwald 
59494381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
59594381a69SMatthias Ringwald     wav_writer_close();
5968b29cfc6SMatthias Ringwald #endif
5978b29cfc6SMatthias Ringwald 
59894381a69SMatthias Ringwald     audio_terminate();
599f7c85330SMatthias Ringwald }
600