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 145681cb550SMatthias Ringwald static btstack_sbc_decoder_state_t msbc_decoder_state; 1461bbecc2bSMatthias Ringwald #endif 1471bbecc2bSMatthias Ringwald 148681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 149681cb550SMatthias Ringwald static const btstack_lc3_decoder_t * lc3_decoder; 150681cb550SMatthias Ringwald static btstack_lc3_decoder_google_t lc3_decoder_context; 151681cb550SMatthias Ringwald static hfp_h2_sync_t hfp_h2_sync; 152681cb550SMatthias 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; 178681cb550SMatthias Ringwald #define SINE_WAVE_SAMPLE_RATE SAMPLE_RATE_32KHZ 17994381a69SMatthias Ringwald 180681cb550SMatthias Ringwald // input signal: pre-computed int16 sine wave, 32000 Hz at 266 Hz 181681cb550SMatthias Ringwald static const int16_t sine_int16[] = { 182681cb550SMatthias Ringwald 0, 1715, 3425, 5126, 6813, 8481, 10126, 11743, 13328, 14876, 183681cb550SMatthias Ringwald 16383, 17846, 19260, 20621, 21925, 23170, 24351, 25465, 26509, 27481, 184681cb550SMatthias Ringwald 28377, 29196, 29934, 30591, 31163, 31650, 32051, 32364, 32587, 32722, 185681cb550SMatthias Ringwald 32767, 32722, 32587, 32364, 32051, 31650, 31163, 30591, 29934, 29196, 186681cb550SMatthias Ringwald 28377, 27481, 26509, 25465, 24351, 23170, 21925, 20621, 19260, 17846, 187681cb550SMatthias Ringwald 16383, 14876, 13328, 11743, 10126, 8481, 6813, 5126, 3425, 1715, 188681cb550SMatthias Ringwald 0, -1715, -3425, -5126, -6813, -8481, -10126, -11743, -13328, -14876, 189681cb550SMatthias Ringwald -16384, -17846, -19260, -20621, -21925, -23170, -24351, -25465, -26509, -27481, 190681cb550SMatthias Ringwald -28377, -29196, -29934, -30591, -31163, -31650, -32051, -32364, -32587, -32722, 191681cb550SMatthias Ringwald -32767, -32722, -32587, -32364, -32051, -31650, -31163, -30591, -29934, -29196, 192681cb550SMatthias Ringwald -28377, -27481, -26509, -25465, -24351, -23170, -21925, -20621, -19260, -17846, 193681cb550SMatthias 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++){ 199681cb550SMatthias Ringwald data[i] = sine_int16[sine_wave_phase]; 2009ad691b0SMatthias Ringwald sine_wave_phase += sine_wave_steps_per_sample; 201681cb550SMatthias 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(); 273*e0c8f71bSMatthias Ringwald if (audio_sink != NULL){ 27494381a69SMatthias Ringwald audio_sink->init(1, sample_rate, &audio_playback_callback); 275d365bb51SMatthias Ringwald audio_sink->start_stream(); 276379c5f5fSMatthias Ringwald 277379c5f5fSMatthias Ringwald audio_output_paused = 1; 278*e0c8f71bSMatthias Ringwald } 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(); 290*e0c8f71bSMatthias Ringwald if (audio_source != NULL){ 29194381a69SMatthias Ringwald audio_source->init(1, sample_rate, &audio_recording_callback); 292d365bb51SMatthias Ringwald audio_source->start_stream(); 293*e0c8f71bSMatthias Ringwald } 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 398681cb550SMatthias Ringwald // encode using hfp_codec 399681cb550SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH) || defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH) 400d4872f4eSMatthias Ringwald static void sco_demo_codec_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){ 401681cb550SMatthias Ringwald if (!audio_input_paused){ 402681cb550SMatthias Ringwald int num_samples = hfp_codec_num_audio_samples_per_frame(&hfp_codec); 403681cb550SMatthias Ringwald btstack_assert(num_samples <= SAMPLES_PER_FRAME_MAX); 404681cb550SMatthias Ringwald uint16_t samples_available = btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) / BYTES_PER_FRAME; 405681cb550SMatthias Ringwald if (hfp_codec_can_encode_audio_frame_now(&hfp_codec) && samples_available >= num_samples){ 406681cb550SMatthias Ringwald int16_t sample_buffer[SAMPLES_PER_FRAME_MAX]; 407681cb550SMatthias Ringwald uint32_t bytes_read; 408681cb550SMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 409681cb550SMatthias Ringwald hfp_codec_encode_audio_frame(&hfp_codec, sample_buffer); 410681cb550SMatthias Ringwald num_audio_frames++; 411681cb550SMatthias Ringwald } 412681cb550SMatthias Ringwald } 413681cb550SMatthias Ringwald // get data from encoder, fill with 0 if not enough 414681cb550SMatthias Ringwald if (audio_input_paused || hfp_codec_num_bytes_available(&hfp_codec) < sco_payload_length){ 415681cb550SMatthias Ringwald // just send '0's 416681cb550SMatthias Ringwald memset(payload_buffer, 0, sco_payload_length); 417681cb550SMatthias Ringwald audio_input_paused = 1; 418681cb550SMatthias Ringwald } else { 419681cb550SMatthias Ringwald hfp_codec_read_from_stream(&hfp_codec, payload_buffer, sco_payload_length); 420681cb550SMatthias Ringwald } 421681cb550SMatthias Ringwald } 422681cb550SMatthias Ringwald #endif 423681cb550SMatthias 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"); 451681cb550SMatthias 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){ 456681cb550SMatthias 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){ 460681cb550SMatthias 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, 466681cb550SMatthias 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 473681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 474681cb550SMatthias Ringwald 475681cb550SMatthias Ringwald #define LC3_SWB_SAMPLES_PER_FRAME 240 476681cb550SMatthias Ringwald #define LC3_SWB_OCTETS_PER_FRAME 58 477681cb550SMatthias Ringwald 478681cb550SMatthias Ringwald static bool sco_demo_lc3swb_frame_callback(bool bad_frame, const uint8_t * frame_data, uint16_t frame_len){ 479681cb550SMatthias Ringwald 480681cb550SMatthias Ringwald // skip H2 header for good frames 481681cb550SMatthias Ringwald if (bad_frame == false){ 482681cb550SMatthias Ringwald btstack_assert(frame_data != NULL); 483681cb550SMatthias Ringwald frame_data += 2; 484681cb550SMatthias Ringwald } 485681cb550SMatthias Ringwald 486681cb550SMatthias Ringwald uint8_t tmp_BEC_detect = 0; 487681cb550SMatthias Ringwald uint8_t BFI = bad_frame ? 1 : 0; 488681cb550SMatthias Ringwald int16_t samples[LC3_SWB_SAMPLES_PER_FRAME]; 489681cb550SMatthias Ringwald (void) lc3_decoder->decode_signed_16(&lc3_decoder_context, frame_data, BFI, 490681cb550SMatthias Ringwald samples, 1, &tmp_BEC_detect); 491681cb550SMatthias Ringwald 492681cb550SMatthias Ringwald // samples in callback in host endianess, ready for playback 493681cb550SMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)samples, LC3_SWB_SAMPLES_PER_FRAME*2); 494681cb550SMatthias Ringwald 495681cb550SMatthias Ringwald #ifdef SCO_WAV_FILENAME 496681cb550SMatthias Ringwald if (num_samples_to_write > 0){ 497681cb550SMatthias Ringwald uint16_t num_samples = btstack_min(LC3_SWB_SAMPLES_PER_FRAME, num_samples_to_write); 498681cb550SMatthias Ringwald num_samples_to_write -= num_samples; 499681cb550SMatthias Ringwald wav_writer_write_int16(num_samples, samples); 500681cb550SMatthias Ringwald if (num_samples_to_write == 0){ 501681cb550SMatthias Ringwald wav_writer_close(); 502681cb550SMatthias Ringwald } 503681cb550SMatthias Ringwald } 504681cb550SMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 505681cb550SMatthias Ringwald 506681cb550SMatthias Ringwald // frame is good, if it isn't a bad frame and we didn't detect other errors 507681cb550SMatthias Ringwald return (bad_frame == false) && (tmp_BEC_detect == 0); 508681cb550SMatthias Ringwald } 509681cb550SMatthias Ringwald 510681cb550SMatthias Ringwald static void sco_demo_lc3swb_init(void){ 511681cb550SMatthias Ringwald 512681cb550SMatthias Ringwald printf("SCO Demo: Init LC3-SWB\n"); 513681cb550SMatthias Ringwald 514681cb550SMatthias Ringwald hfp_codec_init(&hfp_codec, HFP_CODEC_LC3_SWB); 515681cb550SMatthias Ringwald 516681cb550SMatthias Ringwald // init lc3 decoder 517681cb550SMatthias Ringwald lc3_decoder = btstack_lc3_decoder_google_init_instance(&lc3_decoder_context); 518681cb550SMatthias Ringwald lc3_decoder->configure(&lc3_decoder_context, SAMPLE_RATE_32KHZ, BTSTACK_LC3_FRAME_DURATION_7500US, LC3_SWB_OCTETS_PER_FRAME); 519681cb550SMatthias Ringwald 520681cb550SMatthias Ringwald // init HPF H2 framing 521681cb550SMatthias Ringwald hfp_h2_sync_init(&hfp_h2_sync, &sco_demo_lc3swb_frame_callback); 522681cb550SMatthias Ringwald } 523681cb550SMatthias Ringwald 524681cb550SMatthias Ringwald static void sco_demo_lc3swb_receive(const uint8_t * packet, uint16_t size){ 525681cb550SMatthias Ringwald uint8_t packet_status = (packet[1] >> 4) & 3; 526681cb550SMatthias Ringwald bool bad_frame = packet_status != 0; 527681cb550SMatthias Ringwald hfp_h2_sync_process(&hfp_h2_sync, bad_frame, &packet[3], size-3); 528681cb550SMatthias Ringwald } 529681cb550SMatthias Ringwald 530681cb550SMatthias Ringwald static void sco_demo_lc3swb_close(void){ 531681cb550SMatthias Ringwald // TODO: report 532681cb550SMatthias Ringwald } 533681cb550SMatthias Ringwald 534681cb550SMatthias Ringwald static const codec_support_t codec_lc3swb = { 535681cb550SMatthias Ringwald .init = &sco_demo_lc3swb_init, 536681cb550SMatthias Ringwald .receive = &sco_demo_lc3swb_receive, 537681cb550SMatthias Ringwald .fill_payload = &sco_demo_codec_fill_payload, 538681cb550SMatthias Ringwald .close = &sco_demo_lc3swb_close, 539681cb550SMatthias Ringwald .sample_rate = SAMPLE_RATE_32KHZ 540681cb550SMatthias Ringwald }; 541681cb550SMatthias Ringwald #endif 542681cb550SMatthias 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 550681cb550SMatthias Ringwald // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode) 551681cb550SMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 552681cb550SMatthias 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 561681cb550SMatthias 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 578681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 579681cb550SMatthias Ringwald case HFP_CODEC_LC3_SWB: 580681cb550SMatthias Ringwald codec_current = &codec_lc3swb; 581681cb550SMatthias Ringwald break; 582681cb550SMatthias 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