xref: /btstack/example/sco_demo_util.c (revision 0a4f399a9d2305b59c2c6b8e6c36b1618bf00571)
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 
56681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
57681cb550SMatthias Ringwald #include "btstack_lc3.h"
58681cb550SMatthias Ringwald #include "btstack_lc3_google.h"
59681cb550SMatthias Ringwald #endif
60681cb550SMatthias Ringwald 
61681cb550SMatthias 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
93681cb550SMatthias Ringwald #define SAMPLE_RATE_32KHZ       32000
94379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
95f7c85330SMatthias Ringwald 
96681cb550SMatthias 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)
100681cb550SMatthias Ringwald #define PREBUFFER_BYTES_32KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_32KHZ/1000 * BYTES_PER_FRAME)
101f7c85330SMatthias Ringwald 
102681cb550SMatthias Ringwald #if defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH)
103681cb550SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_32KHZ
104681cb550SMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 240
105681cb550SMatthias 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
127681cb550SMatthias 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 
142681cb550SMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
143681cb550SMatthias Ringwald 
1441bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
145*0a4f399aSMatthias Ringwald static btstack_sbc_encoder_state_t msbc_encoder_state;
146681cb550SMatthias Ringwald static btstack_sbc_decoder_state_t msbc_decoder_state;
1471bbecc2bSMatthias Ringwald #endif
1481bbecc2bSMatthias Ringwald 
149681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
150681cb550SMatthias Ringwald static const btstack_lc3_decoder_t * lc3_decoder;
151681cb550SMatthias Ringwald static btstack_lc3_decoder_google_t lc3_decoder_context;
152aeb2ea11SMatthias Ringwald static btstack_lc3_encoder_google_t lc3_encoder_context;
153681cb550SMatthias Ringwald static hfp_h2_sync_t    hfp_h2_sync;
154681cb550SMatthias Ringwald #endif
155379c5f5fSMatthias Ringwald 
1562b89dbfcSMatthias Ringwald int num_samples_to_write;
1572b89dbfcSMatthias Ringwald int num_audio_frames;
1582b89dbfcSMatthias Ringwald 
159bf958e42SMatthias Ringwald // generic codec support
160bf958e42SMatthias Ringwald typedef struct {
161bf958e42SMatthias Ringwald     void (*init)(void);
162bf958e42SMatthias Ringwald     void(*receive)(const uint8_t * packet, uint16_t size);
163bf958e42SMatthias Ringwald     void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length);
164bf958e42SMatthias Ringwald     void (*close)(void);
16579cc780fSMatthias Ringwald     //
16679cc780fSMatthias Ringwald     uint16_t sample_rate;
167bf958e42SMatthias Ringwald } codec_support_t;
16879cc780fSMatthias Ringwald 
16979cc780fSMatthias Ringwald // current configuration
170bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL;
171bf958e42SMatthias Ringwald 
172f0d95bdcSMatthias Ringwald // hfp_codec
173f0d95bdcSMatthias Ringwald static hfp_codec_t hfp_codec;
174d6a06398SMatthias Ringwald 
1759ad691b0SMatthias Ringwald // Sine Wave
1769ad691b0SMatthias Ringwald 
1779ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
1789ad691b0SMatthias Ringwald static uint16_t sine_wave_phase;
1799ad691b0SMatthias Ringwald static uint16_t sine_wave_steps_per_sample;
180681cb550SMatthias Ringwald #define SINE_WAVE_SAMPLE_RATE SAMPLE_RATE_32KHZ
18194381a69SMatthias Ringwald 
182681cb550SMatthias Ringwald // input signal: pre-computed int16 sine wave, 32000 Hz at 266 Hz
183681cb550SMatthias Ringwald static const int16_t sine_int16[] = {
184681cb550SMatthias Ringwald      0,   1715,   3425,   5126,   6813,   8481,  10126,  11743,  13328,  14876,
185681cb550SMatthias Ringwald  16383,  17846,  19260,  20621,  21925,  23170,  24351,  25465,  26509,  27481,
186681cb550SMatthias Ringwald  28377,  29196,  29934,  30591,  31163,  31650,  32051,  32364,  32587,  32722,
187681cb550SMatthias Ringwald  32767,  32722,  32587,  32364,  32051,  31650,  31163,  30591,  29934,  29196,
188681cb550SMatthias Ringwald  28377,  27481,  26509,  25465,  24351,  23170,  21925,  20621,  19260,  17846,
189681cb550SMatthias Ringwald  16383,  14876,  13328,  11743,  10126,   8481,   6813,   5126,   3425,   1715,
190681cb550SMatthias Ringwald      0,  -1715,  -3425,  -5126,  -6813,  -8481, -10126, -11743, -13328, -14876,
191681cb550SMatthias Ringwald -16384, -17846, -19260, -20621, -21925, -23170, -24351, -25465, -26509, -27481,
192681cb550SMatthias Ringwald -28377, -29196, -29934, -30591, -31163, -31650, -32051, -32364, -32587, -32722,
193681cb550SMatthias Ringwald -32767, -32722, -32587, -32364, -32051, -31650, -31163, -30591, -29934, -29196,
194681cb550SMatthias Ringwald -28377, -27481, -26509, -25465, -24351, -23170, -21925, -20621, -19260, -17846,
195681cb550SMatthias Ringwald -16384, -14876, -13328, -11743, -10126,  -8481,  -6813,  -5126,  -3425,  -1715,
19635fd3fb9SMatthias Ringwald };
19735fd3fb9SMatthias Ringwald 
1989ad691b0SMatthias Ringwald static void sco_demo_sine_wave_host_endian(uint16_t num_samples, int16_t * data){
199249d94cfSMatthias Ringwald     unsigned int i;
20059c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
201681cb550SMatthias Ringwald         data[i] = sine_int16[sine_wave_phase];
2029ad691b0SMatthias Ringwald         sine_wave_phase += sine_wave_steps_per_sample;
203681cb550SMatthias Ringwald         if (sine_wave_phase >= (sizeof(sine_int16) / sizeof(int16_t))){
2049ad691b0SMatthias Ringwald             sine_wave_phase = 0;
20535fd3fb9SMatthias Ringwald         }
20635fd3fb9SMatthias Ringwald     }
20735fd3fb9SMatthias Ringwald }
2081bbecc2bSMatthias Ringwald #endif
209dbb41bfeSMilanka Ringwald 
2101762039cSMatthias Ringwald // Mod Player
2111762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
2121762039cSMatthias Ringwald #define NUM_SAMPLES_GENERATOR_BUFFER 30
2131762039cSMatthias Ringwald static void sco_demo_modplayer(uint16_t num_samples, int16_t * data){
2141762039cSMatthias Ringwald     // mix down stereo
2151762039cSMatthias Ringwald     signed short samples[NUM_SAMPLES_GENERATOR_BUFFER * 2];
2161762039cSMatthias Ringwald     while (num_samples > 0){
2171762039cSMatthias Ringwald         uint16_t next_samples = btstack_min(num_samples, NUM_SAMPLES_GENERATOR_BUFFER);
2181762039cSMatthias Ringwald     	hxcmod_fillbuffer(&mod_context, (unsigned short *) samples, next_samples, NULL);
2191762039cSMatthias Ringwald         num_samples -= next_samples;
2201762039cSMatthias Ringwald         uint16_t i;
2211762039cSMatthias Ringwald         for (i=0;i<next_samples;i++){
2221762039cSMatthias Ringwald             int32_t left  = samples[2*i + 0];
2231762039cSMatthias Ringwald             int32_t right = samples[2*i + 1];
2241762039cSMatthias Ringwald             data[i] = (int16_t)((left + right) / 2);
2251762039cSMatthias Ringwald         }
2261762039cSMatthias Ringwald     }
2271762039cSMatthias Ringwald }
2281762039cSMatthias Ringwald #endif
2291762039cSMatthias Ringwald 
23094381a69SMatthias Ringwald // Audio Playback / Recording
231d861f4bfSMatthias Ringwald 
23294381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){
2332b89dbfcSMatthias Ringwald 
234c4e666bcSMatthias Ringwald     // fill with silence while paused
235379c5f5fSMatthias Ringwald     if (audio_output_paused){
236bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){
237f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
238379c5f5fSMatthias Ringwald            return;
239dbb41bfeSMilanka Ringwald         } else {
240c4e666bcSMatthias Ringwald             // resume playback
241379c5f5fSMatthias Ringwald             audio_output_paused = 0;
242dbb41bfeSMilanka Ringwald         }
243c4e666bcSMatthias Ringwald     }
244c4e666bcSMatthias Ringwald 
245c4e666bcSMatthias Ringwald     // get data from ringbuffer
246c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
247f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
248f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
249f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
250c4e666bcSMatthias Ringwald 
251c4e666bcSMatthias Ringwald     // fill with 0 if not enough
252f55ac442SMatthias Ringwald     if (num_samples){
253f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
254379c5f5fSMatthias Ringwald         audio_output_paused = 1;
255c4e666bcSMatthias Ringwald     }
256379c5f5fSMatthias Ringwald }
2578b29cfc6SMatthias Ringwald 
258379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
25994381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){
260379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
261c4e666bcSMatthias Ringwald }
262379c5f5fSMatthias Ringwald #endif
263c4e666bcSMatthias Ringwald 
264c4e666bcSMatthias Ringwald // return 1 if ok
265379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
266c4e666bcSMatthias Ringwald 
267d365bb51SMatthias Ringwald     // -- output -- //
268d365bb51SMatthias Ringwald 
269379c5f5fSMatthias Ringwald     // init buffers
270379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
271379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2722b89dbfcSMatthias Ringwald 
273d365bb51SMatthias Ringwald     // config and setup audio playback
274d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
275e0c8f71bSMatthias Ringwald     if (audio_sink != NULL){
27694381a69SMatthias Ringwald         audio_sink->init(1, sample_rate, &audio_playback_callback);
277d365bb51SMatthias Ringwald         audio_sink->start_stream();
278379c5f5fSMatthias Ringwald 
279379c5f5fSMatthias Ringwald         audio_output_paused  = 1;
280e0c8f71bSMatthias Ringwald     }
281d365bb51SMatthias Ringwald 
282d365bb51SMatthias Ringwald     // -- input -- //
283d365bb51SMatthias Ringwald 
284d365bb51SMatthias Ringwald     // init buffers
285d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
286d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
2876fb1424bSMatthias Ringwald     audio_input_paused  = 1;
288d365bb51SMatthias Ringwald 
2896fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT
290d365bb51SMatthias Ringwald     // config and setup audio recording
291d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
292e0c8f71bSMatthias Ringwald     if (audio_source != NULL){
29394381a69SMatthias Ringwald         audio_source->init(1, sample_rate, &audio_recording_callback);
294d365bb51SMatthias Ringwald         audio_source->start_stream();
295e0c8f71bSMatthias Ringwald     }
2962b89dbfcSMatthias Ringwald #endif
2972b89dbfcSMatthias Ringwald 
298c4e666bcSMatthias Ringwald     return 1;
299c4e666bcSMatthias Ringwald }
3002b89dbfcSMatthias Ringwald 
301379c5f5fSMatthias Ringwald static void audio_terminate(void){
302d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
303d365bb51SMatthias Ringwald     if (!audio_sink) return;
304d365bb51SMatthias Ringwald     audio_sink->close();
305d365bb51SMatthias Ringwald 
306d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
307d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
308d365bb51SMatthias Ringwald     if (!audio_source) return;
309d365bb51SMatthias Ringwald     audio_source->close();
310d365bb51SMatthias Ringwald #endif
3112b89dbfcSMatthias Ringwald }
312c4e666bcSMatthias Ringwald 
313d861f4bfSMatthias Ringwald 
31494381a69SMatthias Ringwald // CVSD - 8 kHz
315fcb08cdbSMilanka Ringwald 
316bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){
317c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
318fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
319fbc7c9f2SMilanka Ringwald }
320fbc7c9f2SMilanka Ringwald 
321bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){
3222c7ae6e1SMatthias Ringwald 
3235303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
3241f8694ccSMatthias Ringwald 
3251f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
326bf958e42SMatthias Ringwald         printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n");
3271f8694ccSMatthias Ringwald         return;
3281f8694ccSMatthias Ringwald     }
3292c7ae6e1SMatthias Ringwald 
330c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
331379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
3325303ddeeSMatthias Ringwald 
3335303ddeeSMatthias Ringwald     // convert into host endian
3345303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
3355303ddeeSMatthias Ringwald     int i;
3365303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
3375303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
3385303ddeeSMatthias Ringwald     }
3395303ddeeSMatthias Ringwald 
3405f4f94c7SMatthias Ringwald     // treat packet as bad frame if controller does not report 'all good'
3415f4f94c7SMatthias Ringwald     bool bad_frame = (packet[1] & 0x30) != 0;
3425f4f94c7SMatthias Ringwald 
3435f4f94c7SMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out);
3445303ddeeSMatthias Ringwald 
3452c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
3462c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
3472c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
3482c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
3492c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
3502c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
3512c7ae6e1SMatthias Ringwald         wav_writer_close();
3522c7ae6e1SMatthias Ringwald     }
3532c7ae6e1SMatthias Ringwald #endif
3542c7ae6e1SMatthias Ringwald 
355379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
356fcb08cdbSMilanka Ringwald }
357fcb08cdbSMilanka Ringwald 
358bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
3596fb1424bSMatthias Ringwald     uint16_t bytes_to_copy = sco_payload_length;
3606fb1424bSMatthias Ringwald 
3612b89dbfcSMatthias Ringwald     // get data from ringbuffer
3622b89dbfcSMatthias Ringwald     uint16_t pos = 0;
363379c5f5fSMatthias Ringwald     if (!audio_input_paused){
3646fb1424bSMatthias Ringwald         uint16_t samples_to_copy = sco_payload_length / 2;
3652b89dbfcSMatthias Ringwald         uint32_t bytes_read = 0;
3666fb1424bSMatthias Ringwald         btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read);
3678fd6902dSMatthias Ringwald         // flip 16 on big endian systems
3688fd6902dSMatthias Ringwald         // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
3698fd6902dSMatthias Ringwald         if (btstack_is_big_endian()){
3706fb1424bSMatthias Ringwald             uint16_t i;
3716fb1424bSMatthias Ringwald             for (i=0;i<samples_to_copy/2;i+=2){
3726fb1424bSMatthias Ringwald                 uint8_t tmp           = payload_buffer[i*2];
3736fb1424bSMatthias Ringwald                 payload_buffer[i*2]   = payload_buffer[i*2+1];
3746fb1424bSMatthias Ringwald                 payload_buffer[i*2+1] = tmp;
3758fd6902dSMatthias Ringwald             }
3768fd6902dSMatthias Ringwald         }
3772b89dbfcSMatthias Ringwald         bytes_to_copy -= bytes_read;
3782b89dbfcSMatthias Ringwald         pos           += bytes_read;
3792b89dbfcSMatthias Ringwald     }
3802b89dbfcSMatthias Ringwald 
3812b89dbfcSMatthias Ringwald     // fill with 0 if not enough
3822b89dbfcSMatthias Ringwald     if (bytes_to_copy){
3836fb1424bSMatthias Ringwald         memset(payload_buffer + pos, 0, bytes_to_copy);
384379c5f5fSMatthias Ringwald         audio_input_paused = 1;
3852b89dbfcSMatthias Ringwald     }
3862b89dbfcSMatthias Ringwald }
38794381a69SMatthias Ringwald 
388bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){
389bf958e42SMatthias 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);
390bf958e42SMatthias Ringwald }
391bf958e42SMatthias Ringwald 
392bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = {
393bf958e42SMatthias Ringwald         .init         = &sco_demo_cvsd_init,
394bf958e42SMatthias Ringwald         .receive      = &sco_demo_cvsd_receive,
395bf958e42SMatthias Ringwald         .fill_payload = &sco_demo_cvsd_fill_payload,
39679cc780fSMatthias Ringwald         .close        = &sco_demo_cvsd_close,
39779cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_8KHZ
398bf958e42SMatthias Ringwald };
399bf958e42SMatthias Ringwald 
400681cb550SMatthias Ringwald // encode using hfp_codec
401681cb550SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH) || defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH)
402d4872f4eSMatthias Ringwald static void sco_demo_codec_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
403681cb550SMatthias Ringwald     if (!audio_input_paused){
404681cb550SMatthias Ringwald         int num_samples = hfp_codec_num_audio_samples_per_frame(&hfp_codec);
405681cb550SMatthias Ringwald         btstack_assert(num_samples <= SAMPLES_PER_FRAME_MAX);
406681cb550SMatthias Ringwald         uint16_t samples_available = btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) / BYTES_PER_FRAME;
407681cb550SMatthias Ringwald         if (hfp_codec_can_encode_audio_frame_now(&hfp_codec) && samples_available >= num_samples){
408681cb550SMatthias Ringwald             int16_t sample_buffer[SAMPLES_PER_FRAME_MAX];
409681cb550SMatthias Ringwald             uint32_t bytes_read;
410681cb550SMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
411681cb550SMatthias Ringwald             hfp_codec_encode_audio_frame(&hfp_codec, sample_buffer);
412681cb550SMatthias Ringwald             num_audio_frames++;
413681cb550SMatthias Ringwald         }
414681cb550SMatthias Ringwald     }
415681cb550SMatthias Ringwald     // get data from encoder, fill with 0 if not enough
416681cb550SMatthias Ringwald     if (audio_input_paused || hfp_codec_num_bytes_available(&hfp_codec) < sco_payload_length){
417681cb550SMatthias Ringwald         // just send '0's
418681cb550SMatthias Ringwald         memset(payload_buffer, 0, sco_payload_length);
419681cb550SMatthias Ringwald         audio_input_paused = 1;
420681cb550SMatthias Ringwald     } else {
421681cb550SMatthias Ringwald         hfp_codec_read_from_stream(&hfp_codec, payload_buffer, sco_payload_length);
422681cb550SMatthias Ringwald     }
423681cb550SMatthias Ringwald }
424681cb550SMatthias Ringwald #endif
425681cb550SMatthias Ringwald 
42694381a69SMatthias Ringwald // mSBC - 16 kHz
42794381a69SMatthias Ringwald 
42894381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
42994381a69SMatthias Ringwald 
43094381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
43194381a69SMatthias Ringwald     UNUSED(context);
43294381a69SMatthias Ringwald     UNUSED(sample_rate);
43394381a69SMatthias Ringwald     UNUSED(data);
43494381a69SMatthias Ringwald     UNUSED(num_samples);
43594381a69SMatthias Ringwald     UNUSED(num_channels);
43694381a69SMatthias Ringwald 
43794381a69SMatthias Ringwald     // samples in callback in host endianess, ready for playback
43894381a69SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
43994381a69SMatthias Ringwald 
44094381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
44194381a69SMatthias Ringwald     if (!num_samples_to_write) return;
44294381a69SMatthias Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
44394381a69SMatthias Ringwald     num_samples_to_write -= num_samples;
44494381a69SMatthias Ringwald     wav_writer_write_int16(num_samples, data);
44594381a69SMatthias Ringwald     if (num_samples_to_write == 0){
44694381a69SMatthias Ringwald         wav_writer_close();
447f7c85330SMatthias Ringwald     }
44894381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
4491a919128SMatthias Ringwald }
45094381a69SMatthias Ringwald 
451bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){
45294381a69SMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
453681cb550SMatthias Ringwald     btstack_sbc_decoder_init(&msbc_decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
454*0a4f399aSMatthias Ringwald     hfp_codec_init_msbc(&hfp_codec, &msbc_encoder_state);
45594381a69SMatthias Ringwald }
45694381a69SMatthias Ringwald 
457bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){
458681cb550SMatthias Ringwald     btstack_sbc_decoder_process_data(&msbc_decoder_state, (packet[1] >> 4) & 3, packet + 3, size - 3);
45994381a69SMatthias Ringwald }
46094381a69SMatthias Ringwald 
461bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){
462681cb550SMatthias 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);
463bf958e42SMatthias Ringwald }
464bf958e42SMatthias Ringwald 
465bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = {
466bf958e42SMatthias Ringwald         .init         = &sco_demo_msbc_init,
467bf958e42SMatthias Ringwald         .receive      = &sco_demo_msbc_receive,
468681cb550SMatthias Ringwald         .fill_payload = &sco_demo_codec_fill_payload,
46979cc780fSMatthias Ringwald         .close        = &sco_demo_msbc_close,
47079cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_16KHZ
471bf958e42SMatthias Ringwald };
472bf958e42SMatthias Ringwald 
47394381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
47494381a69SMatthias Ringwald 
475681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
476681cb550SMatthias Ringwald 
477681cb550SMatthias Ringwald #define LC3_SWB_SAMPLES_PER_FRAME 240
478681cb550SMatthias Ringwald #define LC3_SWB_OCTETS_PER_FRAME   58
479681cb550SMatthias Ringwald 
480681cb550SMatthias Ringwald static bool sco_demo_lc3swb_frame_callback(bool bad_frame, const uint8_t * frame_data, uint16_t frame_len){
481681cb550SMatthias Ringwald 
482681cb550SMatthias Ringwald     // skip H2 header for good frames
483681cb550SMatthias Ringwald     if (bad_frame == false){
484681cb550SMatthias Ringwald         btstack_assert(frame_data != NULL);
485681cb550SMatthias Ringwald         frame_data += 2;
486681cb550SMatthias Ringwald     }
487681cb550SMatthias Ringwald 
488681cb550SMatthias Ringwald     uint8_t tmp_BEC_detect = 0;
489681cb550SMatthias Ringwald     uint8_t BFI = bad_frame ? 1 : 0;
490681cb550SMatthias Ringwald     int16_t samples[LC3_SWB_SAMPLES_PER_FRAME];
491681cb550SMatthias Ringwald     (void) lc3_decoder->decode_signed_16(&lc3_decoder_context, frame_data, BFI,
492681cb550SMatthias Ringwald                                          samples, 1, &tmp_BEC_detect);
493681cb550SMatthias Ringwald 
494681cb550SMatthias Ringwald     // samples in callback in host endianess, ready for playback
495681cb550SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)samples, LC3_SWB_SAMPLES_PER_FRAME*2);
496681cb550SMatthias Ringwald 
497681cb550SMatthias Ringwald #ifdef SCO_WAV_FILENAME
498681cb550SMatthias Ringwald     if (num_samples_to_write > 0){
499681cb550SMatthias Ringwald         uint16_t num_samples = btstack_min(LC3_SWB_SAMPLES_PER_FRAME, num_samples_to_write);
500681cb550SMatthias Ringwald         num_samples_to_write -= num_samples;
501681cb550SMatthias Ringwald         wav_writer_write_int16(num_samples, samples);
502681cb550SMatthias Ringwald         if (num_samples_to_write == 0){
503681cb550SMatthias Ringwald             wav_writer_close();
504681cb550SMatthias Ringwald         }
505681cb550SMatthias Ringwald     }
506681cb550SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
507681cb550SMatthias Ringwald 
508681cb550SMatthias Ringwald     // frame is good, if it isn't a bad frame and we didn't detect other errors
509681cb550SMatthias Ringwald     return (bad_frame == false) && (tmp_BEC_detect == 0);
510681cb550SMatthias Ringwald }
511681cb550SMatthias Ringwald 
512681cb550SMatthias Ringwald static void sco_demo_lc3swb_init(void){
513681cb550SMatthias Ringwald 
514681cb550SMatthias Ringwald     printf("SCO Demo: Init LC3-SWB\n");
515681cb550SMatthias Ringwald 
516aeb2ea11SMatthias Ringwald     const btstack_lc3_encoder_t * lc3_encoder = btstack_lc3_encoder_google_init_instance((btstack_lc3_encoder_google_t *) hfp_codec.lc3_encoder_context);
517aeb2ea11SMatthias Ringwald     hfp_codec_init_lc3_swb(&hfp_codec, lc3_encoder, &lc3_encoder_context);
518681cb550SMatthias Ringwald 
519681cb550SMatthias Ringwald     // init lc3 decoder
520681cb550SMatthias Ringwald     lc3_decoder = btstack_lc3_decoder_google_init_instance(&lc3_decoder_context);
521681cb550SMatthias Ringwald     lc3_decoder->configure(&lc3_decoder_context, SAMPLE_RATE_32KHZ, BTSTACK_LC3_FRAME_DURATION_7500US, LC3_SWB_OCTETS_PER_FRAME);
522681cb550SMatthias Ringwald 
523681cb550SMatthias Ringwald     // init HPF H2 framing
524681cb550SMatthias Ringwald     hfp_h2_sync_init(&hfp_h2_sync, &sco_demo_lc3swb_frame_callback);
525681cb550SMatthias Ringwald }
526681cb550SMatthias Ringwald 
527681cb550SMatthias Ringwald static void sco_demo_lc3swb_receive(const uint8_t * packet, uint16_t size){
528681cb550SMatthias Ringwald     uint8_t packet_status = (packet[1] >> 4) & 3;
529681cb550SMatthias Ringwald     bool bad_frame = packet_status != 0;
530681cb550SMatthias Ringwald     hfp_h2_sync_process(&hfp_h2_sync, bad_frame, &packet[3], size-3);
531681cb550SMatthias Ringwald }
532681cb550SMatthias Ringwald 
533681cb550SMatthias Ringwald static void sco_demo_lc3swb_close(void){
534681cb550SMatthias Ringwald     // TODO: report
535681cb550SMatthias Ringwald }
536681cb550SMatthias Ringwald 
537681cb550SMatthias Ringwald static const codec_support_t codec_lc3swb = {
538681cb550SMatthias Ringwald         .init         = &sco_demo_lc3swb_init,
539681cb550SMatthias Ringwald         .receive      = &sco_demo_lc3swb_receive,
540681cb550SMatthias Ringwald         .fill_payload = &sco_demo_codec_fill_payload,
541681cb550SMatthias Ringwald         .close        = &sco_demo_lc3swb_close,
542681cb550SMatthias Ringwald         .sample_rate = SAMPLE_RATE_32KHZ
543681cb550SMatthias Ringwald };
544681cb550SMatthias Ringwald #endif
545681cb550SMatthias Ringwald 
54694381a69SMatthias Ringwald void sco_demo_init(void){
54794381a69SMatthias Ringwald 
54894381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS
54994381a69SMatthias Ringwald     printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n");
55094381a69SMatthias Ringwald     gap_secure_connections_enable(false);
55194381a69SMatthias Ringwald #endif
55294381a69SMatthias Ringwald 
553681cb550SMatthias Ringwald     // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode)
554681cb550SMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
555681cb550SMatthias Ringwald 
55694381a69SMatthias Ringwald     // status
55794381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
55894381a69SMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
55994381a69SMatthias Ringwald #endif
56094381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
56194381a69SMatthias Ringwald     printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
56294381a69SMatthias Ringwald #endif
5631762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
564681cb550SMatthias Ringwald     printf("SCO Demo: Sending modplayer wave, audio output via btstack_audio.\n");
5651762039cSMatthias Ringwald     // init mod
5661762039cSMatthias Ringwald     int hxcmod_initialized = hxcmod_init(&mod_context);
5671762039cSMatthias Ringwald     btstack_assert(hxcmod_initialized != 0);
5681762039cSMatthias Ringwald #endif
56994381a69SMatthias Ringwald }
57094381a69SMatthias Ringwald 
571bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){
57294381a69SMatthias Ringwald     switch (negotiated_codec){
57394381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
574bf958e42SMatthias Ringwald             codec_current = &codec_cvsd;
57594381a69SMatthias Ringwald             break;
57694381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
57794381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
578bf958e42SMatthias Ringwald             codec_current = &codec_msbc;
57994381a69SMatthias Ringwald             break;
58094381a69SMatthias Ringwald #endif
581681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH
582681cb550SMatthias Ringwald         case HFP_CODEC_LC3_SWB:
583681cb550SMatthias Ringwald             codec_current = &codec_lc3swb;
584681cb550SMatthias Ringwald             break;
585681cb550SMatthias Ringwald #endif
58694381a69SMatthias Ringwald         default:
58794381a69SMatthias Ringwald             btstack_assert(false);
58894381a69SMatthias Ringwald             break;
58994381a69SMatthias Ringwald     }
590bf958e42SMatthias Ringwald 
591bf958e42SMatthias Ringwald     codec_current->init();
5929ad691b0SMatthias Ringwald 
5939ad691b0SMatthias Ringwald     audio_initialize(codec_current->sample_rate);
5949ad691b0SMatthias Ringwald 
5959ad691b0SMatthias Ringwald     audio_prebuffer_bytes = SCO_PREBUFFER_MS * (codec_current->sample_rate/1000) * BYTES_PER_FRAME;
5969ad691b0SMatthias Ringwald 
5979ad691b0SMatthias Ringwald #ifdef SCO_WAV_FILENAME
5989ad691b0SMatthias Ringwald     num_samples_to_write = codec_current->sample_rate * SCO_WAV_DURATION_IN_SECONDS;
5999ad691b0SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, codec_current->sample_rate);
6009ad691b0SMatthias Ringwald #endif
6019ad691b0SMatthias Ringwald 
6029ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
6039ad691b0SMatthias Ringwald     sine_wave_steps_per_sample = SINE_WAVE_SAMPLE_RATE / codec_current->sample_rate;
6049ad691b0SMatthias Ringwald     sco_demo_audio_generator = &sco_demo_sine_wave_host_endian;
6059ad691b0SMatthias Ringwald #endif
6061762039cSMatthias Ringwald 
6071762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER
6081762039cSMatthias Ringwald     // load mod
6091762039cSMatthias Ringwald     hxcmod_setcfg(&mod_context, codec_current->sample_rate, 16, 1, 1, 1);
6101762039cSMatthias Ringwald     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
6111762039cSMatthias Ringwald     sco_demo_audio_generator = &sco_demo_modplayer;
6121762039cSMatthias Ringwald #endif
61394381a69SMatthias Ringwald }
61494381a69SMatthias Ringwald 
61594381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
61694381a69SMatthias Ringwald     static uint32_t packets = 0;
61794381a69SMatthias Ringwald     static uint32_t crc_errors = 0;
61894381a69SMatthias Ringwald     static uint32_t data_received = 0;
61994381a69SMatthias Ringwald     static uint32_t byte_errors = 0;
62094381a69SMatthias Ringwald 
62194381a69SMatthias Ringwald     count_received++;
62294381a69SMatthias Ringwald 
62394381a69SMatthias Ringwald     data_received += size - 3;
62494381a69SMatthias Ringwald     packets++;
62594381a69SMatthias Ringwald     if (data_received > 100000){
62694381a69SMatthias 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);
62794381a69SMatthias Ringwald         crc_errors = 0;
62894381a69SMatthias Ringwald         byte_errors = 0;
62994381a69SMatthias Ringwald         data_received = 0;
63094381a69SMatthias Ringwald         packets = 0;
63194381a69SMatthias Ringwald     }
63294381a69SMatthias Ringwald 
633bf958e42SMatthias Ringwald     codec_current->receive(packet, size);
63494381a69SMatthias Ringwald }
63594381a69SMatthias Ringwald 
63694381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
63794381a69SMatthias Ringwald 
63894381a69SMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
63994381a69SMatthias Ringwald 
64094381a69SMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
64194381a69SMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
64294381a69SMatthias Ringwald 
64394381a69SMatthias Ringwald     hci_reserve_packet_buffer();
64494381a69SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
64594381a69SMatthias Ringwald 
646bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
647bf958e42SMatthias Ringwald     #define REFILL_SAMPLES 16
648bf958e42SMatthias Ringwald     // re-fill audio buffer
649bf958e42SMatthias Ringwald     uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2;
650bf958e42SMatthias Ringwald     while (samples_free > 0){
651bf958e42SMatthias Ringwald         int16_t samples_buffer[REFILL_SAMPLES];
652bf958e42SMatthias Ringwald         uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES);
653bf958e42SMatthias Ringwald         (*sco_demo_audio_generator)(samples_to_add, samples_buffer);
654bf958e42SMatthias Ringwald         btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2);
655bf958e42SMatthias Ringwald         samples_free -= samples_to_add;
65694381a69SMatthias Ringwald     }
657bf958e42SMatthias Ringwald #endif
658bf958e42SMatthias Ringwald 
659bf958e42SMatthias Ringwald     // resume if pre-buffer is filled
660bf958e42SMatthias Ringwald     if (audio_input_paused){
661bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){
662bf958e42SMatthias Ringwald             // resume sending
663bf958e42SMatthias Ringwald             audio_input_paused = 0;
664bf958e42SMatthias Ringwald         }
665bf958e42SMatthias Ringwald     }
666bf958e42SMatthias Ringwald 
667bf958e42SMatthias Ringwald     // fill payload by codec
668bf958e42SMatthias Ringwald     codec_current->fill_payload(&sco_packet[3], sco_payload_length);
6692b89dbfcSMatthias Ringwald 
670c4e666bcSMatthias Ringwald     // set handle + flags
671c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
672c4e666bcSMatthias Ringwald     // set len
673c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
674c4e666bcSMatthias Ringwald     // finally send packet
675f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
676f7c85330SMatthias Ringwald 
677f7c85330SMatthias Ringwald     // request another send event
678f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
679f7c85330SMatthias Ringwald 
6804a96141eSMatthias Ringwald     count_sent++;
68194381a69SMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) {
68294381a69SMatthias Ringwald         printf("SCO: sent %u, received %u\n", count_sent, count_received);
68394381a69SMatthias Ringwald     }
684f7c85330SMatthias Ringwald }
685f7c85330SMatthias Ringwald 
68694381a69SMatthias Ringwald void sco_demo_close(void){
68794381a69SMatthias Ringwald     printf("SCO demo close\n");
6881a919128SMatthias Ringwald 
68994381a69SMatthias Ringwald     printf("SCO demo statistics: ");
690bf958e42SMatthias Ringwald     codec_current->close();
691bf958e42SMatthias Ringwald     codec_current = NULL;
69294381a69SMatthias Ringwald 
69394381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
69494381a69SMatthias Ringwald     wav_writer_close();
6958b29cfc6SMatthias Ringwald #endif
6968b29cfc6SMatthias Ringwald 
69794381a69SMatthias Ringwald     audio_terminate();
698f7c85330SMatthias Ringwald }
699