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