xref: /btstack/example/sco_demo_util.c (revision 9ad691b0cbc1133a4cee3358610c55b16151df7d)
1f7c85330SMatthias Ringwald /*
2f7c85330SMatthias Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3f7c85330SMatthias Ringwald  *
4f7c85330SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5f7c85330SMatthias Ringwald  * modification, are permitted provided that the following conditions
6f7c85330SMatthias Ringwald  * are met:
7f7c85330SMatthias Ringwald  *
8f7c85330SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9f7c85330SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10f7c85330SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11f7c85330SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12f7c85330SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13f7c85330SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14f7c85330SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15f7c85330SMatthias Ringwald  *    from this software without specific prior written permission.
16f7c85330SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17f7c85330SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18f7c85330SMatthias Ringwald  *    monetary gain.
19f7c85330SMatthias Ringwald  *
20f7c85330SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21f7c85330SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22f7c85330SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25f7c85330SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26f7c85330SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27f7c85330SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28f7c85330SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29f7c85330SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30f7c85330SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31f7c85330SMatthias Ringwald  * SUCH DAMAGE.
32f7c85330SMatthias Ringwald  *
33f7c85330SMatthias Ringwald  * Please inquire about commercial licensing options at
34f7c85330SMatthias Ringwald  * [email protected]
35f7c85330SMatthias Ringwald  *
36f7c85330SMatthias Ringwald  */
37ab2c6ae4SMatthias Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "sco_demo_util.c"
39f7c85330SMatthias Ringwald 
40f7c85330SMatthias Ringwald /*
41f7c85330SMatthias Ringwald  * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo
42f7c85330SMatthias Ringwald  */
43f7c85330SMatthias Ringwald 
442ec72fbbSMilanka Ringwald #include <stdio.h>
452ec72fbbSMilanka Ringwald 
46f7c85330SMatthias Ringwald #include "sco_demo_util.h"
47379c5f5fSMatthias Ringwald 
48379c5f5fSMatthias Ringwald #include "btstack_audio.h"
49fcb08cdbSMilanka Ringwald #include "btstack_debug.h"
50379c5f5fSMatthias Ringwald #include "btstack_ring_buffer.h"
5135fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h"
52379c5f5fSMatthias Ringwald #include "classic/btstack_sbc.h"
5335fd3fb9SMatthias Ringwald #include "classic/hfp.h"
54379c5f5fSMatthias Ringwald #include "classic/hfp_msbc.h"
55fcb08cdbSMilanka Ringwald 
56f89e874bSMatthias Ringwald #ifdef _MSC_VER
57f89e874bSMatthias Ringwald // ignore deprecated warning for fopen
58f89e874bSMatthias Ringwald #pragma warning(disable : 4996)
59f89e874bSMatthias Ringwald #endif
60f89e874bSMatthias Ringwald 
6135fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
62fbc7c9f2SMilanka Ringwald #include "wav_util.h"
6335fd3fb9SMatthias Ringwald #endif
64fbc7c9f2SMilanka Ringwald 
65c4e666bcSMatthias Ringwald // test modes
66f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		 0
6794381a69SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 1
68f7c85330SMatthias Ringwald 
69f7c85330SMatthias Ringwald // SCO demo configuration
70d365bb51SMatthias Ringwald #define SCO_DEMO_MODE               SCO_DEMO_MODE_MICROPHONE
71c4e666bcSMatthias Ringwald 
72c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console
73f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD           100
74f7c85330SMatthias Ringwald 
75f55ac442SMatthias Ringwald 
76d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
772c7ae6e1SMatthias Ringwald // length and name of wav file on disk
78c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
798b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME            "sco_input.wav"
80859f2bc5SMatthias Ringwald #endif
81859f2bc5SMatthias Ringwald 
82c4e666bcSMatthias Ringwald // constants
83c4e666bcSMatthias Ringwald #define NUM_CHANNELS            1
84b150a479SMatthias Ringwald #define SAMPLE_RATE_8KHZ        8000
85b150a479SMatthias Ringwald #define SAMPLE_RATE_16KHZ       16000
86379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME         2
87f7c85330SMatthias Ringwald 
88b150a479SMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency
89b150a479SMatthias Ringwald #define SCO_PREBUFFER_MS      50
90b150a479SMatthias Ringwald #define PREBUFFER_BYTES_8KHZ  (SCO_PREBUFFER_MS *  SAMPLE_RATE_8KHZ/1000 * BYTES_PER_FRAME)
91b150a479SMatthias Ringwald #define PREBUFFER_BYTES_16KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_16KHZ/1000 * BYTES_PER_FRAME)
92f7c85330SMatthias Ringwald 
939582ae64SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH)
949582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_16KHZ
959582ae64SMatthias Ringwald #else
969582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_8KHZ
979582ae64SMatthias Ringwald #endif
989582ae64SMatthias Ringwald 
99bf958e42SMatthias Ringwald static uint16_t              audio_prebuffer_bytes;
100bf958e42SMatthias Ringwald 
1012b89dbfcSMatthias Ringwald // output
102d861f4bfSMatthias Ringwald static int                   audio_output_paused  = 0;
1039582ae64SMatthias Ringwald static uint8_t               audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
104379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer;
1052b89dbfcSMatthias Ringwald 
1062b89dbfcSMatthias Ringwald // input
1072b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
108379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT
1093cf06407SMatthias Ringwald #else
1103cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR
1113cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data);
1126fb1424bSMatthias Ringwald #endif
113379c5f5fSMatthias Ringwald static int                   audio_input_paused  = 0;
1149582ae64SMatthias Ringwald static uint8_t               audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX];
115379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer;
116f7c85330SMatthias Ringwald 
117fcb08cdbSMilanka Ringwald static int count_sent = 0;
118fcb08cdbSMilanka Ringwald static int count_received = 0;
119c4e666bcSMatthias Ringwald 
1201bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
12179cc780fSMatthias Ringwald #define MSBC_MAX_NUM_SAMPLES (16*8)
122379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state;
1231bbecc2bSMatthias Ringwald #endif
1241bbecc2bSMatthias Ringwald 
125379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
126379c5f5fSMatthias Ringwald 
1272b89dbfcSMatthias Ringwald int num_samples_to_write;
1282b89dbfcSMatthias Ringwald int num_audio_frames;
1292b89dbfcSMatthias Ringwald 
130bf958e42SMatthias Ringwald // generic codec support
131bf958e42SMatthias Ringwald typedef struct {
132bf958e42SMatthias Ringwald     void (*init)(void);
133bf958e42SMatthias Ringwald     void(*receive)(const uint8_t * packet, uint16_t size);
134bf958e42SMatthias Ringwald     void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length);
135bf958e42SMatthias Ringwald     void (*close)(void);
13679cc780fSMatthias Ringwald     //
13779cc780fSMatthias Ringwald     uint16_t sample_rate;
138bf958e42SMatthias Ringwald } codec_support_t;
13979cc780fSMatthias Ringwald 
14079cc780fSMatthias Ringwald // current configuration
141bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL;
142bf958e42SMatthias Ringwald 
143d6a06398SMatthias Ringwald 
144*9ad691b0SMatthias Ringwald // Sine Wave
145*9ad691b0SMatthias Ringwald 
146*9ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
147*9ad691b0SMatthias Ringwald static uint16_t sine_wave_phase;
148*9ad691b0SMatthias Ringwald static uint16_t sine_wave_steps_per_sample;
149*9ad691b0SMatthias Ringwald #define SINE_WAVE_SAMPLE_RATE SAMPLE_RATE_16KHZ
15094381a69SMatthias Ringwald 
1517556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz
152c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = {
1537556ab9fSMatthias Ringwald      0,   3135,   6237,   9270,  12202,  14999,  17633,  20073,  22294,  24270,
1547556ab9fSMatthias Ringwald  25980,  27406,  28531,  29344,  29835,  30000,  29835,  29344,  28531,  27406,
1557556ab9fSMatthias Ringwald  25980,  24270,  22294,  20073,  17633,  14999,  12202,   9270,   6237,   3135,
1567556ab9fSMatthias Ringwald      0,  -3135,  -6237,  -9270, -12202, -14999, -17633, -20073, -22294, -24270,
1577556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406,
1587556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202,  -9270,  -6237,  -3135,
15935fd3fb9SMatthias Ringwald };
16035fd3fb9SMatthias Ringwald 
161*9ad691b0SMatthias Ringwald static void sco_demo_sine_wave_host_endian(uint16_t num_samples, int16_t * data){
162249d94cfSMatthias Ringwald     unsigned int i;
16359c97ae1SMatthias Ringwald     for (i=0; i < num_samples; i++){
164*9ad691b0SMatthias Ringwald         data[i] = sine_int16_at_16000hz[sine_wave_phase];
165*9ad691b0SMatthias Ringwald         sine_wave_phase += sine_wave_steps_per_sample;
166*9ad691b0SMatthias Ringwald         if (sine_wave_phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){
167*9ad691b0SMatthias Ringwald             sine_wave_phase = 0;
16835fd3fb9SMatthias Ringwald         }
16935fd3fb9SMatthias Ringwald     }
17035fd3fb9SMatthias Ringwald }
1711bbecc2bSMatthias Ringwald #endif
172dbb41bfeSMilanka Ringwald 
17394381a69SMatthias Ringwald // Audio Playback / Recording
174d861f4bfSMatthias Ringwald 
17594381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){
1762b89dbfcSMatthias Ringwald 
177c4e666bcSMatthias Ringwald     // fill with silence while paused
178379c5f5fSMatthias Ringwald     if (audio_output_paused){
179bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){
180f55ac442SMatthias Ringwald             memset(buffer, 0, num_samples * BYTES_PER_FRAME);
181379c5f5fSMatthias Ringwald            return;
182dbb41bfeSMilanka Ringwald         } else {
183c4e666bcSMatthias Ringwald             // resume playback
184379c5f5fSMatthias Ringwald             audio_output_paused = 0;
185dbb41bfeSMilanka Ringwald         }
186c4e666bcSMatthias Ringwald     }
187c4e666bcSMatthias Ringwald 
188c4e666bcSMatthias Ringwald     // get data from ringbuffer
189c4e666bcSMatthias Ringwald     uint32_t bytes_read = 0;
190f55ac442SMatthias Ringwald     btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
191f55ac442SMatthias Ringwald     num_samples -= bytes_read / BYTES_PER_FRAME;
192f55ac442SMatthias Ringwald     buffer      += bytes_read / BYTES_PER_FRAME;
193c4e666bcSMatthias Ringwald 
194c4e666bcSMatthias Ringwald     // fill with 0 if not enough
195f55ac442SMatthias Ringwald     if (num_samples){
196f55ac442SMatthias Ringwald         memset(buffer, 0, num_samples * BYTES_PER_FRAME);
197379c5f5fSMatthias Ringwald         audio_output_paused = 1;
198c4e666bcSMatthias Ringwald     }
199379c5f5fSMatthias Ringwald }
2008b29cfc6SMatthias Ringwald 
201379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT
20294381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){
203379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2);
204c4e666bcSMatthias Ringwald }
205379c5f5fSMatthias Ringwald #endif
206c4e666bcSMatthias Ringwald 
207c4e666bcSMatthias Ringwald // return 1 if ok
208379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){
209c4e666bcSMatthias Ringwald 
210d365bb51SMatthias Ringwald     // -- output -- //
211d365bb51SMatthias Ringwald 
212379c5f5fSMatthias Ringwald     // init buffers
213379c5f5fSMatthias Ringwald     memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage));
214379c5f5fSMatthias Ringwald     btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage));
2152b89dbfcSMatthias Ringwald 
216d365bb51SMatthias Ringwald     // config and setup audio playback
217d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
218d365bb51SMatthias Ringwald     if (!audio_sink) return 0;
2192b89dbfcSMatthias Ringwald 
22094381a69SMatthias Ringwald     audio_sink->init(1, sample_rate, &audio_playback_callback);
221d365bb51SMatthias Ringwald     audio_sink->start_stream();
222379c5f5fSMatthias Ringwald 
223379c5f5fSMatthias Ringwald     audio_output_paused  = 1;
224d365bb51SMatthias Ringwald 
225d365bb51SMatthias Ringwald     // -- input -- //
226d365bb51SMatthias Ringwald 
227d365bb51SMatthias Ringwald     // init buffers
228d365bb51SMatthias Ringwald     memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage));
229d365bb51SMatthias Ringwald     btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage));
2306fb1424bSMatthias Ringwald     audio_input_paused  = 1;
231d365bb51SMatthias Ringwald 
2326fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT
233d365bb51SMatthias Ringwald     // config and setup audio recording
234d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
235d365bb51SMatthias Ringwald     if (!audio_source) return 0;
236d365bb51SMatthias Ringwald 
23794381a69SMatthias Ringwald     audio_source->init(1, sample_rate, &audio_recording_callback);
238d365bb51SMatthias Ringwald     audio_source->start_stream();
2392b89dbfcSMatthias Ringwald #endif
2402b89dbfcSMatthias Ringwald 
241c4e666bcSMatthias Ringwald     return 1;
242c4e666bcSMatthias Ringwald }
2432b89dbfcSMatthias Ringwald 
244379c5f5fSMatthias Ringwald static void audio_terminate(void){
245d365bb51SMatthias Ringwald     const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
246d365bb51SMatthias Ringwald     if (!audio_sink) return;
247d365bb51SMatthias Ringwald     audio_sink->close();
248d365bb51SMatthias Ringwald 
249d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT
250d365bb51SMatthias Ringwald     const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance();
251d365bb51SMatthias Ringwald     if (!audio_source) return;
252d365bb51SMatthias Ringwald     audio_source->close();
253d365bb51SMatthias Ringwald #endif
2542b89dbfcSMatthias Ringwald }
255c4e666bcSMatthias Ringwald 
256d861f4bfSMatthias Ringwald 
25794381a69SMatthias Ringwald // CVSD - 8 kHz
258fcb08cdbSMilanka Ringwald 
259bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){
260c4e666bcSMatthias Ringwald     printf("SCO Demo: Init CVSD\n");
261fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
262fbc7c9f2SMilanka Ringwald }
263fbc7c9f2SMilanka Ringwald 
264bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){
2652c7ae6e1SMatthias Ringwald 
2665303ddeeSMatthias Ringwald     int16_t audio_frame_out[128];    //
2671f8694ccSMatthias Ringwald 
2681f8694ccSMatthias Ringwald     if (size > sizeof(audio_frame_out)){
269bf958e42SMatthias Ringwald         printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n");
2701f8694ccSMatthias Ringwald         return;
2711f8694ccSMatthias Ringwald     }
2722c7ae6e1SMatthias Ringwald 
273c4e666bcSMatthias Ringwald     const int audio_bytes_read = size - 3;
274379c5f5fSMatthias Ringwald     const int num_samples = audio_bytes_read / BYTES_PER_FRAME;
2755303ddeeSMatthias Ringwald 
2765303ddeeSMatthias Ringwald     // convert into host endian
2775303ddeeSMatthias Ringwald     int16_t audio_frame_in[128];
2785303ddeeSMatthias Ringwald     int i;
2795303ddeeSMatthias Ringwald     for (i=0;i<num_samples;i++){
2805303ddeeSMatthias Ringwald         audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2);
2815303ddeeSMatthias Ringwald     }
2825303ddeeSMatthias Ringwald 
2835f4f94c7SMatthias Ringwald     // treat packet as bad frame if controller does not report 'all good'
2845f4f94c7SMatthias Ringwald     bool bad_frame = (packet[1] & 0x30) != 0;
2855f4f94c7SMatthias Ringwald 
2865f4f94c7SMatthias Ringwald     btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out);
2875303ddeeSMatthias Ringwald 
2882c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME
2892c7ae6e1SMatthias Ringwald     // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut)
2902c7ae6e1SMatthias Ringwald     const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
2912c7ae6e1SMatthias Ringwald     wav_writer_write_le_int16(samples_to_write, audio_frame_out);
2922c7ae6e1SMatthias Ringwald     num_samples_to_write -= samples_to_write;
2932c7ae6e1SMatthias Ringwald     if (num_samples_to_write == 0){
2942c7ae6e1SMatthias Ringwald         wav_writer_close();
2952c7ae6e1SMatthias Ringwald     }
2962c7ae6e1SMatthias Ringwald #endif
2972c7ae6e1SMatthias Ringwald 
298379c5f5fSMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
299fcb08cdbSMilanka Ringwald }
300fcb08cdbSMilanka Ringwald 
301bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
3026fb1424bSMatthias Ringwald     uint16_t bytes_to_copy = sco_payload_length;
3036fb1424bSMatthias Ringwald 
3042b89dbfcSMatthias Ringwald     // get data from ringbuffer
3052b89dbfcSMatthias Ringwald     uint16_t pos = 0;
306379c5f5fSMatthias Ringwald     if (!audio_input_paused){
3076fb1424bSMatthias Ringwald         uint16_t samples_to_copy = sco_payload_length / 2;
3082b89dbfcSMatthias Ringwald         uint32_t bytes_read = 0;
3096fb1424bSMatthias Ringwald         btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read);
3108fd6902dSMatthias Ringwald         // flip 16 on big endian systems
3118fd6902dSMatthias Ringwald         // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
3128fd6902dSMatthias Ringwald         if (btstack_is_big_endian()){
3136fb1424bSMatthias Ringwald             uint16_t i;
3146fb1424bSMatthias Ringwald             for (i=0;i<samples_to_copy/2;i+=2){
3156fb1424bSMatthias Ringwald                 uint8_t tmp           = payload_buffer[i*2];
3166fb1424bSMatthias Ringwald                 payload_buffer[i*2]   = payload_buffer[i*2+1];
3176fb1424bSMatthias Ringwald                 payload_buffer[i*2+1] = tmp;
3188fd6902dSMatthias Ringwald             }
3198fd6902dSMatthias Ringwald         }
3202b89dbfcSMatthias Ringwald         bytes_to_copy -= bytes_read;
3212b89dbfcSMatthias Ringwald         pos           += bytes_read;
3222b89dbfcSMatthias Ringwald     }
3232b89dbfcSMatthias Ringwald 
3242b89dbfcSMatthias Ringwald     // fill with 0 if not enough
3252b89dbfcSMatthias Ringwald     if (bytes_to_copy){
3266fb1424bSMatthias Ringwald         memset(payload_buffer + pos, 0, bytes_to_copy);
327379c5f5fSMatthias Ringwald         audio_input_paused = 1;
3282b89dbfcSMatthias Ringwald     }
3292b89dbfcSMatthias Ringwald }
33094381a69SMatthias Ringwald 
331bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){
332bf958e42SMatthias 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);
333bf958e42SMatthias Ringwald }
334bf958e42SMatthias Ringwald 
335bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = {
336bf958e42SMatthias Ringwald         .init         = &sco_demo_cvsd_init,
337bf958e42SMatthias Ringwald         .receive      = &sco_demo_cvsd_receive,
338bf958e42SMatthias Ringwald         .fill_payload = &sco_demo_cvsd_fill_payload,
33979cc780fSMatthias Ringwald         .close        = &sco_demo_cvsd_close,
34079cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_8KHZ
341bf958e42SMatthias Ringwald };
342bf958e42SMatthias Ringwald 
34394381a69SMatthias Ringwald // mSBC - 16 kHz
34494381a69SMatthias Ringwald 
34594381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
34694381a69SMatthias Ringwald 
34794381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
34894381a69SMatthias Ringwald     UNUSED(context);
34994381a69SMatthias Ringwald     UNUSED(sample_rate);
35094381a69SMatthias Ringwald     UNUSED(data);
35194381a69SMatthias Ringwald     UNUSED(num_samples);
35294381a69SMatthias Ringwald     UNUSED(num_channels);
35394381a69SMatthias Ringwald 
35494381a69SMatthias Ringwald     // samples in callback in host endianess, ready for playback
35594381a69SMatthias Ringwald     btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
35694381a69SMatthias Ringwald 
35794381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME
35894381a69SMatthias Ringwald     if (!num_samples_to_write) return;
35994381a69SMatthias Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
36094381a69SMatthias Ringwald     num_samples_to_write -= num_samples;
36194381a69SMatthias Ringwald     wav_writer_write_int16(num_samples, data);
36294381a69SMatthias Ringwald     if (num_samples_to_write == 0){
36394381a69SMatthias Ringwald         wav_writer_close();
364f7c85330SMatthias Ringwald     }
36594381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */
3661a919128SMatthias Ringwald }
36794381a69SMatthias Ringwald 
368bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){
36994381a69SMatthias Ringwald     printf("SCO Demo: Init mSBC\n");
37094381a69SMatthias Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
37194381a69SMatthias Ringwald     hfp_msbc_init();
37294381a69SMatthias Ringwald }
37394381a69SMatthias Ringwald 
374bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){
37594381a69SMatthias Ringwald     btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
37694381a69SMatthias Ringwald }
37794381a69SMatthias Ringwald 
378bf958e42SMatthias Ringwald void sco_demo_msbc_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){
37994381a69SMatthias Ringwald     if (!audio_input_paused){
38094381a69SMatthias Ringwald         int num_samples = hfp_msbc_num_audio_samples_per_frame();
38179cc780fSMatthias Ringwald         btstack_assert(num_samples <= MSBC_MAX_NUM_SAMPLES);
38294381a69SMatthias Ringwald         if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= (unsigned int)(num_samples * BYTES_PER_FRAME)){
38379cc780fSMatthias Ringwald             int16_t sample_buffer[MSBC_MAX_NUM_SAMPLES];
38494381a69SMatthias Ringwald             uint32_t bytes_read;
38594381a69SMatthias Ringwald             btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read);
38694381a69SMatthias Ringwald             hfp_msbc_encode_audio_frame(sample_buffer);
38794381a69SMatthias Ringwald             num_audio_frames++;
38894381a69SMatthias Ringwald         }
389b89b876fSMatthias Ringwald         btstack_assert(hfp_msbc_num_bytes_in_stream() >= sco_payload_length);
39094381a69SMatthias Ringwald     }
391b89b876fSMatthias Ringwald 
392b89b876fSMatthias Ringwald     // get data from encoder, fill with 0 if not enough
39394381a69SMatthias Ringwald     if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){
39494381a69SMatthias Ringwald         // just send '0's
39594381a69SMatthias Ringwald         memset(payload_buffer, 0, sco_payload_length);
39694381a69SMatthias Ringwald         audio_input_paused = 1;
39794381a69SMatthias Ringwald     } else {
39894381a69SMatthias Ringwald         hfp_msbc_read_from_stream(payload_buffer, sco_payload_length);
39994381a69SMatthias Ringwald     }
40094381a69SMatthias Ringwald }
40194381a69SMatthias Ringwald 
402bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){
403bf958e42SMatthias Ringwald     printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.\n", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr);
404bf958e42SMatthias Ringwald }
405bf958e42SMatthias Ringwald 
406bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = {
407bf958e42SMatthias Ringwald         .init         = &sco_demo_msbc_init,
408bf958e42SMatthias Ringwald         .receive      = &sco_demo_msbc_receive,
409bf958e42SMatthias Ringwald         .fill_payload = &sco_demo_msbc_fill_payload,
41079cc780fSMatthias Ringwald         .close        = &sco_demo_msbc_close,
41179cc780fSMatthias Ringwald         .sample_rate = SAMPLE_RATE_16KHZ
412bf958e42SMatthias Ringwald };
413bf958e42SMatthias Ringwald 
41494381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */
41594381a69SMatthias Ringwald 
41694381a69SMatthias Ringwald void sco_demo_init(void){
41794381a69SMatthias Ringwald 
41894381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS
41994381a69SMatthias Ringwald     printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n");
42094381a69SMatthias Ringwald     gap_secure_connections_enable(false);
42194381a69SMatthias Ringwald #endif
42294381a69SMatthias Ringwald 
42394381a69SMatthias Ringwald 	// status
42494381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
42594381a69SMatthias Ringwald     printf("SCO Demo: Sending and receiving audio via btstack_audio.\n");
42694381a69SMatthias Ringwald #endif
42794381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
42894381a69SMatthias Ringwald     if (btstack_audio_sink_get_instance()){
42994381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n");
43094381a69SMatthias Ringwald     } else {
43194381a69SMatthias Ringwald         printf("SCO Demo: Sending sine wave, hexdump received data.\n");
43294381a69SMatthias Ringwald     }
43394381a69SMatthias Ringwald #endif
43494381a69SMatthias Ringwald 
43594381a69SMatthias Ringwald     // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode)
43694381a69SMatthias Ringwald     hci_set_sco_voice_setting(0x60);    // linear, unsigned, 16-bit, CVSD
43794381a69SMatthias Ringwald }
43894381a69SMatthias Ringwald 
439bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){
44094381a69SMatthias Ringwald     switch (negotiated_codec){
44194381a69SMatthias Ringwald         case HFP_CODEC_CVSD:
442bf958e42SMatthias Ringwald             codec_current = &codec_cvsd;
44394381a69SMatthias Ringwald             break;
44494381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
44594381a69SMatthias Ringwald         case HFP_CODEC_MSBC:
446bf958e42SMatthias Ringwald             codec_current = &codec_msbc;
44794381a69SMatthias Ringwald             break;
44894381a69SMatthias Ringwald #endif
44994381a69SMatthias Ringwald         default:
45094381a69SMatthias Ringwald             btstack_assert(false);
45194381a69SMatthias Ringwald             break;
45294381a69SMatthias Ringwald     }
453bf958e42SMatthias Ringwald 
454bf958e42SMatthias Ringwald     codec_current->init();
455*9ad691b0SMatthias Ringwald 
456*9ad691b0SMatthias Ringwald     audio_initialize(codec_current->sample_rate);
457*9ad691b0SMatthias Ringwald 
458*9ad691b0SMatthias Ringwald     audio_prebuffer_bytes = SCO_PREBUFFER_MS * (codec_current->sample_rate/1000) * BYTES_PER_FRAME;
459*9ad691b0SMatthias Ringwald 
460*9ad691b0SMatthias Ringwald #ifdef SCO_WAV_FILENAME
461*9ad691b0SMatthias Ringwald     num_samples_to_write = codec_current->sample_rate * SCO_WAV_DURATION_IN_SECONDS;
462*9ad691b0SMatthias Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, codec_current->sample_rate);
463*9ad691b0SMatthias Ringwald #endif
464*9ad691b0SMatthias Ringwald 
465*9ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
466*9ad691b0SMatthias Ringwald     sine_wave_steps_per_sample = SINE_WAVE_SAMPLE_RATE / codec_current->sample_rate;
467*9ad691b0SMatthias Ringwald     sco_demo_audio_generator = &sco_demo_sine_wave_host_endian;
468*9ad691b0SMatthias Ringwald #endif
46994381a69SMatthias Ringwald }
47094381a69SMatthias Ringwald 
47194381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
47294381a69SMatthias Ringwald     static uint32_t packets = 0;
47394381a69SMatthias Ringwald     static uint32_t crc_errors = 0;
47494381a69SMatthias Ringwald     static uint32_t data_received = 0;
47594381a69SMatthias Ringwald     static uint32_t byte_errors = 0;
47694381a69SMatthias Ringwald 
47794381a69SMatthias Ringwald     count_received++;
47894381a69SMatthias Ringwald 
47994381a69SMatthias Ringwald     data_received += size - 3;
48094381a69SMatthias Ringwald     packets++;
48194381a69SMatthias Ringwald     if (data_received > 100000){
48294381a69SMatthias 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);
48394381a69SMatthias Ringwald         crc_errors = 0;
48494381a69SMatthias Ringwald         byte_errors = 0;
48594381a69SMatthias Ringwald         data_received = 0;
48694381a69SMatthias Ringwald         packets = 0;
48794381a69SMatthias Ringwald     }
48894381a69SMatthias Ringwald 
489bf958e42SMatthias Ringwald     codec_current->receive(packet, size);
49094381a69SMatthias Ringwald }
49194381a69SMatthias Ringwald 
49294381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
49394381a69SMatthias Ringwald 
49494381a69SMatthias Ringwald     if (sco_handle == HCI_CON_HANDLE_INVALID) return;
49594381a69SMatthias Ringwald 
49694381a69SMatthias Ringwald     int sco_packet_length = hci_get_sco_packet_length();
49794381a69SMatthias Ringwald     int sco_payload_length = sco_packet_length - 3;
49894381a69SMatthias Ringwald 
49994381a69SMatthias Ringwald     hci_reserve_packet_buffer();
50094381a69SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
50194381a69SMatthias Ringwald 
502bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR
503bf958e42SMatthias Ringwald     #define REFILL_SAMPLES 16
504bf958e42SMatthias Ringwald     // re-fill audio buffer
505bf958e42SMatthias Ringwald     uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2;
506bf958e42SMatthias Ringwald     while (samples_free > 0){
507bf958e42SMatthias Ringwald         int16_t samples_buffer[REFILL_SAMPLES];
508bf958e42SMatthias Ringwald         uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES);
509bf958e42SMatthias Ringwald         (*sco_demo_audio_generator)(samples_to_add, samples_buffer);
510bf958e42SMatthias Ringwald         btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2);
511bf958e42SMatthias Ringwald         samples_free -= samples_to_add;
51294381a69SMatthias Ringwald     }
513bf958e42SMatthias Ringwald #endif
514bf958e42SMatthias Ringwald 
515bf958e42SMatthias Ringwald     // resume if pre-buffer is filled
516bf958e42SMatthias Ringwald     if (audio_input_paused){
517bf958e42SMatthias Ringwald         if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){
518bf958e42SMatthias Ringwald             // resume sending
519bf958e42SMatthias Ringwald             audio_input_paused = 0;
520bf958e42SMatthias Ringwald         }
521bf958e42SMatthias Ringwald     }
522bf958e42SMatthias Ringwald 
523bf958e42SMatthias Ringwald     // fill payload by codec
524bf958e42SMatthias Ringwald     codec_current->fill_payload(&sco_packet[3], sco_payload_length);
5252b89dbfcSMatthias Ringwald 
526c4e666bcSMatthias Ringwald     // set handle + flags
527c4e666bcSMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
528c4e666bcSMatthias Ringwald     // set len
529c4e666bcSMatthias Ringwald     sco_packet[2] = sco_payload_length;
530c4e666bcSMatthias Ringwald     // finally send packet
531f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
532f7c85330SMatthias Ringwald 
533f7c85330SMatthias Ringwald     // request another send event
534f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
535f7c85330SMatthias Ringwald 
5364a96141eSMatthias Ringwald     count_sent++;
53794381a69SMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) {
53894381a69SMatthias Ringwald         printf("SCO: sent %u, received %u\n", count_sent, count_received);
53994381a69SMatthias Ringwald     }
540f7c85330SMatthias Ringwald }
541f7c85330SMatthias Ringwald 
54294381a69SMatthias Ringwald void sco_demo_close(void){
54394381a69SMatthias Ringwald     printf("SCO demo close\n");
5441a919128SMatthias Ringwald 
54594381a69SMatthias Ringwald     printf("SCO demo statistics: ");
546bf958e42SMatthias Ringwald     codec_current->close();
547bf958e42SMatthias Ringwald     codec_current = NULL;
54894381a69SMatthias Ringwald 
54994381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME)
55094381a69SMatthias Ringwald     wav_writer_close();
5518b29cfc6SMatthias Ringwald #endif
5528b29cfc6SMatthias Ringwald 
55394381a69SMatthias Ringwald     audio_terminate();
554f7c85330SMatthias Ringwald }
555