xref: /btstack/example/sco_demo_util.c (revision 681cb550580033829435e1ce57ed2e591b2ce519)
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"
54f0d95bdcSMatthias Ringwald #include "classic/hfp_codec.h"
55fcb08cdbSMilanka Ringwald 
56*681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
57*681cb550SMatthias Ringwald #include "btstack_lc3.h"
58*681cb550SMatthias Ringwald #include "btstack_lc3_google.h"
59*681cb550SMatthias Ringwald #endif
60*681cb550SMatthias Ringwald 
61*681cb550SMatthias Ringwald 
62f89e874bSMatthias Ringwald #ifdef _MSC_VER
63f89e874bSMatthias Ringwald // ignore deprecated warning for fopen
64f89e874bSMatthias Ringwald #pragma warning(disable : 4996)
65f89e874bSMatthias Ringwald #endif
66f89e874bSMatthias Ringwald 
6735fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
68fbc7c9f2SMilanka Ringwald #include "wav_util.h"
6935fd3fb9SMatthias Ringwald #endif
70fbc7c9f2SMilanka Ringwald 
71c4e666bcSMatthias Ringwald // test modes
72f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		 0
7394381a69SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 1
741762039cSMatthias Ringwald #define SCO_DEMO_MODE_MODPLAYER  2
75f7c85330SMatthias Ringwald 
76f7c85330SMatthias Ringwald // SCO demo configuration
77d365bb51SMatthias Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_MICROPHONE
78c4e666bcSMatthias Ringwald 
79c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console
80f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD           100
81f7c85330SMatthias Ringwald 
82f55ac442SMatthias Ringwald 
83d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
842c7ae6e1SMatthias Ringwald // length and name of wav file on disk
85c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
868b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
87859f2bc5SMatthias Ringwald #endif
88859f2bc5SMatthias Ringwald 
89c4e666bcSMatthias Ringwald // constants
90c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
91b150a479SMatthias Ringwald #define SAMPLE_RATE_8KHZ        8000
92b150a479SMatthias Ringwald #define SAMPLE_RATE_16KHZ       16000
93*681cb550SMatthias Ringwald #define SAMPLE_RATE_32KHZ       32000
94379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
95f7c85330SMatthias Ringwald 
96*681cb550SMatthias Ringwald // audio pre-buffer - also defines latency
97b150a479SMatthias Ringwald #define SCO_PREBUFFER_MS      50
98b150a479SMatthias Ringwald #define PREBUFFER_BYTES_8KHZ  (SCO_PREBUFFER_MS *  SAMPLE_RATE_8KHZ/1000 * BYTES_PER_FRAME)
99b150a479SMatthias Ringwald #define PREBUFFER_BYTES_16KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_16KHZ/1000 * BYTES_PER_FRAME)
100*681cb550SMatthias Ringwald #define PREBUFFER_BYTES_32KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_32KHZ/1000 * BYTES_PER_FRAME)
101f7c85330SMatthias Ringwald 
102*681cb550SMatthias Ringwald #if defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH)
103*681cb550SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_32KHZ
104*681cb550SMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 240
105*681cb550SMatthias Ringwald #elif defined(ENABLE_HFP_WIDE_BAND_SPEECH)
1069582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_16KHZ
107f0d95bdcSMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 120
1089582ae64SMatthias Ringwald #else
1099582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_8KHZ
110f0d95bdcSMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 60
1119582ae64SMatthias Ringwald #endif
1129582ae64SMatthias Ringwald 
113bf958e42SMatthias Ringwald static uint16_t              audio_prebuffer_bytes;
114bf958e42SMatthias Ringwald 
1152b89dbfcSMatthias Ringwald // output
116d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
1179582ae64SMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
118379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
1192b89dbfcSMatthias Ringwald 
1202b89dbfcSMatthias Ringwald // input
1212b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
122379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
1233cf06407SMatthias Ringwald #else
1243cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR
1253cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data);
1266fb1424bSMatthias Ringwald #endif
127*681cb550SMatthias Ringwald 
128379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
1299582ae64SMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
130379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
131f7c85330SMatthias Ringwald 
1321762039cSMatthias Ringwald // mod player
1331762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
1341762039cSMatthias Ringwald #include "hxcmod.h"
1351762039cSMatthias Ringwald #include "mods/mod.h"
1361762039cSMatthias Ringwald static modcontext mod_context;
1371762039cSMatthias Ringwald #endif
1381762039cSMatthias Ringwald 
139fcb08cdbSMilanka Ringwald static int count_sent = 0;
140fcb08cdbSMilanka Ringwald static int count_received = 0;
141c4e666bcSMatthias Ringwald 
142*681cb550SMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
143*681cb550SMatthias Ringwald 
1441bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
145*681cb550SMatthias Ringwald static btstack_sbc_decoder_state_t msbc_decoder_state;
1461bbecc2bSMatthias Ringwald #endif
1471bbecc2bSMatthias Ringwald 
148*681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
149*681cb550SMatthias Ringwald static const btstack_lc3_decoder_t * lc3_decoder;
150*681cb550SMatthias Ringwald static btstack_lc3_decoder_google_t lc3_decoder_context;
151*681cb550SMatthias Ringwald static hfp_h2_sync_t    hfp_h2_sync;
152*681cb550SMatthias Ringwald #endif
153379c5f5fSMatthias Ringwald 
1542b89dbfcSMatthias Ringwald int num_samples_to_write;
1552b89dbfcSMatthias Ringwald int num_audio_frames;
1562b89dbfcSMatthias Ringwald 
157bf958e42SMatthias Ringwald // generic codec support
158bf958e42SMatthias Ringwald typedef struct {
159bf958e42SMatthias Ringwald     void (*init)(void);
160bf958e42SMatthias Ringwald     void(*receive)(const uint8_t * packet, uint16_t size);
161bf958e42SMatthias Ringwald     void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length);
162bf958e42SMatthias Ringwald     void (*close)(void);
16379cc780fSMatthias Ringwald     //
16479cc780fSMatthias Ringwald     uint16_t sample_rate;
165bf958e42SMatthias Ringwald } codec_support_t;
16679cc780fSMatthias Ringwald 
16779cc780fSMatthias Ringwald // current configuration
168bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL;
169bf958e42SMatthias Ringwald 
170f0d95bdcSMatthias Ringwald // hfp_codec
171f0d95bdcSMatthias Ringwald static hfp_codec_t hfp_codec;
172d6a06398SMatthias Ringwald 
1739ad691b0SMatthias Ringwald // Sine Wave
1749ad691b0SMatthias Ringwald 
1759ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
1769ad691b0SMatthias Ringwald static uint16_t sine_wave_phase;
1779ad691b0SMatthias Ringwald static uint16_t sine_wave_steps_per_sample;
178*681cb550SMatthias Ringwald #define SINE_WAVE_SAMPLE_RATE SAMPLE_RATE_32KHZ
17994381a69SMatthias Ringwald 
180*681cb550SMatthias Ringwald // input signal: pre-computed int16 sine wave, 32000 Hz at 266 Hz
181*681cb550SMatthias Ringwald static const int16_t sine_int16[] = {
182*681cb550SMatthias Ringwald      0,   1715,   3425,   5126,   6813,   8481,  10126,  11743,  13328,  14876,
183*681cb550SMatthias Ringwald  16383,  17846,  19260,  20621,  21925,  23170,  24351,  25465,  26509,  27481,
184*681cb550SMatthias Ringwald  28377,  29196,  29934,  30591,  31163,  31650,  32051,  32364,  32587,  32722,
185*681cb550SMatthias Ringwald  32767,  32722,  32587,  32364,  32051,  31650,  31163,  30591,  29934,  29196,
186*681cb550SMatthias Ringwald  28377,  27481,  26509,  25465,  24351,  23170,  21925,  20621,  19260,  17846,
187*681cb550SMatthias Ringwald  16383,  14876,  13328,  11743,  10126,   8481,   6813,   5126,   3425,   1715,
188*681cb550SMatthias Ringwald      0,  -1715,  -3425,  -5126,  -6813,  -8481, -10126, -11743, -13328, -14876,
189*681cb550SMatthias Ringwald -16384, -17846, -19260, -20621, -21925, -23170, -24351, -25465, -26509, -27481,
190*681cb550SMatthias Ringwald -28377, -29196, -29934, -30591, -31163, -31650, -32051, -32364, -32587, -32722,
191*681cb550SMatthias Ringwald -32767, -32722, -32587, -32364, -32051, -31650, -31163, -30591, -29934, -29196,
192*681cb550SMatthias Ringwald -28377, -27481, -26509, -25465, -24351, -23170, -21925, -20621, -19260, -17846,
193*681cb550SMatthias Ringwald -16384, -14876, -13328, -11743, -10126,  -8481,  -6813,  -5126,  -3425,  -1715,
19435fd3fb9SMatthias Ringwald };
19535fd3fb9SMatthias Ringwald 
1969ad691b0SMatthias Ringwald static void sco_demo_sine_wave_host_endian(uint16_t num_samples, int16_t * data){
197249d94cfSMatthias Ringwald     unsigned int i;
19859c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
199*681cb550SMatthias Ringwald         data[i] = sine_int16[sine_wave_phase];
2009ad691b0SMatthias Ringwald         sine_wave_phase += sine_wave_steps_per_sample;
201*681cb550SMatthias Ringwald         if (sine_wave_phase >= (sizeof(sine_int16) / sizeof(int16_t))){
2029ad691b0SMatthias Ringwald             sine_wave_phase = 0;
20335fd3fb9SMatthias Ringwald         }
20435fd3fb9SMatthias Ringwald     }
20535fd3fb9SMatthias Ringwald }
2061bbecc2bSMatthias Ringwald #endif
207dbb41bfeSMilanka Ringwald 
2081762039cSMatthias Ringwald // Mod Player
2091762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
2101762039cSMatthias Ringwald #define NUM_SAMPLES_GENERATOR_BUFFER 30
2111762039cSMatthias Ringwald static void sco_demo_modplayer(uint16_t num_samples, int16_t * data){
2121762039cSMatthias Ringwald     // mix down stereo
2131762039cSMatthias Ringwald     signed short samples[NUM_SAMPLES_GENERATOR_BUFFER * 2];
2141762039cSMatthias Ringwald     while (num_samples > 0){
2151762039cSMatthias Ringwald         uint16_t next_samples = btstack_min(num_samples, NUM_SAMPLES_GENERATOR_BUFFER);
2161762039cSMatthias Ringwald     	hxcmod_fillbuffer(&mod_context, (unsigned short *) samples, next_samples, NULL);
2171762039cSMatthias Ringwald         num_samples -= next_samples;
2181762039cSMatthias Ringwald         uint16_t i;
2191762039cSMatthias Ringwald         for (i=0;i<next_samples;i++){
2201762039cSMatthias Ringwald             int32_t left  = samples[2*i + 0];
2211762039cSMatthias Ringwald             int32_t right = samples[2*i + 1];
2221762039cSMatthias Ringwald             data[i] = (int16_t)((left + right) / 2);
2231762039cSMatthias Ringwald         }
2241762039cSMatthias Ringwald     }
2251762039cSMatthias Ringwald }
2261762039cSMatthias Ringwald #endif
2271762039cSMatthias Ringwald 
22894381a69SMatthias Ringwald // Audio Playback / Recording
229d861f4bfSMatthias Ringwald 
23094381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){
2312b89dbfcSMatthias Ringwald 
232c4e666bcSMatthias Ringwald     // fill with silence while paused
233379c5f5fSMatthias Ringwald     if (audio_output_paused){
234bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){
235f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
236379c5f5fSMatthias Ringwald            return;
237dbb41bfeSMilanka Ringwald         } else {
238c4e666bcSMatthias Ringwald             // resume playback
239379c5f5fSMatthias Ringwald             audio_output_paused = 0;
240dbb41bfeSMilanka Ringwald         }
241c4e666bcSMatthias Ringwald     }
242c4e666bcSMatthias Ringwald 
243c4e666bcSMatthias Ringwald     // get data from ringbuffer
244c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
245f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
246f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
247f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
248c4e666bcSMatthias Ringwald 
249c4e666bcSMatthias Ringwald     // fill with 0 if not enough
250f55ac442SMatthias Ringwald     if (num_samples){
251f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
252379c5f5fSMatthias Ringwald         audio_output_paused = 1;
253c4e666bcSMatthias Ringwald     }
254379c5f5fSMatthias Ringwald }
2558b29cfc6SMatthias Ringwald 
256379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
25794381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){
258379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
259c4e666bcSMatthias Ringwald }
260379c5f5fSMatthias Ringwald #endif
261c4e666bcSMatthias Ringwald 
262c4e666bcSMatthias Ringwald // return 1 if ok
263379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
264c4e666bcSMatthias Ringwald 
265d365bb51SMatthias Ringwald     // -- output -- //
266d365bb51SMatthias Ringwald 
267379c5f5fSMatthias Ringwald     // init buffers
268379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
269379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2702b89dbfcSMatthias Ringwald 
271d365bb51SMatthias Ringwald     // config and setup audio playback
272d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
273d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2742b89dbfcSMatthias Ringwald 
27594381a69SMatthias Ringwald     audio_sink->init(1, sample_rate, &audio_playback_callback);
276d365bb51SMatthias Ringwald     audio_sink->start_stream();
277379c5f5fSMatthias Ringwald 
278379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
279d365bb51SMatthias Ringwald 
280d365bb51SMatthias Ringwald     // -- input -- //
281d365bb51SMatthias Ringwald 
282d365bb51SMatthias Ringwald     // init buffers
283d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
284d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
2856fb1424bSMatthias Ringwald     audio_input_paused  = 1;
286d365bb51SMatthias Ringwald 
2876fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT
288d365bb51SMatthias Ringwald     // config and setup audio recording
289d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
290d365bb51SMatthias Ringwald     if (!audio_source) return 0;
291d365bb51SMatthias Ringwald 
29294381a69SMatthias Ringwald     audio_source->init(1, sample_rate, &audio_recording_callback);
293d365bb51SMatthias Ringwald     audio_source->start_stream();
2942b89dbfcSMatthias Ringwald #endif
2952b89dbfcSMatthias Ringwald 
296c4e666bcSMatthias Ringwald     return 1;
297c4e666bcSMatthias Ringwald }
2982b89dbfcSMatthias Ringwald 
299379c5f5fSMatthias Ringwald static void audio_terminate(void){
300d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
301d365bb51SMatthias Ringwald     if (!audio_sink) return;
302d365bb51SMatthias Ringwald     audio_sink->close();
303d365bb51SMatthias Ringwald 
304d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
305d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
306d365bb51SMatthias Ringwald     if (!audio_source) return;
307d365bb51SMatthias Ringwald     audio_source->close();
308d365bb51SMatthias Ringwald #endif
3092b89dbfcSMatthias Ringwald }
310c4e666bcSMatthias Ringwald 
311d861f4bfSMatthias Ringwald 
31294381a69SMatthias Ringwald // CVSD - 8 kHz
313fcb08cdbSMilanka Ringwald 
314bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){
315c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
316fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
317fbc7c9f2SMilanka Ringwald }
318fbc7c9f2SMilanka Ringwald 
319bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){
3202c7ae6e1SMatthias Ringwald 
3215303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
3221f8694ccSMatthias Ringwald 
3231f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
324bf958e42SMatthias Ringwald         printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n");
3251f8694ccSMatthias Ringwald         return;
3261f8694ccSMatthias Ringwald     }
3272c7ae6e1SMatthias Ringwald 
328c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
329379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
3305303ddeeSMatthias Ringwald 
3315303ddeeSMatthias Ringwald     // convert into host endian
3325303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
3335303ddeeSMatthias Ringwald     int i;
3345303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
3355303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
3365303ddeeSMatthias Ringwald     }
3375303ddeeSMatthias Ringwald 
3385f4f94c7SMatthias Ringwald     // treat packet as bad frame if controller does not report 'all good'
3395f4f94c7SMatthias Ringwald     bool bad_frame = (packet[1] & 0x30) != 0;
3405f4f94c7SMatthias Ringwald 
3415f4f94c7SMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out);
3425303ddeeSMatthias Ringwald 
3432c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3442c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3452c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3462c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3472c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3482c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3492c7ae6e1SMatthias Ringwald         wav_writer_close();
3502c7ae6e1SMatthias Ringwald     }
3512c7ae6e1SMatthias Ringwald #endif
3522c7ae6e1SMatthias Ringwald 
353379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
354fcb08cdbSMilanka Ringwald }
355fcb08cdbSMilanka Ringwald 
356bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
3576fb1424bSMatthias Ringwald     uint16_t bytes_to_copy = sco_payload_length;
3586fb1424bSMatthias Ringwald 
3592b89dbfcSMatthias Ringwald     // get data from ringbuffer
3602b89dbfcSMatthias Ringwald     uint16_t pos = 0;
361379c5f5fSMatthias Ringwald     if (!audio_input_paused){
3626fb1424bSMatthias Ringwald         uint16_t samples_to_copy = sco_payload_length / 2;
3632b89dbfcSMatthias Ringwald         uint32_t bytes_read = 0;
3646fb1424bSMatthias Ringwald         btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read);
3658fd6902dSMatthias Ringwald         // flip 16 on big endian systems
3668fd6902dSMatthias Ringwald         // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
3678fd6902dSMatthias Ringwald         if (btstack_is_big_endian()){
3686fb1424bSMatthias Ringwald             uint16_t i;
3696fb1424bSMatthias Ringwald             for (i=0;i<samples_to_copy/2;i+=2){
3706fb1424bSMatthias Ringwald                 uint8_t tmp           = payload_buffer[i*2];
3716fb1424bSMatthias Ringwald                 payload_buffer[i*2]   = payload_buffer[i*2+1];
3726fb1424bSMatthias Ringwald                 payload_buffer[i*2+1] = tmp;
3738fd6902dSMatthias Ringwald             }
3748fd6902dSMatthias Ringwald         }
3752b89dbfcSMatthias Ringwald         bytes_to_copy -= bytes_read;
3762b89dbfcSMatthias Ringwald         pos           += bytes_read;
3772b89dbfcSMatthias Ringwald     }
3782b89dbfcSMatthias Ringwald 
3792b89dbfcSMatthias Ringwald     // fill with 0 if not enough
3802b89dbfcSMatthias Ringwald     if (bytes_to_copy){
3816fb1424bSMatthias Ringwald         memset(payload_buffer + pos, 0, bytes_to_copy);
382379c5f5fSMatthias Ringwald         audio_input_paused = 1;
3832b89dbfcSMatthias Ringwald     }
3842b89dbfcSMatthias Ringwald }
38594381a69SMatthias Ringwald 
386bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){
387bf958e42SMatthias 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);
388bf958e42SMatthias Ringwald }
389bf958e42SMatthias Ringwald 
390bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = {
391bf958e42SMatthias Ringwald         .init         = &sco_demo_cvsd_init,
392bf958e42SMatthias Ringwald         .receive      = &sco_demo_cvsd_receive,
393bf958e42SMatthias Ringwald         .fill_payload = &sco_demo_cvsd_fill_payload,
39479cc780fSMatthias Ringwald         .close        = &sco_demo_cvsd_close,
39579cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_8KHZ
396bf958e42SMatthias Ringwald };
397bf958e42SMatthias Ringwald 
398*681cb550SMatthias Ringwald // encode using hfp_codec
399*681cb550SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH) || defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH)
400*681cb550SMatthias Ringwald void sco_demo_codec_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
401*681cb550SMatthias Ringwald     if (!audio_input_paused){
402*681cb550SMatthias Ringwald         int num_samples = hfp_codec_num_audio_samples_per_frame(&hfp_codec);
403*681cb550SMatthias Ringwald         btstack_assert(num_samples <= SAMPLES_PER_FRAME_MAX);
404*681cb550SMatthias Ringwald         uint16_t samples_available = btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) / BYTES_PER_FRAME;
405*681cb550SMatthias Ringwald         if (hfp_codec_can_encode_audio_frame_now(&hfp_codec) && samples_available >= num_samples){
406*681cb550SMatthias Ringwald             int16_t sample_buffer[SAMPLES_PER_FRAME_MAX];
407*681cb550SMatthias Ringwald             uint32_t bytes_read;
408*681cb550SMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
409*681cb550SMatthias Ringwald             hfp_codec_encode_audio_frame(&hfp_codec, sample_buffer);
410*681cb550SMatthias Ringwald             num_audio_frames++;
411*681cb550SMatthias Ringwald         }
412*681cb550SMatthias Ringwald     }
413*681cb550SMatthias Ringwald     // get data from encoder, fill with 0 if not enough
414*681cb550SMatthias Ringwald     if (audio_input_paused || hfp_codec_num_bytes_available(&hfp_codec) < sco_payload_length){
415*681cb550SMatthias Ringwald         // just send '0's
416*681cb550SMatthias Ringwald         memset(payload_buffer, 0, sco_payload_length);
417*681cb550SMatthias Ringwald         audio_input_paused = 1;
418*681cb550SMatthias Ringwald     } else {
419*681cb550SMatthias Ringwald         hfp_codec_read_from_stream(&hfp_codec, payload_buffer, sco_payload_length);
420*681cb550SMatthias Ringwald     }
421*681cb550SMatthias Ringwald }
422*681cb550SMatthias Ringwald #endif
423*681cb550SMatthias Ringwald 
42494381a69SMatthias Ringwald // mSBC - 16 kHz
42594381a69SMatthias Ringwald 
42694381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
42794381a69SMatthias Ringwald 
42894381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
42994381a69SMatthias Ringwald     UNUSED(context);
43094381a69SMatthias Ringwald     UNUSED(sample_rate);
43194381a69SMatthias Ringwald     UNUSED(data);
43294381a69SMatthias Ringwald     UNUSED(num_samples);
43394381a69SMatthias Ringwald     UNUSED(num_channels);
43494381a69SMatthias Ringwald 
43594381a69SMatthias Ringwald     // samples in callback in host endianess, ready for playback
43694381a69SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
43794381a69SMatthias Ringwald 
43894381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
43994381a69SMatthias Ringwald     if (!num_samples_to_write) return;
44094381a69SMatthias Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
44194381a69SMatthias Ringwald     num_samples_to_write -= num_samples;
44294381a69SMatthias Ringwald     wav_writer_write_int16(num_samples, data);
44394381a69SMatthias Ringwald     if (num_samples_to_write == 0){
44494381a69SMatthias Ringwald         wav_writer_close();
445f7c85330SMatthias Ringwald     }
44694381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
4471a919128SMatthias Ringwald }
44894381a69SMatthias Ringwald 
449bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){
45094381a69SMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
451*681cb550SMatthias Ringwald     btstack_sbc_decoder_init(&msbc_decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
452f0d95bdcSMatthias Ringwald     hfp_codec_init(&hfp_codec, HFP_CODEC_MSBC);
45394381a69SMatthias Ringwald }
45494381a69SMatthias Ringwald 
455bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){
456*681cb550SMatthias Ringwald     btstack_sbc_decoder_process_data(&msbc_decoder_state, (packet[1] >> 4) & 3, packet + 3, size - 3);
45794381a69SMatthias Ringwald }
45894381a69SMatthias Ringwald 
459bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){
460*681cb550SMatthias Ringwald     printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.\n", msbc_decoder_state.good_frames_nr, msbc_decoder_state.zero_frames_nr, msbc_decoder_state.bad_frames_nr);
461bf958e42SMatthias Ringwald }
462bf958e42SMatthias Ringwald 
463bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = {
464bf958e42SMatthias Ringwald         .init         = &sco_demo_msbc_init,
465bf958e42SMatthias Ringwald         .receive      = &sco_demo_msbc_receive,
466*681cb550SMatthias Ringwald         .fill_payload = &sco_demo_codec_fill_payload,
46779cc780fSMatthias Ringwald         .close        = &sco_demo_msbc_close,
46879cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_16KHZ
469bf958e42SMatthias Ringwald };
470bf958e42SMatthias Ringwald 
47194381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
47294381a69SMatthias Ringwald 
473*681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
474*681cb550SMatthias Ringwald 
475*681cb550SMatthias Ringwald #define LC3_SWB_SAMPLES_PER_FRAME 240
476*681cb550SMatthias Ringwald #define LC3_SWB_OCTETS_PER_FRAME   58
477*681cb550SMatthias Ringwald 
478*681cb550SMatthias Ringwald static bool sco_demo_lc3swb_frame_callback(bool bad_frame, const uint8_t * frame_data, uint16_t frame_len){
479*681cb550SMatthias Ringwald 
480*681cb550SMatthias Ringwald     // skip H2 header for good frames
481*681cb550SMatthias Ringwald     if (bad_frame == false){
482*681cb550SMatthias Ringwald         btstack_assert(frame_data != NULL);
483*681cb550SMatthias Ringwald         frame_data += 2;
484*681cb550SMatthias Ringwald     }
485*681cb550SMatthias Ringwald 
486*681cb550SMatthias Ringwald     uint8_t tmp_BEC_detect = 0;
487*681cb550SMatthias Ringwald     uint8_t BFI = bad_frame ? 1 : 0;
488*681cb550SMatthias Ringwald     int16_t samples[LC3_SWB_SAMPLES_PER_FRAME];
489*681cb550SMatthias Ringwald     (void) lc3_decoder->decode_signed_16(&lc3_decoder_context, frame_data, BFI,
490*681cb550SMatthias Ringwald                                          samples, 1, &tmp_BEC_detect);
491*681cb550SMatthias Ringwald 
492*681cb550SMatthias Ringwald     // samples in callback in host endianess, ready for playback
493*681cb550SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)samples, LC3_SWB_SAMPLES_PER_FRAME*2);
494*681cb550SMatthias Ringwald 
495*681cb550SMatthias Ringwald #ifdef SCO_WAV_FILENAME
496*681cb550SMatthias Ringwald     if (num_samples_to_write > 0){
497*681cb550SMatthias Ringwald         uint16_t num_samples = btstack_min(LC3_SWB_SAMPLES_PER_FRAME, num_samples_to_write);
498*681cb550SMatthias Ringwald         num_samples_to_write -= num_samples;
499*681cb550SMatthias Ringwald         wav_writer_write_int16(num_samples, samples);
500*681cb550SMatthias Ringwald         if (num_samples_to_write == 0){
501*681cb550SMatthias Ringwald             wav_writer_close();
502*681cb550SMatthias Ringwald         }
503*681cb550SMatthias Ringwald     }
504*681cb550SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
505*681cb550SMatthias Ringwald 
506*681cb550SMatthias Ringwald     // frame is good, if it isn't a bad frame and we didn't detect other errors
507*681cb550SMatthias Ringwald     return (bad_frame == false) && (tmp_BEC_detect == 0);
508*681cb550SMatthias Ringwald }
509*681cb550SMatthias Ringwald 
510*681cb550SMatthias Ringwald static void sco_demo_lc3swb_init(void){
511*681cb550SMatthias Ringwald 
512*681cb550SMatthias Ringwald     printf("SCO Demo: Init LC3-SWB\n");
513*681cb550SMatthias Ringwald 
514*681cb550SMatthias Ringwald     hfp_codec_init(&hfp_codec, HFP_CODEC_LC3_SWB);
515*681cb550SMatthias Ringwald 
516*681cb550SMatthias Ringwald     // init lc3 decoder
517*681cb550SMatthias Ringwald     lc3_decoder = btstack_lc3_decoder_google_init_instance(&lc3_decoder_context);
518*681cb550SMatthias Ringwald     lc3_decoder->configure(&lc3_decoder_context, SAMPLE_RATE_32KHZ, BTSTACK_LC3_FRAME_DURATION_7500US, LC3_SWB_OCTETS_PER_FRAME);
519*681cb550SMatthias Ringwald 
520*681cb550SMatthias Ringwald     // init HPF H2 framing
521*681cb550SMatthias Ringwald     hfp_h2_sync_init(&hfp_h2_sync, &sco_demo_lc3swb_frame_callback);
522*681cb550SMatthias Ringwald }
523*681cb550SMatthias Ringwald 
524*681cb550SMatthias Ringwald static void sco_demo_lc3swb_receive(const uint8_t * packet, uint16_t size){
525*681cb550SMatthias Ringwald     uint8_t packet_status = (packet[1] >> 4) & 3;
526*681cb550SMatthias Ringwald     bool bad_frame = packet_status != 0;
527*681cb550SMatthias Ringwald     hfp_h2_sync_process(&hfp_h2_sync, bad_frame, &packet[3], size-3);
528*681cb550SMatthias Ringwald }
529*681cb550SMatthias Ringwald 
530*681cb550SMatthias Ringwald static void sco_demo_lc3swb_close(void){
531*681cb550SMatthias Ringwald     // TODO: report
532*681cb550SMatthias Ringwald }
533*681cb550SMatthias Ringwald 
534*681cb550SMatthias Ringwald static const codec_support_t codec_lc3swb = {
535*681cb550SMatthias Ringwald         .init         = &sco_demo_lc3swb_init,
536*681cb550SMatthias Ringwald         .receive      = &sco_demo_lc3swb_receive,
537*681cb550SMatthias Ringwald         .fill_payload = &sco_demo_codec_fill_payload,
538*681cb550SMatthias Ringwald         .close        = &sco_demo_lc3swb_close,
539*681cb550SMatthias Ringwald         .sample_rate = SAMPLE_RATE_32KHZ
540*681cb550SMatthias Ringwald };
541*681cb550SMatthias Ringwald #endif
542*681cb550SMatthias Ringwald 
54394381a69SMatthias Ringwald void sco_demo_init(void){
54494381a69SMatthias Ringwald 
54594381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS
54694381a69SMatthias Ringwald     printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n");
54794381a69SMatthias Ringwald     gap_secure_connections_enable(false);
54894381a69SMatthias Ringwald #endif
54994381a69SMatthias Ringwald 
550*681cb550SMatthias Ringwald     // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode)
551*681cb550SMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
552*681cb550SMatthias Ringwald 
55394381a69SMatthias Ringwald     // status
55494381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
55594381a69SMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
55694381a69SMatthias Ringwald #endif
55794381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
55894381a69SMatthias Ringwald     printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
55994381a69SMatthias Ringwald #endif
5601762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
561*681cb550SMatthias Ringwald     printf("SCO Demo: Sending modplayer wave, audio output via btstack_audio.\n");
5621762039cSMatthias Ringwald     // init mod
5631762039cSMatthias Ringwald     int hxcmod_initialized = hxcmod_init(&mod_context);
5641762039cSMatthias Ringwald     btstack_assert(hxcmod_initialized != 0);
5651762039cSMatthias Ringwald #endif
56694381a69SMatthias Ringwald }
56794381a69SMatthias Ringwald 
568bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){
56994381a69SMatthias Ringwald     switch (negotiated_codec){
57094381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
571bf958e42SMatthias Ringwald             codec_current = &codec_cvsd;
57294381a69SMatthias Ringwald             break;
57394381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
57494381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
575bf958e42SMatthias Ringwald             codec_current = &codec_msbc;
57694381a69SMatthias Ringwald             break;
57794381a69SMatthias Ringwald #endif
578*681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
579*681cb550SMatthias Ringwald         case HFP_CODEC_LC3_SWB:
580*681cb550SMatthias Ringwald             codec_current = &codec_lc3swb;
581*681cb550SMatthias Ringwald             break;
582*681cb550SMatthias Ringwald #endif
58394381a69SMatthias Ringwald         default:
58494381a69SMatthias Ringwald             btstack_assert(false);
58594381a69SMatthias Ringwald             break;
58694381a69SMatthias Ringwald     }
587bf958e42SMatthias Ringwald 
588bf958e42SMatthias Ringwald     codec_current->init();
5899ad691b0SMatthias Ringwald 
5909ad691b0SMatthias Ringwald     audio_initialize(codec_current->sample_rate);
5919ad691b0SMatthias Ringwald 
5929ad691b0SMatthias Ringwald     audio_prebuffer_bytes = SCO_PREBUFFER_MS * (codec_current->sample_rate/1000) * BYTES_PER_FRAME;
5939ad691b0SMatthias Ringwald 
5949ad691b0SMatthias Ringwald #ifdef SCO_WAV_FILENAME
5959ad691b0SMatthias Ringwald     num_samples_to_write = codec_current->sample_rate * SCO_WAV_DURATION_IN_SECONDS;
5969ad691b0SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, codec_current->sample_rate);
5979ad691b0SMatthias Ringwald #endif
5989ad691b0SMatthias Ringwald 
5999ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
6009ad691b0SMatthias Ringwald     sine_wave_steps_per_sample = SINE_WAVE_SAMPLE_RATE / codec_current->sample_rate;
6019ad691b0SMatthias Ringwald     sco_demo_audio_generator = &sco_demo_sine_wave_host_endian;
6029ad691b0SMatthias Ringwald #endif
6031762039cSMatthias Ringwald 
6041762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
6051762039cSMatthias Ringwald     // load mod
6061762039cSMatthias Ringwald     hxcmod_setcfg(&mod_context, codec_current->sample_rate, 16, 1, 1, 1);
6071762039cSMatthias Ringwald     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
6081762039cSMatthias Ringwald     sco_demo_audio_generator = &sco_demo_modplayer;
6091762039cSMatthias Ringwald #endif
61094381a69SMatthias Ringwald }
61194381a69SMatthias Ringwald 
61294381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
61394381a69SMatthias Ringwald     static uint32_t packets = 0;
61494381a69SMatthias Ringwald     static uint32_t crc_errors = 0;
61594381a69SMatthias Ringwald     static uint32_t data_received = 0;
61694381a69SMatthias Ringwald     static uint32_t byte_errors = 0;
61794381a69SMatthias Ringwald 
61894381a69SMatthias Ringwald     count_received++;
61994381a69SMatthias Ringwald 
62094381a69SMatthias Ringwald     data_received += size - 3;
62194381a69SMatthias Ringwald     packets++;
62294381a69SMatthias Ringwald     if (data_received > 100000){
62394381a69SMatthias 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);
62494381a69SMatthias Ringwald         crc_errors = 0;
62594381a69SMatthias Ringwald         byte_errors = 0;
62694381a69SMatthias Ringwald         data_received = 0;
62794381a69SMatthias Ringwald         packets = 0;
62894381a69SMatthias Ringwald     }
62994381a69SMatthias Ringwald 
630bf958e42SMatthias Ringwald     codec_current->receive(packet, size);
63194381a69SMatthias Ringwald }
63294381a69SMatthias Ringwald 
63394381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
63494381a69SMatthias Ringwald 
63594381a69SMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
63694381a69SMatthias Ringwald 
63794381a69SMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
63894381a69SMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
63994381a69SMatthias Ringwald 
64094381a69SMatthias Ringwald     hci_reserve_packet_buffer();
64194381a69SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
64294381a69SMatthias Ringwald 
643bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
644bf958e42SMatthias Ringwald     #define REFILL_SAMPLES 16
645bf958e42SMatthias Ringwald     // re-fill audio buffer
646bf958e42SMatthias Ringwald     uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2;
647bf958e42SMatthias Ringwald     while (samples_free > 0){
648bf958e42SMatthias Ringwald         int16_t samples_buffer[REFILL_SAMPLES];
649bf958e42SMatthias Ringwald         uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES);
650bf958e42SMatthias Ringwald         (*sco_demo_audio_generator)(samples_to_add, samples_buffer);
651bf958e42SMatthias Ringwald         btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2);
652bf958e42SMatthias Ringwald         samples_free -= samples_to_add;
65394381a69SMatthias Ringwald     }
654bf958e42SMatthias Ringwald #endif
655bf958e42SMatthias Ringwald 
656bf958e42SMatthias Ringwald     // resume if pre-buffer is filled
657bf958e42SMatthias Ringwald     if (audio_input_paused){
658bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){
659bf958e42SMatthias Ringwald             // resume sending
660bf958e42SMatthias Ringwald             audio_input_paused = 0;
661bf958e42SMatthias Ringwald         }
662bf958e42SMatthias Ringwald     }
663bf958e42SMatthias Ringwald 
664bf958e42SMatthias Ringwald     // fill payload by codec
665bf958e42SMatthias Ringwald     codec_current->fill_payload(&sco_packet[3], sco_payload_length);
6662b89dbfcSMatthias Ringwald 
667c4e666bcSMatthias Ringwald     // set handle + flags
668c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
669c4e666bcSMatthias Ringwald     // set len
670c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
671c4e666bcSMatthias Ringwald     // finally send packet
672f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
673f7c85330SMatthias Ringwald 
674f7c85330SMatthias Ringwald     // request another send event
675f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
676f7c85330SMatthias Ringwald 
6774a96141eSMatthias Ringwald     count_sent++;
67894381a69SMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) {
67994381a69SMatthias Ringwald         printf("SCO: sent %u, received %u\n", count_sent, count_received);
68094381a69SMatthias Ringwald     }
681f7c85330SMatthias Ringwald }
682f7c85330SMatthias Ringwald 
68394381a69SMatthias Ringwald void sco_demo_close(void){
68494381a69SMatthias Ringwald     printf("SCO demo close\n");
6851a919128SMatthias Ringwald 
68694381a69SMatthias Ringwald     printf("SCO demo statistics: ");
687bf958e42SMatthias Ringwald     codec_current->close();
688bf958e42SMatthias Ringwald     codec_current = NULL;
68994381a69SMatthias Ringwald 
69094381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
69194381a69SMatthias Ringwald     wav_writer_close();
6928b29cfc6SMatthias Ringwald #endif
6938b29cfc6SMatthias Ringwald 
69494381a69SMatthias Ringwald     audio_terminate();
695f7c85330SMatthias Ringwald }
696