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 84*b150a479SMatthias Ringwald #define SAMPLE_RATE_8KHZ 8000 85*b150a479SMatthias Ringwald #define SAMPLE_RATE_16KHZ 16000 86379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME 2 87f7c85330SMatthias Ringwald 88*b150a479SMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency 89*b150a479SMatthias Ringwald #define SCO_PREBUFFER_MS 50 90*b150a479SMatthias Ringwald #define PREBUFFER_BYTES_8KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_8KHZ/1000 * BYTES_PER_FRAME) 91*b150a479SMatthias Ringwald #define PREBUFFER_BYTES_16KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_16KHZ/1000 * BYTES_PER_FRAME) 92f7c85330SMatthias Ringwald 932b89dbfcSMatthias Ringwald // output 94d861f4bfSMatthias Ringwald static int audio_output_paused = 0; 95*b150a479SMatthias Ringwald static uint8_t audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_16KHZ]; 96379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer; 972b89dbfcSMatthias Ringwald 982b89dbfcSMatthias Ringwald // input 992b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 100379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT 1013cf06407SMatthias Ringwald #else 1023cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR 1033cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data); 1046fb1424bSMatthias Ringwald #endif 105379c5f5fSMatthias Ringwald static int audio_input_paused = 0; 106*b150a479SMatthias Ringwald static uint16_t audio_input_prebuffer_bytes; 107*b150a479SMatthias Ringwald static uint8_t audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_16KHZ]; 108379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer; 109f7c85330SMatthias Ringwald 110fcb08cdbSMilanka Ringwald static int count_sent = 0; 111fcb08cdbSMilanka Ringwald static int count_received = 0; 112c4e666bcSMatthias Ringwald static int negotiated_codec = -1; 113c4e666bcSMatthias Ringwald 1141bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 115379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state; 1161bbecc2bSMatthias Ringwald #endif 1171bbecc2bSMatthias Ringwald 118379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state; 119379c5f5fSMatthias Ringwald 120379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8) 121fcb08cdbSMilanka Ringwald 1222b89dbfcSMatthias Ringwald int num_samples_to_write; 1232b89dbfcSMatthias Ringwald int num_audio_frames; 1242b89dbfcSMatthias Ringwald 1253cf06407SMatthias Ringwald // sine generator 126d6a06398SMatthias Ringwald 1273cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 1283cf06407SMatthias Ringwald static unsigned int phase; 12994381a69SMatthias Ringwald 1307556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz 131c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 1327556ab9fSMatthias Ringwald 0, 3135, 6237, 9270, 12202, 14999, 17633, 20073, 22294, 24270, 1337556ab9fSMatthias Ringwald 25980, 27406, 28531, 29344, 29835, 30000, 29835, 29344, 28531, 27406, 1347556ab9fSMatthias Ringwald 25980, 24270, 22294, 20073, 17633, 14999, 12202, 9270, 6237, 3135, 1357556ab9fSMatthias Ringwald 0, -3135, -6237, -9270, -12202, -14999, -17633, -20073, -22294, -24270, 1367556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406, 1377556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202, -9270, -6237, -3135, 13835fd3fb9SMatthias Ringwald }; 13935fd3fb9SMatthias Ringwald 14059c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian 1413cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_host_endian(uint16_t num_samples, int16_t * data){ 142249d94cfSMatthias Ringwald unsigned int i; 14359c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 1446fb1424bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase]; 14559c97ae1SMatthias Ringwald // ony use every second sample from 16khz table to get 8khz 14659c97ae1SMatthias Ringwald phase += 2; 147c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 14835fd3fb9SMatthias Ringwald phase = 0; 14935fd3fb9SMatthias Ringwald } 15035fd3fb9SMatthias Ringwald } 15135fd3fb9SMatthias Ringwald } 15235fd3fb9SMatthias Ringwald 1531bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess 1541bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 1553cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(uint16_t num_samples, int16_t * data){ 156249d94cfSMatthias Ringwald unsigned int i; 1571bbecc2bSMatthias Ringwald for (i=0; i < num_samples; i++){ 1581bbecc2bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase++]; 1591bbecc2bSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 1601bbecc2bSMatthias Ringwald phase = 0; 1611bbecc2bSMatthias Ringwald } 1621bbecc2bSMatthias Ringwald } 1631bbecc2bSMatthias Ringwald } 1642b89dbfcSMatthias Ringwald #endif 1651bbecc2bSMatthias Ringwald #endif 166dbb41bfeSMilanka Ringwald 16794381a69SMatthias Ringwald // Audio Playback / Recording 168d861f4bfSMatthias Ringwald 16994381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){ 1702b89dbfcSMatthias Ringwald 171be030f50SMilanka Ringwald uint32_t prebuffer_bytes; 172c4e666bcSMatthias Ringwald switch (negotiated_codec){ 173c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 174*b150a479SMatthias Ringwald prebuffer_bytes = PREBUFFER_BYTES_16KHZ; 175c4e666bcSMatthias Ringwald break; 176c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 177c4e666bcSMatthias Ringwald default: 178*b150a479SMatthias Ringwald prebuffer_bytes = PREBUFFER_BYTES_8KHZ; 179c4e666bcSMatthias Ringwald break; 180dbb41bfeSMilanka Ringwald } 181dbb41bfeSMilanka Ringwald 182c4e666bcSMatthias Ringwald // fill with silence while paused 183379c5f5fSMatthias Ringwald if (audio_output_paused){ 184379c5f5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){ 185f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 186379c5f5fSMatthias Ringwald return; 187dbb41bfeSMilanka Ringwald } else { 188c4e666bcSMatthias Ringwald // resume playback 189379c5f5fSMatthias Ringwald audio_output_paused = 0; 190dbb41bfeSMilanka Ringwald } 191c4e666bcSMatthias Ringwald } 192c4e666bcSMatthias Ringwald 193c4e666bcSMatthias Ringwald // get data from ringbuffer 194c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 195f55ac442SMatthias Ringwald btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 196f55ac442SMatthias Ringwald num_samples -= bytes_read / BYTES_PER_FRAME; 197f55ac442SMatthias Ringwald buffer += bytes_read / BYTES_PER_FRAME; 198c4e666bcSMatthias Ringwald 199c4e666bcSMatthias Ringwald // fill with 0 if not enough 200f55ac442SMatthias Ringwald if (num_samples){ 201f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 202379c5f5fSMatthias Ringwald audio_output_paused = 1; 203c4e666bcSMatthias Ringwald } 204379c5f5fSMatthias Ringwald } 2058b29cfc6SMatthias Ringwald 206379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 20794381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){ 208379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2); 209c4e666bcSMatthias Ringwald } 210379c5f5fSMatthias Ringwald #endif 211c4e666bcSMatthias Ringwald 212c4e666bcSMatthias Ringwald // return 1 if ok 213379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){ 214c4e666bcSMatthias Ringwald 215d365bb51SMatthias Ringwald // -- output -- // 216d365bb51SMatthias Ringwald 217379c5f5fSMatthias Ringwald // init buffers 218379c5f5fSMatthias Ringwald memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage)); 219379c5f5fSMatthias Ringwald btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage)); 2202b89dbfcSMatthias Ringwald 221d365bb51SMatthias Ringwald // config and setup audio playback 222d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 223d365bb51SMatthias Ringwald if (!audio_sink) return 0; 2242b89dbfcSMatthias Ringwald 22594381a69SMatthias Ringwald audio_sink->init(1, sample_rate, &audio_playback_callback); 226d365bb51SMatthias Ringwald audio_sink->start_stream(); 227379c5f5fSMatthias Ringwald 228379c5f5fSMatthias Ringwald audio_output_paused = 1; 229d365bb51SMatthias Ringwald 230d365bb51SMatthias Ringwald // -- input -- // 231d365bb51SMatthias Ringwald 232d365bb51SMatthias Ringwald // init buffers 233d365bb51SMatthias Ringwald memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage)); 234d365bb51SMatthias Ringwald btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage)); 2356fb1424bSMatthias Ringwald audio_input_paused = 1; 236d365bb51SMatthias Ringwald 2376fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT 238d365bb51SMatthias Ringwald // config and setup audio recording 239d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance(); 240d365bb51SMatthias Ringwald if (!audio_source) return 0; 241d365bb51SMatthias Ringwald 24294381a69SMatthias Ringwald audio_source->init(1, sample_rate, &audio_recording_callback); 243d365bb51SMatthias Ringwald audio_source->start_stream(); 2442b89dbfcSMatthias Ringwald #endif 2452b89dbfcSMatthias Ringwald 246c4e666bcSMatthias Ringwald return 1; 247c4e666bcSMatthias Ringwald } 2482b89dbfcSMatthias Ringwald 249379c5f5fSMatthias Ringwald static void audio_terminate(void){ 250d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 251d365bb51SMatthias Ringwald if (!audio_sink) return; 252d365bb51SMatthias Ringwald audio_sink->close(); 253d365bb51SMatthias Ringwald 254d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT 255d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance(); 256d365bb51SMatthias Ringwald if (!audio_source) return; 257d365bb51SMatthias Ringwald audio_source->close(); 258d365bb51SMatthias Ringwald #endif 2592b89dbfcSMatthias Ringwald } 260c4e666bcSMatthias Ringwald 261d861f4bfSMatthias Ringwald 26294381a69SMatthias Ringwald // CVSD - 8 kHz 263fcb08cdbSMilanka Ringwald 264fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){ 265c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 266c4e666bcSMatthias Ringwald 267fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 268c4e666bcSMatthias Ringwald 269*b150a479SMatthias Ringwald audio_input_prebuffer_bytes = PREBUFFER_BYTES_8KHZ; 270*b150a479SMatthias Ringwald 2712c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 272*b150a479SMatthias Ringwald num_samples_to_write = SAMPLE_RATE_8KHZ * SCO_WAV_DURATION_IN_SECONDS; 273*b150a479SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, SAMPLE_RATE_8KHZ); 2742c7ae6e1SMatthias Ringwald #endif 275dbb41bfeSMilanka Ringwald 276*b150a479SMatthias Ringwald audio_initialize(SAMPLE_RATE_8KHZ); 277fbc7c9f2SMilanka Ringwald } 278fbc7c9f2SMilanka Ringwald 279fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 2802c7ae6e1SMatthias Ringwald 2815303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 2821f8694ccSMatthias Ringwald 2831f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 2841f8694ccSMatthias Ringwald printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); 2851f8694ccSMatthias Ringwald return; 2861f8694ccSMatthias Ringwald } 2872c7ae6e1SMatthias Ringwald 288c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 289379c5f5fSMatthias Ringwald const int num_samples = audio_bytes_read / BYTES_PER_FRAME; 2905303ddeeSMatthias Ringwald 2915303ddeeSMatthias Ringwald // convert into host endian 2925303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 2935303ddeeSMatthias Ringwald int i; 2945303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 2955303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 2965303ddeeSMatthias Ringwald } 2975303ddeeSMatthias Ringwald 2985f4f94c7SMatthias Ringwald // treat packet as bad frame if controller does not report 'all good' 2995f4f94c7SMatthias Ringwald bool bad_frame = (packet[1] & 0x30) != 0; 3005f4f94c7SMatthias Ringwald 3015f4f94c7SMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out); 3025303ddeeSMatthias Ringwald 3032c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3042c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 3052c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 3062c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 3072c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 3082c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 3092c7ae6e1SMatthias Ringwald wav_writer_close(); 3102c7ae6e1SMatthias Ringwald } 3112c7ae6e1SMatthias Ringwald #endif 3122c7ae6e1SMatthias Ringwald 313379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 314fcb08cdbSMilanka Ringwald } 315fcb08cdbSMilanka Ringwald 31694381a69SMatthias Ringwald void sco_demo_fill_payload_CVSD(uint8_t * payload_buffer, uint16_t sco_payload_length){ 3172c7ae6e1SMatthias Ringwald 3183cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 3196fb1424bSMatthias Ringwald #define REFILL_SAMPLES 16 3206fb1424bSMatthias Ringwald // re-fill with sine 3216fb1424bSMatthias Ringwald uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2; 3226fb1424bSMatthias Ringwald while (samples_free > 0){ 3236fb1424bSMatthias Ringwald int16_t samples_buffer[REFILL_SAMPLES]; 3246fb1424bSMatthias Ringwald uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES); 3253cf06407SMatthias Ringwald (*sco_demo_audio_generator)(samples_to_add, samples_buffer); 3266fb1424bSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2); 3276fb1424bSMatthias Ringwald samples_free -= samples_to_add; 3286fb1424bSMatthias Ringwald } 3291a919128SMatthias Ringwald #endif 3302b89dbfcSMatthias Ringwald 3316fb1424bSMatthias Ringwald // resume if pre-buffer is filled 332379c5f5fSMatthias Ringwald if (audio_input_paused){ 333*b150a479SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_input_prebuffer_bytes){ 3342b89dbfcSMatthias Ringwald // resume sending 335379c5f5fSMatthias Ringwald audio_input_paused = 0; 3362b89dbfcSMatthias Ringwald } 3372b89dbfcSMatthias Ringwald } 3382b89dbfcSMatthias Ringwald 3396fb1424bSMatthias Ringwald uint16_t bytes_to_copy = sco_payload_length; 3406fb1424bSMatthias Ringwald 3412b89dbfcSMatthias Ringwald // get data from ringbuffer 3422b89dbfcSMatthias Ringwald uint16_t pos = 0; 343379c5f5fSMatthias Ringwald if (!audio_input_paused){ 3446fb1424bSMatthias Ringwald uint16_t samples_to_copy = sco_payload_length / 2; 3452b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 3466fb1424bSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read); 3478fd6902dSMatthias Ringwald // flip 16 on big endian systems 3488fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 3498fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 3506fb1424bSMatthias Ringwald uint16_t i; 3516fb1424bSMatthias Ringwald for (i=0;i<samples_to_copy/2;i+=2){ 3526fb1424bSMatthias Ringwald uint8_t tmp = payload_buffer[i*2]; 3536fb1424bSMatthias Ringwald payload_buffer[i*2] = payload_buffer[i*2+1]; 3546fb1424bSMatthias Ringwald payload_buffer[i*2+1] = tmp; 3558fd6902dSMatthias Ringwald } 3568fd6902dSMatthias Ringwald } 3572b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 3582b89dbfcSMatthias Ringwald pos += bytes_read; 3592b89dbfcSMatthias Ringwald } 3602b89dbfcSMatthias Ringwald 3612b89dbfcSMatthias Ringwald // fill with 0 if not enough 3622b89dbfcSMatthias Ringwald if (bytes_to_copy){ 3636fb1424bSMatthias Ringwald memset(payload_buffer + pos, 0, bytes_to_copy); 364379c5f5fSMatthias Ringwald audio_input_paused = 1; 3652b89dbfcSMatthias Ringwald } 3662b89dbfcSMatthias Ringwald } 36794381a69SMatthias Ringwald 36894381a69SMatthias Ringwald // mSBC - 16 kHz 36994381a69SMatthias Ringwald 37094381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 37194381a69SMatthias Ringwald 37294381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 37394381a69SMatthias Ringwald UNUSED(context); 37494381a69SMatthias Ringwald UNUSED(sample_rate); 37594381a69SMatthias Ringwald UNUSED(data); 37694381a69SMatthias Ringwald UNUSED(num_samples); 37794381a69SMatthias Ringwald UNUSED(num_channels); 37894381a69SMatthias Ringwald 37994381a69SMatthias Ringwald // samples in callback in host endianess, ready for playback 38094381a69SMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 38194381a69SMatthias Ringwald 38294381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME 38394381a69SMatthias Ringwald if (!num_samples_to_write) return; 38494381a69SMatthias Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 38594381a69SMatthias Ringwald num_samples_to_write -= num_samples; 38694381a69SMatthias Ringwald wav_writer_write_int16(num_samples, data); 38794381a69SMatthias Ringwald if (num_samples_to_write == 0){ 38894381a69SMatthias Ringwald wav_writer_close(); 389f7c85330SMatthias Ringwald } 39094381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 3911a919128SMatthias Ringwald } 39294381a69SMatthias Ringwald 39394381a69SMatthias Ringwald static void sco_demo_init_mSBC(void){ 39494381a69SMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 39594381a69SMatthias Ringwald 39694381a69SMatthias Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 39794381a69SMatthias Ringwald hfp_msbc_init(); 39894381a69SMatthias Ringwald 399*b150a479SMatthias Ringwald audio_input_prebuffer_bytes = PREBUFFER_BYTES_16KHZ; 400*b150a479SMatthias Ringwald 40194381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME 402*b150a479SMatthias Ringwald num_samples_to_write = SAMPLE_RATE_16KHZ * SCO_WAV_DURATION_IN_SECONDS; 403*b150a479SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, SAMPLE_RATE_16KHZ); 404f7c85330SMatthias Ringwald #endif 405220eb563SMilanka Ringwald 406*b150a479SMatthias Ringwald audio_initialize(SAMPLE_RATE_16KHZ); 40794381a69SMatthias Ringwald } 40894381a69SMatthias Ringwald 40994381a69SMatthias Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 41094381a69SMatthias Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 41194381a69SMatthias Ringwald } 41294381a69SMatthias Ringwald 41394381a69SMatthias Ringwald void sco_demo_fill_payload_mSBC(uint8_t * payload_buffer, uint16_t sco_payload_length){ 41494381a69SMatthias Ringwald 4153cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 416b89b876fSMatthias Ringwald #define REFILL_SAMPLES 16 417b89b876fSMatthias Ringwald // re-fill with sine 418b89b876fSMatthias Ringwald uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2; 419b89b876fSMatthias Ringwald while (samples_free > 0){ 420b89b876fSMatthias Ringwald int16_t samples_buffer[REFILL_SAMPLES]; 421b89b876fSMatthias Ringwald uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES); 4223cf06407SMatthias Ringwald (*sco_demo_audio_generator)(samples_to_add, samples_buffer); 423b89b876fSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2); 424b89b876fSMatthias Ringwald samples_free -= samples_to_add; 42594381a69SMatthias Ringwald } 42694381a69SMatthias Ringwald #endif 42794381a69SMatthias Ringwald 428b89b876fSMatthias Ringwald // resume if pre-buffer is filled 42994381a69SMatthias Ringwald if (audio_input_paused){ 430*b150a479SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_input_prebuffer_bytes){ 43194381a69SMatthias Ringwald // resume sending 43294381a69SMatthias Ringwald audio_input_paused = 0; 43394381a69SMatthias Ringwald } 43494381a69SMatthias Ringwald } 43594381a69SMatthias Ringwald if (!audio_input_paused){ 43694381a69SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 437b89b876fSMatthias Ringwald btstack_assert(num_samples <= MAX_NUM_MSBC_SAMPLES); 43894381a69SMatthias 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)){ 43994381a69SMatthias Ringwald int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES]; 44094381a69SMatthias Ringwald uint32_t bytes_read; 44194381a69SMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 44294381a69SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 44394381a69SMatthias Ringwald num_audio_frames++; 44494381a69SMatthias Ringwald } 445b89b876fSMatthias Ringwald btstack_assert(hfp_msbc_num_bytes_in_stream() >= sco_payload_length); 44694381a69SMatthias Ringwald } 447b89b876fSMatthias Ringwald 448b89b876fSMatthias Ringwald // get data from encoder, fill with 0 if not enough 44994381a69SMatthias Ringwald if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 45094381a69SMatthias Ringwald // just send '0's 45194381a69SMatthias Ringwald memset(payload_buffer, 0, sco_payload_length); 45294381a69SMatthias Ringwald audio_input_paused = 1; 45394381a69SMatthias Ringwald } else { 45494381a69SMatthias Ringwald hfp_msbc_read_from_stream(payload_buffer, sco_payload_length); 45594381a69SMatthias Ringwald } 45694381a69SMatthias Ringwald } 45794381a69SMatthias Ringwald 45894381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 45994381a69SMatthias Ringwald 46094381a69SMatthias Ringwald void sco_demo_init(void){ 46194381a69SMatthias Ringwald 46294381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS 46394381a69SMatthias Ringwald printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n"); 46494381a69SMatthias Ringwald gap_secure_connections_enable(false); 46594381a69SMatthias Ringwald #endif 46694381a69SMatthias Ringwald 46794381a69SMatthias Ringwald // status 46894381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 46994381a69SMatthias Ringwald printf("SCO Demo: Sending and receiving audio via btstack_audio.\n"); 47094381a69SMatthias Ringwald #endif 47194381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 47294381a69SMatthias Ringwald if (btstack_audio_sink_get_instance()){ 47394381a69SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n"); 47494381a69SMatthias Ringwald } else { 47594381a69SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 47694381a69SMatthias Ringwald } 47794381a69SMatthias Ringwald #endif 47894381a69SMatthias Ringwald 47994381a69SMatthias Ringwald // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode) 48094381a69SMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 48194381a69SMatthias Ringwald } 48294381a69SMatthias Ringwald 48394381a69SMatthias Ringwald void sco_demo_set_codec(uint8_t codec){ 48494381a69SMatthias Ringwald if (negotiated_codec == codec) return; 48594381a69SMatthias Ringwald negotiated_codec = codec; 48694381a69SMatthias Ringwald 48794381a69SMatthias Ringwald switch (negotiated_codec){ 48894381a69SMatthias Ringwald case HFP_CODEC_CVSD: 4893cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 4903cf06407SMatthias Ringwald sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_8000_hz_host_endian; 4913cf06407SMatthias Ringwald #endif 49294381a69SMatthias Ringwald sco_demo_init_CVSD(); 49394381a69SMatthias Ringwald break; 49494381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 49594381a69SMatthias Ringwald case HFP_CODEC_MSBC: 4963cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 4973cf06407SMatthias Ringwald sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_16000_hz_host_endian; 4983cf06407SMatthias Ringwald #endif 49994381a69SMatthias Ringwald sco_demo_init_mSBC(); 50094381a69SMatthias Ringwald break; 50194381a69SMatthias Ringwald #endif 50294381a69SMatthias Ringwald default: 50394381a69SMatthias Ringwald btstack_assert(false); 50494381a69SMatthias Ringwald break; 50594381a69SMatthias Ringwald } 50694381a69SMatthias Ringwald } 50794381a69SMatthias Ringwald 50894381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 50994381a69SMatthias Ringwald static uint32_t packets = 0; 51094381a69SMatthias Ringwald static uint32_t crc_errors = 0; 51194381a69SMatthias Ringwald static uint32_t data_received = 0; 51294381a69SMatthias Ringwald static uint32_t byte_errors = 0; 51394381a69SMatthias Ringwald 51494381a69SMatthias Ringwald count_received++; 51594381a69SMatthias Ringwald 51694381a69SMatthias Ringwald data_received += size - 3; 51794381a69SMatthias Ringwald packets++; 51894381a69SMatthias Ringwald if (data_received > 100000){ 51994381a69SMatthias 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); 52094381a69SMatthias Ringwald crc_errors = 0; 52194381a69SMatthias Ringwald byte_errors = 0; 52294381a69SMatthias Ringwald data_received = 0; 52394381a69SMatthias Ringwald packets = 0; 52494381a69SMatthias Ringwald } 52594381a69SMatthias Ringwald 52694381a69SMatthias Ringwald switch (negotiated_codec){ 52794381a69SMatthias Ringwald case HFP_CODEC_CVSD: 52894381a69SMatthias Ringwald sco_demo_receive_CVSD(packet, size); 52994381a69SMatthias Ringwald break; 53094381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 53194381a69SMatthias Ringwald case HFP_CODEC_MSBC: 53294381a69SMatthias Ringwald sco_demo_receive_mSBC(packet, size); 53394381a69SMatthias Ringwald break; 53494381a69SMatthias Ringwald #endif 53594381a69SMatthias Ringwald default: 53694381a69SMatthias Ringwald btstack_assert(false); 53794381a69SMatthias Ringwald break; 53894381a69SMatthias Ringwald } 53994381a69SMatthias Ringwald } 54094381a69SMatthias Ringwald 54194381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 54294381a69SMatthias Ringwald 54394381a69SMatthias Ringwald if (sco_handle == HCI_CON_HANDLE_INVALID) return; 54494381a69SMatthias Ringwald 54594381a69SMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 54694381a69SMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 54794381a69SMatthias Ringwald 54894381a69SMatthias Ringwald hci_reserve_packet_buffer(); 54994381a69SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 55094381a69SMatthias Ringwald 55194381a69SMatthias Ringwald switch (negotiated_codec){ 55294381a69SMatthias Ringwald case HFP_CODEC_CVSD: 55394381a69SMatthias Ringwald sco_demo_fill_payload_CVSD(&sco_packet[3], sco_payload_length); 55494381a69SMatthias Ringwald break; 55594381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 55694381a69SMatthias Ringwald case HFP_CODEC_MSBC: 55794381a69SMatthias Ringwald sco_demo_fill_payload_mSBC(&sco_packet[3], sco_payload_length); 55894381a69SMatthias Ringwald break; 55994381a69SMatthias Ringwald #endif 56094381a69SMatthias Ringwald default: 56194381a69SMatthias Ringwald btstack_assert(false); 56294381a69SMatthias Ringwald break; 56394381a69SMatthias Ringwald } 5642b89dbfcSMatthias Ringwald 565c4e666bcSMatthias Ringwald // set handle + flags 566c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 567c4e666bcSMatthias Ringwald // set len 568c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 569c4e666bcSMatthias Ringwald // finally send packet 570f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 571f7c85330SMatthias Ringwald 572f7c85330SMatthias Ringwald // request another send event 573f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 574f7c85330SMatthias Ringwald 5754a96141eSMatthias Ringwald count_sent++; 57694381a69SMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) { 57794381a69SMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 57894381a69SMatthias Ringwald } 579f7c85330SMatthias Ringwald } 580f7c85330SMatthias Ringwald 58194381a69SMatthias Ringwald void sco_demo_close(void){ 58294381a69SMatthias Ringwald printf("SCO demo close\n"); 5831a919128SMatthias Ringwald 58494381a69SMatthias Ringwald printf("SCO demo statistics: "); 585c4e666bcSMatthias Ringwald switch (negotiated_codec){ 58694381a69SMatthias Ringwald case HFP_CODEC_CVSD: 58794381a69SMatthias 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); 58894381a69SMatthias Ringwald break; 5891bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 590c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 59194381a69SMatthias 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); 592c4e666bcSMatthias Ringwald break; 5931bbecc2bSMatthias Ringwald #endif 594c4e666bcSMatthias Ringwald default: 59594381a69SMatthias Ringwald btstack_assert(false); 596c4e666bcSMatthias Ringwald break; 5978b29cfc6SMatthias Ringwald } 59894381a69SMatthias Ringwald 59994381a69SMatthias Ringwald negotiated_codec = -1; 60094381a69SMatthias Ringwald 60194381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 60294381a69SMatthias Ringwald wav_writer_close(); 6038b29cfc6SMatthias Ringwald #endif 6048b29cfc6SMatthias Ringwald 60594381a69SMatthias Ringwald audio_terminate(); 606f7c85330SMatthias Ringwald } 607