xref: /btstack/example/sco_demo_util.c (revision 2936a8054edf5d70421f03747db4cacc4e2c71ad)
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"
53e1d1fb60SMatthias Ringwald #include "classic/btstack_sbc_bluedroid.h"
5435fd3fb9SMatthias Ringwald #include "classic/hfp.h"
55f0d95bdcSMatthias Ringwald #include "classic/hfp_codec.h"
56fcb08cdbSMilanka Ringwald 
57681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
58681cb550SMatthias Ringwald #include "btstack_lc3.h"
59681cb550SMatthias Ringwald #include "btstack_lc3_google.h"
60681cb550SMatthias Ringwald #endif
61681cb550SMatthias Ringwald 
62681cb550SMatthias Ringwald 
63f89e874bSMatthias Ringwald #ifdef _MSC_VER
64f89e874bSMatthias Ringwald // ignore deprecated warning for fopen
65f89e874bSMatthias Ringwald #pragma warning(disable : 4996)
66f89e874bSMatthias Ringwald #endif
67f89e874bSMatthias Ringwald 
6835fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
69fbc7c9f2SMilanka Ringwald #include "wav_util.h"
7035fd3fb9SMatthias Ringwald #endif
71fbc7c9f2SMilanka Ringwald 
72c4e666bcSMatthias Ringwald // test modes
73f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		 0
7494381a69SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 1
751762039cSMatthias Ringwald #define SCO_DEMO_MODE_MODPLAYER  2
76f7c85330SMatthias Ringwald 
77f7c85330SMatthias Ringwald // SCO demo configuration
78*2936a805SMatthias Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_MICROPHONE
79c4e666bcSMatthias Ringwald 
80c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console
81f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD           100
82f7c85330SMatthias Ringwald 
83f55ac442SMatthias Ringwald 
84d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
852c7ae6e1SMatthias Ringwald // length and name of wav file on disk
86c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
878b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
88859f2bc5SMatthias Ringwald #endif
89859f2bc5SMatthias Ringwald 
90c4e666bcSMatthias Ringwald // constants
91c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
92b150a479SMatthias Ringwald #define SAMPLE_RATE_8KHZ        8000
93b150a479SMatthias Ringwald #define SAMPLE_RATE_16KHZ       16000
94681cb550SMatthias Ringwald #define SAMPLE_RATE_32KHZ       32000
95379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
96f7c85330SMatthias Ringwald 
97681cb550SMatthias Ringwald // audio pre-buffer - also defines latency
98b150a479SMatthias Ringwald #define SCO_PREBUFFER_MS      50
99b150a479SMatthias Ringwald #define PREBUFFER_BYTES_8KHZ  (SCO_PREBUFFER_MS *  SAMPLE_RATE_8KHZ/1000 * BYTES_PER_FRAME)
100b150a479SMatthias Ringwald #define PREBUFFER_BYTES_16KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_16KHZ/1000 * BYTES_PER_FRAME)
101681cb550SMatthias Ringwald #define PREBUFFER_BYTES_32KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_32KHZ/1000 * BYTES_PER_FRAME)
102f7c85330SMatthias Ringwald 
103681cb550SMatthias Ringwald #if defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH)
104681cb550SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_32KHZ
105681cb550SMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 240
106681cb550SMatthias Ringwald #elif defined(ENABLE_HFP_WIDE_BAND_SPEECH)
1079582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_16KHZ
108f0d95bdcSMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 120
1099582ae64SMatthias Ringwald #else
1109582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_8KHZ
111f0d95bdcSMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 60
1129582ae64SMatthias Ringwald #endif
1139582ae64SMatthias Ringwald 
114bf958e42SMatthias Ringwald static uint16_t              audio_prebuffer_bytes;
115bf958e42SMatthias Ringwald 
1162b89dbfcSMatthias Ringwald // output
117d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
1189582ae64SMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
119379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
1202b89dbfcSMatthias Ringwald 
1212b89dbfcSMatthias Ringwald // input
1222b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
123379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
1243cf06407SMatthias Ringwald #else
1253cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR
1263cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data);
1276fb1424bSMatthias Ringwald #endif
128681cb550SMatthias Ringwald 
129379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
1309582ae64SMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
131379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
132f7c85330SMatthias Ringwald 
1331762039cSMatthias Ringwald // mod player
1341762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
1351762039cSMatthias Ringwald #include "hxcmod.h"
1361762039cSMatthias Ringwald #include "mods/mod.h"
1371762039cSMatthias Ringwald static modcontext mod_context;
1381762039cSMatthias Ringwald #endif
1391762039cSMatthias Ringwald 
140fcb08cdbSMilanka Ringwald static int count_sent = 0;
141fcb08cdbSMilanka Ringwald static int count_received = 0;
142c4e666bcSMatthias Ringwald 
143681cb550SMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
144681cb550SMatthias Ringwald 
1451bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
14637abe280SMatthias Ringwald static const btstack_sbc_decoder_t *   sbc_decoder_instance;
14737abe280SMatthias Ringwald static btstack_sbc_decoder_bluedroid_t sbc_decoder_context;
148e1d1fb60SMatthias Ringwald static const btstack_sbc_encoder_t *   sbc_encoder_instance;
149e1d1fb60SMatthias Ringwald static btstack_sbc_encoder_bluedroid_t sbc_encoder_context;
1501bbecc2bSMatthias Ringwald #endif
1511bbecc2bSMatthias Ringwald 
152681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
153681cb550SMatthias Ringwald static const btstack_lc3_decoder_t * lc3_decoder;
154681cb550SMatthias Ringwald static btstack_lc3_decoder_google_t lc3_decoder_context;
155aeb2ea11SMatthias Ringwald static btstack_lc3_encoder_google_t lc3_encoder_context;
156681cb550SMatthias Ringwald static hfp_h2_sync_t    hfp_h2_sync;
157681cb550SMatthias Ringwald #endif
158379c5f5fSMatthias Ringwald 
1592b89dbfcSMatthias Ringwald int num_samples_to_write;
1602b89dbfcSMatthias Ringwald int num_audio_frames;
1612b89dbfcSMatthias Ringwald 
162bf958e42SMatthias Ringwald // generic codec support
163bf958e42SMatthias Ringwald typedef struct {
164bf958e42SMatthias Ringwald     void (*init)(void);
165bf958e42SMatthias Ringwald     void(*receive)(const uint8_t * packet, uint16_t size);
166bf958e42SMatthias Ringwald     void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length);
167bf958e42SMatthias Ringwald     void (*close)(void);
16879cc780fSMatthias Ringwald     //
16979cc780fSMatthias Ringwald     uint16_t sample_rate;
170bf958e42SMatthias Ringwald } codec_support_t;
17179cc780fSMatthias Ringwald 
17279cc780fSMatthias Ringwald // current configuration
173bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL;
174bf958e42SMatthias Ringwald 
175f0d95bdcSMatthias Ringwald // hfp_codec
1767555fa8bSMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH) || defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH)
177f0d95bdcSMatthias Ringwald static hfp_codec_t hfp_codec;
1787555fa8bSMatthias Ringwald #endif
179d6a06398SMatthias Ringwald 
1809ad691b0SMatthias Ringwald // Sine Wave
1819ad691b0SMatthias Ringwald 
1829ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
1839ad691b0SMatthias Ringwald static uint16_t sine_wave_phase;
1849ad691b0SMatthias Ringwald static uint16_t sine_wave_steps_per_sample;
185681cb550SMatthias Ringwald #define SINE_WAVE_SAMPLE_RATE SAMPLE_RATE_32KHZ
18694381a69SMatthias Ringwald 
187681cb550SMatthias Ringwald // input signal: pre-computed int16 sine wave, 32000 Hz at 266 Hz
188681cb550SMatthias Ringwald static const int16_t sine_int16[] = {
189681cb550SMatthias Ringwald      0,   1715,   3425,   5126,   6813,   8481,  10126,  11743,  13328,  14876,
190681cb550SMatthias Ringwald  16383,  17846,  19260,  20621,  21925,  23170,  24351,  25465,  26509,  27481,
191681cb550SMatthias Ringwald  28377,  29196,  29934,  30591,  31163,  31650,  32051,  32364,  32587,  32722,
192681cb550SMatthias Ringwald  32767,  32722,  32587,  32364,  32051,  31650,  31163,  30591,  29934,  29196,
193681cb550SMatthias Ringwald  28377,  27481,  26509,  25465,  24351,  23170,  21925,  20621,  19260,  17846,
194681cb550SMatthias Ringwald  16383,  14876,  13328,  11743,  10126,   8481,   6813,   5126,   3425,   1715,
195681cb550SMatthias Ringwald      0,  -1715,  -3425,  -5126,  -6813,  -8481, -10126, -11743, -13328, -14876,
196681cb550SMatthias Ringwald -16384, -17846, -19260, -20621, -21925, -23170, -24351, -25465, -26509, -27481,
197681cb550SMatthias Ringwald -28377, -29196, -29934, -30591, -31163, -31650, -32051, -32364, -32587, -32722,
198681cb550SMatthias Ringwald -32767, -32722, -32587, -32364, -32051, -31650, -31163, -30591, -29934, -29196,
199681cb550SMatthias Ringwald -28377, -27481, -26509, -25465, -24351, -23170, -21925, -20621, -19260, -17846,
200681cb550SMatthias Ringwald -16384, -14876, -13328, -11743, -10126,  -8481,  -6813,  -5126,  -3425,  -1715,
20135fd3fb9SMatthias Ringwald };
20235fd3fb9SMatthias Ringwald 
sco_demo_sine_wave_host_endian(uint16_t num_samples,int16_t * data)2039ad691b0SMatthias Ringwald static void sco_demo_sine_wave_host_endian(uint16_t num_samples, int16_t * data){
204249d94cfSMatthias Ringwald     unsigned int i;
20559c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
206681cb550SMatthias Ringwald         data[i] = sine_int16[sine_wave_phase];
2079ad691b0SMatthias Ringwald         sine_wave_phase += sine_wave_steps_per_sample;
208681cb550SMatthias Ringwald         if (sine_wave_phase >= (sizeof(sine_int16) / sizeof(int16_t))){
2099ad691b0SMatthias Ringwald             sine_wave_phase = 0;
21035fd3fb9SMatthias Ringwald         }
21135fd3fb9SMatthias Ringwald     }
21235fd3fb9SMatthias Ringwald }
2131bbecc2bSMatthias Ringwald #endif
214dbb41bfeSMilanka Ringwald 
2151762039cSMatthias Ringwald // Mod Player
2161762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
2171762039cSMatthias Ringwald #define NUM_SAMPLES_GENERATOR_BUFFER 30
sco_demo_modplayer(uint16_t num_samples,int16_t * data)2181762039cSMatthias Ringwald static void sco_demo_modplayer(uint16_t num_samples, int16_t * data){
2191762039cSMatthias Ringwald     // mix down stereo
2201762039cSMatthias Ringwald     signed short samples[NUM_SAMPLES_GENERATOR_BUFFER * 2];
2211762039cSMatthias Ringwald     while (num_samples > 0){
2221762039cSMatthias Ringwald         uint16_t next_samples = btstack_min(num_samples, NUM_SAMPLES_GENERATOR_BUFFER);
2231762039cSMatthias Ringwald     	hxcmod_fillbuffer(&mod_context, (unsigned short *) samples, next_samples, NULL);
2241762039cSMatthias Ringwald         num_samples -= next_samples;
2251762039cSMatthias Ringwald         uint16_t i;
2261762039cSMatthias Ringwald         for (i=0;i<next_samples;i++){
2271762039cSMatthias Ringwald             int32_t left  = samples[2*i + 0];
2281762039cSMatthias Ringwald             int32_t right = samples[2*i + 1];
2291762039cSMatthias Ringwald             data[i] = (int16_t)((left + right) / 2);
2301762039cSMatthias Ringwald         }
2311762039cSMatthias Ringwald     }
2321762039cSMatthias Ringwald }
2331762039cSMatthias Ringwald #endif
2341762039cSMatthias Ringwald 
23594381a69SMatthias Ringwald // Audio Playback / Recording
236d861f4bfSMatthias Ringwald 
audio_playback_callback(int16_t * buffer,uint16_t num_samples)23794381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){
2382b89dbfcSMatthias Ringwald 
239c4e666bcSMatthias Ringwald     // fill with silence while paused
240379c5f5fSMatthias Ringwald     if (audio_output_paused){
241bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){
242f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
243379c5f5fSMatthias Ringwald            return;
244dbb41bfeSMilanka Ringwald         } else {
245c4e666bcSMatthias Ringwald             // resume playback
246379c5f5fSMatthias Ringwald             audio_output_paused = 0;
247dbb41bfeSMilanka Ringwald         }
248c4e666bcSMatthias Ringwald     }
249c4e666bcSMatthias Ringwald 
250c4e666bcSMatthias Ringwald     // get data from ringbuffer
251c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
252f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
253f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
254f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
255c4e666bcSMatthias Ringwald 
256c4e666bcSMatthias Ringwald     // fill with 0 if not enough
257f55ac442SMatthias Ringwald     if (num_samples){
258f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
259379c5f5fSMatthias Ringwald         audio_output_paused = 1;
260c4e666bcSMatthias Ringwald     }
261379c5f5fSMatthias Ringwald }
2628b29cfc6SMatthias Ringwald 
263379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
audio_recording_callback(const int16_t * buffer,uint16_t num_samples)26494381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){
265379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
266c4e666bcSMatthias Ringwald }
267379c5f5fSMatthias Ringwald #endif
268c4e666bcSMatthias Ringwald 
269c4e666bcSMatthias Ringwald // return 1 if ok
audio_initialize(int sample_rate)270379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
271c4e666bcSMatthias Ringwald 
272d365bb51SMatthias Ringwald     // -- output -- //
273d365bb51SMatthias Ringwald 
274379c5f5fSMatthias Ringwald     // init buffers
275379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
276379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2772b89dbfcSMatthias Ringwald 
278d365bb51SMatthias Ringwald     // config and setup audio playback
279d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
280e0c8f71bSMatthias Ringwald     if (audio_sink != NULL){
28194381a69SMatthias Ringwald         audio_sink->init(1, sample_rate, &audio_playback_callback);
282d365bb51SMatthias Ringwald         audio_sink->start_stream();
283379c5f5fSMatthias Ringwald 
284379c5f5fSMatthias Ringwald         audio_output_paused  = 1;
285e0c8f71bSMatthias Ringwald     }
286d365bb51SMatthias Ringwald 
287d365bb51SMatthias Ringwald     // -- input -- //
288d365bb51SMatthias Ringwald 
289d365bb51SMatthias Ringwald     // init buffers
290d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
291d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
2926fb1424bSMatthias Ringwald     audio_input_paused  = 1;
293d365bb51SMatthias Ringwald 
2946fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT
295d365bb51SMatthias Ringwald     // config and setup audio recording
296d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
297e0c8f71bSMatthias Ringwald     if (audio_source != NULL){
29894381a69SMatthias Ringwald         audio_source->init(1, sample_rate, &audio_recording_callback);
299d365bb51SMatthias Ringwald         audio_source->start_stream();
300e0c8f71bSMatthias Ringwald     }
3012b89dbfcSMatthias Ringwald #endif
3022b89dbfcSMatthias Ringwald 
303c4e666bcSMatthias Ringwald     return 1;
304c4e666bcSMatthias Ringwald }
3052b89dbfcSMatthias Ringwald 
audio_terminate(void)306379c5f5fSMatthias Ringwald static void audio_terminate(void){
307d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
308d365bb51SMatthias Ringwald     if (!audio_sink) return;
309d365bb51SMatthias Ringwald     audio_sink->close();
310d365bb51SMatthias Ringwald 
311d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
312d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
313d365bb51SMatthias Ringwald     if (!audio_source) return;
314d365bb51SMatthias Ringwald     audio_source->close();
315d365bb51SMatthias Ringwald #endif
3162b89dbfcSMatthias Ringwald }
317c4e666bcSMatthias Ringwald 
318d861f4bfSMatthias Ringwald 
31994381a69SMatthias Ringwald // CVSD - 8 kHz
320fcb08cdbSMilanka Ringwald 
sco_demo_cvsd_init(void)321bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){
322c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
323fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
324fbc7c9f2SMilanka Ringwald }
325fbc7c9f2SMilanka Ringwald 
sco_demo_cvsd_receive(const uint8_t * packet,uint16_t size)326bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){
3272c7ae6e1SMatthias Ringwald 
3285303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
3291f8694ccSMatthias Ringwald 
3301f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
331bf958e42SMatthias Ringwald         printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n");
3321f8694ccSMatthias Ringwald         return;
3331f8694ccSMatthias Ringwald     }
3342c7ae6e1SMatthias Ringwald 
335c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
336379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
3375303ddeeSMatthias Ringwald 
3385303ddeeSMatthias Ringwald     // convert into host endian
3395303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
3405303ddeeSMatthias Ringwald     int i;
3415303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
3425303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
3435303ddeeSMatthias Ringwald     }
3445303ddeeSMatthias Ringwald 
3455f4f94c7SMatthias Ringwald     // treat packet as bad frame if controller does not report 'all good'
3465f4f94c7SMatthias Ringwald     bool bad_frame = (packet[1] & 0x30) != 0;
3475f4f94c7SMatthias Ringwald 
3485f4f94c7SMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out);
3495303ddeeSMatthias Ringwald 
3502c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3512c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3522c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3532c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3542c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3552c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3562c7ae6e1SMatthias Ringwald         wav_writer_close();
3572c7ae6e1SMatthias Ringwald     }
3582c7ae6e1SMatthias Ringwald #endif
3592c7ae6e1SMatthias Ringwald 
360379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
361fcb08cdbSMilanka Ringwald }
362fcb08cdbSMilanka Ringwald 
sco_demo_cvsd_fill_payload(uint8_t * payload_buffer,uint16_t sco_payload_length)363bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
3646fb1424bSMatthias Ringwald     uint16_t bytes_to_copy = sco_payload_length;
3656fb1424bSMatthias Ringwald 
3662b89dbfcSMatthias Ringwald     // get data from ringbuffer
3672b89dbfcSMatthias Ringwald     uint16_t pos = 0;
368379c5f5fSMatthias Ringwald     if (!audio_input_paused){
3696fb1424bSMatthias Ringwald         uint16_t samples_to_copy = sco_payload_length / 2;
3702b89dbfcSMatthias Ringwald         uint32_t bytes_read = 0;
3716fb1424bSMatthias Ringwald         btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read);
3728fd6902dSMatthias Ringwald         // flip 16 on big endian systems
3738fd6902dSMatthias Ringwald         // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
3748fd6902dSMatthias Ringwald         if (btstack_is_big_endian()){
3756fb1424bSMatthias Ringwald             uint16_t i;
3766fb1424bSMatthias Ringwald             for (i=0;i<samples_to_copy/2;i+=2){
3776fb1424bSMatthias Ringwald                 uint8_t tmp           = payload_buffer[i*2];
3786fb1424bSMatthias Ringwald                 payload_buffer[i*2]   = payload_buffer[i*2+1];
3796fb1424bSMatthias Ringwald                 payload_buffer[i*2+1] = tmp;
3808fd6902dSMatthias Ringwald             }
3818fd6902dSMatthias Ringwald         }
3822b89dbfcSMatthias Ringwald         bytes_to_copy -= bytes_read;
3832b89dbfcSMatthias Ringwald         pos           += bytes_read;
3842b89dbfcSMatthias Ringwald     }
3852b89dbfcSMatthias Ringwald 
3862b89dbfcSMatthias Ringwald     // fill with 0 if not enough
3872b89dbfcSMatthias Ringwald     if (bytes_to_copy){
3886fb1424bSMatthias Ringwald         memset(payload_buffer + pos, 0, bytes_to_copy);
389379c5f5fSMatthias Ringwald         audio_input_paused = 1;
3902b89dbfcSMatthias Ringwald     }
3912b89dbfcSMatthias Ringwald }
39294381a69SMatthias Ringwald 
sco_demo_cvsd_close(void)393bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){
394bf958e42SMatthias 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);
395bf958e42SMatthias Ringwald }
396bf958e42SMatthias Ringwald 
397bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = {
398bf958e42SMatthias Ringwald         .init         = &sco_demo_cvsd_init,
399bf958e42SMatthias Ringwald         .receive      = &sco_demo_cvsd_receive,
400bf958e42SMatthias Ringwald         .fill_payload = &sco_demo_cvsd_fill_payload,
40179cc780fSMatthias Ringwald         .close        = &sco_demo_cvsd_close,
40279cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_8KHZ
403bf958e42SMatthias Ringwald };
404bf958e42SMatthias Ringwald 
405681cb550SMatthias Ringwald // encode using hfp_codec
406681cb550SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH) || defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH)
sco_demo_codec_fill_payload(uint8_t * payload_buffer,uint16_t sco_payload_length)407d4872f4eSMatthias Ringwald static void sco_demo_codec_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
408681cb550SMatthias Ringwald     if (!audio_input_paused){
409681cb550SMatthias Ringwald         int num_samples = hfp_codec_num_audio_samples_per_frame(&hfp_codec);
410681cb550SMatthias Ringwald         btstack_assert(num_samples <= SAMPLES_PER_FRAME_MAX);
411681cb550SMatthias Ringwald         uint16_t samples_available = btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) / BYTES_PER_FRAME;
412681cb550SMatthias Ringwald         if (hfp_codec_can_encode_audio_frame_now(&hfp_codec) && samples_available >= num_samples){
413681cb550SMatthias Ringwald             int16_t sample_buffer[SAMPLES_PER_FRAME_MAX];
414681cb550SMatthias Ringwald             uint32_t bytes_read;
415681cb550SMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
416681cb550SMatthias Ringwald             hfp_codec_encode_audio_frame(&hfp_codec, sample_buffer);
417681cb550SMatthias Ringwald             num_audio_frames++;
418681cb550SMatthias Ringwald         }
419681cb550SMatthias Ringwald     }
420681cb550SMatthias Ringwald     // get data from encoder, fill with 0 if not enough
421681cb550SMatthias Ringwald     if (audio_input_paused || hfp_codec_num_bytes_available(&hfp_codec) < sco_payload_length){
422681cb550SMatthias Ringwald         // just send '0's
423681cb550SMatthias Ringwald         memset(payload_buffer, 0, sco_payload_length);
424681cb550SMatthias Ringwald         audio_input_paused = 1;
425681cb550SMatthias Ringwald     } else {
426681cb550SMatthias Ringwald         hfp_codec_read_from_stream(&hfp_codec, payload_buffer, sco_payload_length);
427681cb550SMatthias Ringwald     }
428681cb550SMatthias Ringwald }
429681cb550SMatthias Ringwald #endif
430681cb550SMatthias Ringwald 
43194381a69SMatthias Ringwald // mSBC - 16 kHz
43294381a69SMatthias Ringwald 
43394381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
43494381a69SMatthias Ringwald 
handle_pcm_data(int16_t * data,int num_samples,int num_channels,int sample_rate,void * context)43594381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
43694381a69SMatthias Ringwald     UNUSED(context);
43794381a69SMatthias Ringwald     UNUSED(sample_rate);
43894381a69SMatthias Ringwald     UNUSED(data);
43994381a69SMatthias Ringwald     UNUSED(num_samples);
44094381a69SMatthias Ringwald     UNUSED(num_channels);
44194381a69SMatthias Ringwald 
44294381a69SMatthias Ringwald     // samples in callback in host endianess, ready for playback
44394381a69SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
44494381a69SMatthias Ringwald 
44594381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
44694381a69SMatthias Ringwald     if (!num_samples_to_write) return;
44794381a69SMatthias Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
44894381a69SMatthias Ringwald     num_samples_to_write -= num_samples;
44994381a69SMatthias Ringwald     wav_writer_write_int16(num_samples, data);
45094381a69SMatthias Ringwald     if (num_samples_to_write == 0){
45194381a69SMatthias Ringwald         wav_writer_close();
452f7c85330SMatthias Ringwald     }
45394381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
4541a919128SMatthias Ringwald }
45594381a69SMatthias Ringwald 
sco_demo_msbc_init(void)456bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){
45794381a69SMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
45837abe280SMatthias Ringwald     sbc_decoder_instance = btstack_sbc_decoder_bluedroid_init_instance(&sbc_decoder_context);
45937abe280SMatthias Ringwald     sbc_decoder_instance->configure(&sbc_decoder_context, SBC_MODE_mSBC, &handle_pcm_data, NULL);
460e1d1fb60SMatthias Ringwald     sbc_encoder_instance = btstack_sbc_encoder_bluedroid_init_instance(&sbc_encoder_context);
461e1d1fb60SMatthias Ringwald     hfp_codec_init_msbc_with_codec(&hfp_codec, sbc_encoder_instance, &sbc_encoder_context);
46294381a69SMatthias Ringwald }
46394381a69SMatthias Ringwald 
sco_demo_msbc_receive(const uint8_t * packet,uint16_t size)464bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){
46537abe280SMatthias Ringwald     sbc_decoder_instance->decode_signed_16(&sbc_decoder_context, (packet[1] >> 4) & 3, packet + 3, size - 3);
46694381a69SMatthias Ringwald }
46794381a69SMatthias Ringwald 
sco_demo_msbc_close(void)468bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){
46937abe280SMatthias Ringwald     printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.\n", sbc_decoder_context.good_frames_nr, sbc_decoder_context.zero_frames_nr, sbc_decoder_context.bad_frames_nr);
470bf958e42SMatthias Ringwald }
471bf958e42SMatthias Ringwald 
472bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = {
473bf958e42SMatthias Ringwald         .init         = &sco_demo_msbc_init,
474bf958e42SMatthias Ringwald         .receive      = &sco_demo_msbc_receive,
475681cb550SMatthias Ringwald         .fill_payload = &sco_demo_codec_fill_payload,
47679cc780fSMatthias Ringwald         .close        = &sco_demo_msbc_close,
47779cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_16KHZ
478bf958e42SMatthias Ringwald };
479bf958e42SMatthias Ringwald 
48094381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
48194381a69SMatthias Ringwald 
482681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
483681cb550SMatthias Ringwald 
484681cb550SMatthias Ringwald #define LC3_SWB_SAMPLES_PER_FRAME 240
485681cb550SMatthias Ringwald #define LC3_SWB_OCTETS_PER_FRAME   58
486681cb550SMatthias Ringwald 
sco_demo_lc3swb_frame_callback(bool bad_frame,const uint8_t * frame_data,uint16_t frame_len)487681cb550SMatthias Ringwald static bool sco_demo_lc3swb_frame_callback(bool bad_frame, const uint8_t * frame_data, uint16_t frame_len){
488681cb550SMatthias Ringwald 
489681cb550SMatthias Ringwald     // skip H2 header for good frames
490681cb550SMatthias Ringwald     if (bad_frame == false){
491681cb550SMatthias Ringwald         btstack_assert(frame_data != NULL);
492681cb550SMatthias Ringwald         frame_data += 2;
493681cb550SMatthias Ringwald     }
494681cb550SMatthias Ringwald 
495681cb550SMatthias Ringwald     uint8_t tmp_BEC_detect = 0;
496681cb550SMatthias Ringwald     uint8_t BFI = bad_frame ? 1 : 0;
497681cb550SMatthias Ringwald     int16_t samples[LC3_SWB_SAMPLES_PER_FRAME];
498681cb550SMatthias Ringwald     (void) lc3_decoder->decode_signed_16(&lc3_decoder_context, frame_data, BFI,
499681cb550SMatthias Ringwald                                          samples, 1, &tmp_BEC_detect);
500681cb550SMatthias Ringwald 
501681cb550SMatthias Ringwald     // samples in callback in host endianess, ready for playback
502681cb550SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)samples, LC3_SWB_SAMPLES_PER_FRAME*2);
503681cb550SMatthias Ringwald 
504681cb550SMatthias Ringwald #ifdef SCO_WAV_FILENAME
505681cb550SMatthias Ringwald     if (num_samples_to_write > 0){
506681cb550SMatthias Ringwald         uint16_t num_samples = btstack_min(LC3_SWB_SAMPLES_PER_FRAME, num_samples_to_write);
507681cb550SMatthias Ringwald         num_samples_to_write -= num_samples;
508681cb550SMatthias Ringwald         wav_writer_write_int16(num_samples, samples);
509681cb550SMatthias Ringwald         if (num_samples_to_write == 0){
510681cb550SMatthias Ringwald             wav_writer_close();
511681cb550SMatthias Ringwald         }
512681cb550SMatthias Ringwald     }
513681cb550SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
514681cb550SMatthias Ringwald 
515681cb550SMatthias Ringwald     // frame is good, if it isn't a bad frame and we didn't detect other errors
516681cb550SMatthias Ringwald     return (bad_frame == false) && (tmp_BEC_detect == 0);
517681cb550SMatthias Ringwald }
518681cb550SMatthias Ringwald 
sco_demo_lc3swb_init(void)519681cb550SMatthias Ringwald static void sco_demo_lc3swb_init(void){
520681cb550SMatthias Ringwald 
521681cb550SMatthias Ringwald     printf("SCO Demo: Init LC3-SWB\n");
522681cb550SMatthias Ringwald 
5233b7e9cecSMatthias Ringwald     hfp_codec.lc3_encoder_context = &lc3_encoder_context;
524e1d1fb60SMatthias Ringwald     const btstack_lc3_encoder_t * lc3_encoder = btstack_lc3_encoder_google_init_instance( &lc3_encoder_context);
525aeb2ea11SMatthias Ringwald     hfp_codec_init_lc3_swb(&hfp_codec, lc3_encoder, &lc3_encoder_context);
526681cb550SMatthias Ringwald 
527681cb550SMatthias Ringwald     // init lc3 decoder
528681cb550SMatthias Ringwald     lc3_decoder = btstack_lc3_decoder_google_init_instance(&lc3_decoder_context);
529681cb550SMatthias Ringwald     lc3_decoder->configure(&lc3_decoder_context, SAMPLE_RATE_32KHZ, BTSTACK_LC3_FRAME_DURATION_7500US, LC3_SWB_OCTETS_PER_FRAME);
530681cb550SMatthias Ringwald 
531681cb550SMatthias Ringwald     // init HPF H2 framing
532681cb550SMatthias Ringwald     hfp_h2_sync_init(&hfp_h2_sync, &sco_demo_lc3swb_frame_callback);
533681cb550SMatthias Ringwald }
534681cb550SMatthias Ringwald 
sco_demo_lc3swb_receive(const uint8_t * packet,uint16_t size)535681cb550SMatthias Ringwald static void sco_demo_lc3swb_receive(const uint8_t * packet, uint16_t size){
536681cb550SMatthias Ringwald     uint8_t packet_status = (packet[1] >> 4) & 3;
537681cb550SMatthias Ringwald     bool bad_frame = packet_status != 0;
538681cb550SMatthias Ringwald     hfp_h2_sync_process(&hfp_h2_sync, bad_frame, &packet[3], size-3);
539681cb550SMatthias Ringwald }
540681cb550SMatthias Ringwald 
sco_demo_lc3swb_close(void)541681cb550SMatthias Ringwald static void sco_demo_lc3swb_close(void){
542681cb550SMatthias Ringwald     // TODO: report
543681cb550SMatthias Ringwald }
544681cb550SMatthias Ringwald 
545681cb550SMatthias Ringwald static const codec_support_t codec_lc3swb = {
546681cb550SMatthias Ringwald         .init         = &sco_demo_lc3swb_init,
547681cb550SMatthias Ringwald         .receive      = &sco_demo_lc3swb_receive,
548681cb550SMatthias Ringwald         .fill_payload = &sco_demo_codec_fill_payload,
549681cb550SMatthias Ringwald         .close        = &sco_demo_lc3swb_close,
550681cb550SMatthias Ringwald         .sample_rate = SAMPLE_RATE_32KHZ
551681cb550SMatthias Ringwald };
552681cb550SMatthias Ringwald #endif
553681cb550SMatthias Ringwald 
sco_demo_init(void)55494381a69SMatthias Ringwald void sco_demo_init(void){
55594381a69SMatthias Ringwald 
55694381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS
55794381a69SMatthias Ringwald     printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n");
55894381a69SMatthias Ringwald     gap_secure_connections_enable(false);
55994381a69SMatthias Ringwald #endif
56094381a69SMatthias Ringwald 
561681cb550SMatthias Ringwald     // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode)
562681cb550SMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
563681cb550SMatthias Ringwald 
56494381a69SMatthias Ringwald     // status
56594381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
56694381a69SMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
56794381a69SMatthias Ringwald #endif
56894381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
56994381a69SMatthias Ringwald     printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
57094381a69SMatthias Ringwald #endif
5711762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
572681cb550SMatthias Ringwald     printf("SCO Demo: Sending modplayer wave, audio output via btstack_audio.\n");
5731762039cSMatthias Ringwald     // init mod
5741762039cSMatthias Ringwald     int hxcmod_initialized = hxcmod_init(&mod_context);
5751762039cSMatthias Ringwald     btstack_assert(hxcmod_initialized != 0);
5761762039cSMatthias Ringwald #endif
57794381a69SMatthias Ringwald }
57894381a69SMatthias Ringwald 
sco_demo_set_codec(uint8_t negotiated_codec)579bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){
58094381a69SMatthias Ringwald     switch (negotiated_codec){
58194381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
582bf958e42SMatthias Ringwald             codec_current = &codec_cvsd;
58394381a69SMatthias Ringwald             break;
58494381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
58594381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
586bf958e42SMatthias Ringwald             codec_current = &codec_msbc;
58794381a69SMatthias Ringwald             break;
58894381a69SMatthias Ringwald #endif
589681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
590681cb550SMatthias Ringwald         case HFP_CODEC_LC3_SWB:
591681cb550SMatthias Ringwald             codec_current = &codec_lc3swb;
592681cb550SMatthias Ringwald             break;
593681cb550SMatthias Ringwald #endif
59494381a69SMatthias Ringwald         default:
59594381a69SMatthias Ringwald             btstack_assert(false);
59694381a69SMatthias Ringwald             break;
59794381a69SMatthias Ringwald     }
598bf958e42SMatthias Ringwald 
599bf958e42SMatthias Ringwald     codec_current->init();
6009ad691b0SMatthias Ringwald 
6019ad691b0SMatthias Ringwald     audio_initialize(codec_current->sample_rate);
6029ad691b0SMatthias Ringwald 
6039ad691b0SMatthias Ringwald     audio_prebuffer_bytes = SCO_PREBUFFER_MS * (codec_current->sample_rate/1000) * BYTES_PER_FRAME;
6049ad691b0SMatthias Ringwald 
6059ad691b0SMatthias Ringwald #ifdef SCO_WAV_FILENAME
6069ad691b0SMatthias Ringwald     num_samples_to_write = codec_current->sample_rate * SCO_WAV_DURATION_IN_SECONDS;
6079ad691b0SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, codec_current->sample_rate);
6089ad691b0SMatthias Ringwald #endif
6099ad691b0SMatthias Ringwald 
6109ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
6119ad691b0SMatthias Ringwald     sine_wave_steps_per_sample = SINE_WAVE_SAMPLE_RATE / codec_current->sample_rate;
6129ad691b0SMatthias Ringwald     sco_demo_audio_generator = &sco_demo_sine_wave_host_endian;
6139ad691b0SMatthias Ringwald #endif
6141762039cSMatthias Ringwald 
6151762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
6161762039cSMatthias Ringwald     // load mod
6171762039cSMatthias Ringwald     hxcmod_setcfg(&mod_context, codec_current->sample_rate, 16, 1, 1, 1);
6181762039cSMatthias Ringwald     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
6191762039cSMatthias Ringwald     sco_demo_audio_generator = &sco_demo_modplayer;
6201762039cSMatthias Ringwald #endif
62194381a69SMatthias Ringwald }
62294381a69SMatthias Ringwald 
sco_demo_receive(uint8_t * packet,uint16_t size)62394381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
62494381a69SMatthias Ringwald     static uint32_t packets = 0;
62594381a69SMatthias Ringwald     static uint32_t crc_errors = 0;
62694381a69SMatthias Ringwald     static uint32_t data_received = 0;
62794381a69SMatthias Ringwald     static uint32_t byte_errors = 0;
62894381a69SMatthias Ringwald 
62994381a69SMatthias Ringwald     count_received++;
63094381a69SMatthias Ringwald 
63194381a69SMatthias Ringwald     data_received += size - 3;
63294381a69SMatthias Ringwald     packets++;
63394381a69SMatthias Ringwald     if (data_received > 100000){
63494381a69SMatthias 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);
63594381a69SMatthias Ringwald         crc_errors = 0;
63694381a69SMatthias Ringwald         byte_errors = 0;
63794381a69SMatthias Ringwald         data_received = 0;
63894381a69SMatthias Ringwald         packets = 0;
63994381a69SMatthias Ringwald     }
64094381a69SMatthias Ringwald 
641bf958e42SMatthias Ringwald     codec_current->receive(packet, size);
64294381a69SMatthias Ringwald }
64394381a69SMatthias Ringwald 
sco_demo_send(hci_con_handle_t sco_handle)64494381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
64594381a69SMatthias Ringwald 
64694381a69SMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
64794381a69SMatthias Ringwald 
648b8543c7aSMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length_for_connection(sco_handle);
64994381a69SMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
65094381a69SMatthias Ringwald 
65194381a69SMatthias Ringwald     hci_reserve_packet_buffer();
65294381a69SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
65394381a69SMatthias Ringwald 
654bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
655bf958e42SMatthias Ringwald     #define REFILL_SAMPLES 16
656bf958e42SMatthias Ringwald     // re-fill audio buffer
657bf958e42SMatthias Ringwald     uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2;
658bf958e42SMatthias Ringwald     while (samples_free > 0){
659bf958e42SMatthias Ringwald         int16_t samples_buffer[REFILL_SAMPLES];
660bf958e42SMatthias Ringwald         uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES);
661bf958e42SMatthias Ringwald         (*sco_demo_audio_generator)(samples_to_add, samples_buffer);
662bf958e42SMatthias Ringwald         btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2);
663bf958e42SMatthias Ringwald         samples_free -= samples_to_add;
66494381a69SMatthias Ringwald     }
665bf958e42SMatthias Ringwald #endif
666bf958e42SMatthias Ringwald 
667bf958e42SMatthias Ringwald     // resume if pre-buffer is filled
668bf958e42SMatthias Ringwald     if (audio_input_paused){
669bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){
670bf958e42SMatthias Ringwald             // resume sending
671bf958e42SMatthias Ringwald             audio_input_paused = 0;
672bf958e42SMatthias Ringwald         }
673bf958e42SMatthias Ringwald     }
674bf958e42SMatthias Ringwald 
675bf958e42SMatthias Ringwald     // fill payload by codec
676bf958e42SMatthias Ringwald     codec_current->fill_payload(&sco_packet[3], sco_payload_length);
6772b89dbfcSMatthias Ringwald 
678c4e666bcSMatthias Ringwald     // set handle + flags
679c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
680c4e666bcSMatthias Ringwald     // set len
681c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
682c4e666bcSMatthias Ringwald     // finally send packet
683f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
684f7c85330SMatthias Ringwald 
685f7c85330SMatthias Ringwald     // request another send event
686f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
687f7c85330SMatthias Ringwald 
6884a96141eSMatthias Ringwald     count_sent++;
68994381a69SMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) {
69094381a69SMatthias Ringwald         printf("SCO: sent %u, received %u\n", count_sent, count_received);
69194381a69SMatthias Ringwald     }
692f7c85330SMatthias Ringwald }
693f7c85330SMatthias Ringwald 
sco_demo_close(void)69494381a69SMatthias Ringwald void sco_demo_close(void){
69594381a69SMatthias Ringwald     printf("SCO demo close\n");
6961a919128SMatthias Ringwald 
69794381a69SMatthias Ringwald     printf("SCO demo statistics: ");
698bf958e42SMatthias Ringwald     codec_current->close();
699bf958e42SMatthias Ringwald     codec_current = NULL;
70094381a69SMatthias Ringwald 
70194381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
70294381a69SMatthias Ringwald     wav_writer_close();
7038b29cfc6SMatthias Ringwald #endif
7048b29cfc6SMatthias Ringwald 
70594381a69SMatthias Ringwald     audio_terminate();
706f7c85330SMatthias Ringwald }
707