1f7c85330SMatthias Ringwald /* 2f7c85330SMatthias Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3f7c85330SMatthias Ringwald * 4f7c85330SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5f7c85330SMatthias Ringwald * modification, are permitted provided that the following conditions 6f7c85330SMatthias Ringwald * are met: 7f7c85330SMatthias Ringwald * 8f7c85330SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9f7c85330SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10f7c85330SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11f7c85330SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12f7c85330SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13f7c85330SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14f7c85330SMatthias Ringwald * contributors may be used to endorse or promote products derived 15f7c85330SMatthias Ringwald * from this software without specific prior written permission. 16f7c85330SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17f7c85330SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18f7c85330SMatthias Ringwald * monetary gain. 19f7c85330SMatthias Ringwald * 20f7c85330SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21f7c85330SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22f7c85330SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25f7c85330SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26f7c85330SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27f7c85330SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28f7c85330SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29f7c85330SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30f7c85330SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31f7c85330SMatthias Ringwald * SUCH DAMAGE. 32f7c85330SMatthias Ringwald * 33f7c85330SMatthias Ringwald * Please inquire about commercial licensing options at 34f7c85330SMatthias Ringwald * [email protected] 35f7c85330SMatthias Ringwald * 36f7c85330SMatthias Ringwald */ 37ab2c6ae4SMatthias Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "sco_demo_util.c" 39f7c85330SMatthias Ringwald 40f7c85330SMatthias Ringwald /* 41f7c85330SMatthias Ringwald * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo 42f7c85330SMatthias Ringwald */ 43f7c85330SMatthias Ringwald 442ec72fbbSMilanka Ringwald #include <stdio.h> 452ec72fbbSMilanka Ringwald 46f7c85330SMatthias Ringwald #include "sco_demo_util.h" 47379c5f5fSMatthias Ringwald 48379c5f5fSMatthias Ringwald #include "btstack_audio.h" 49fcb08cdbSMilanka Ringwald #include "btstack_debug.h" 50379c5f5fSMatthias Ringwald #include "btstack_ring_buffer.h" 5135fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h" 52379c5f5fSMatthias Ringwald #include "classic/btstack_sbc.h" 5335fd3fb9SMatthias Ringwald #include "classic/hfp.h" 54379c5f5fSMatthias Ringwald #include "classic/hfp_msbc.h" 55fcb08cdbSMilanka Ringwald 56f89e874bSMatthias Ringwald #ifdef _MSC_VER 57f89e874bSMatthias Ringwald // ignore deprecated warning for fopen 58f89e874bSMatthias Ringwald #pragma warning(disable : 4996) 59f89e874bSMatthias Ringwald #endif 60f89e874bSMatthias Ringwald 6135fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 62fbc7c9f2SMilanka Ringwald #include "wav_util.h" 6335fd3fb9SMatthias Ringwald #endif 64fbc7c9f2SMilanka Ringwald 65c4e666bcSMatthias Ringwald // test modes 66f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE 0 6794381a69SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 1 68f7c85330SMatthias Ringwald 69f7c85330SMatthias Ringwald // SCO demo configuration 70d365bb51SMatthias Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_MICROPHONE 71c4e666bcSMatthias Ringwald 72c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console 73f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 74f7c85330SMatthias Ringwald 75f55ac442SMatthias Ringwald 76d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 772c7ae6e1SMatthias Ringwald // length and name of wav file on disk 78c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15 798b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 80859f2bc5SMatthias Ringwald #endif 81859f2bc5SMatthias Ringwald 82c4e666bcSMatthias Ringwald // constants 83c4e666bcSMatthias Ringwald #define NUM_CHANNELS 1 84b150a479SMatthias Ringwald #define SAMPLE_RATE_8KHZ 8000 85b150a479SMatthias Ringwald #define SAMPLE_RATE_16KHZ 16000 86379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME 2 87f7c85330SMatthias Ringwald 88b150a479SMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency 89b150a479SMatthias Ringwald #define SCO_PREBUFFER_MS 50 90b150a479SMatthias Ringwald #define PREBUFFER_BYTES_8KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_8KHZ/1000 * BYTES_PER_FRAME) 91b150a479SMatthias Ringwald #define PREBUFFER_BYTES_16KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_16KHZ/1000 * BYTES_PER_FRAME) 92f7c85330SMatthias Ringwald 939582ae64SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH) 949582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_16KHZ 959582ae64SMatthias Ringwald #else 969582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_8KHZ 979582ae64SMatthias Ringwald #endif 989582ae64SMatthias Ringwald 99bf958e42SMatthias Ringwald static uint16_t audio_prebuffer_bytes; 100bf958e42SMatthias Ringwald 1012b89dbfcSMatthias Ringwald // output 102d861f4bfSMatthias Ringwald static int audio_output_paused = 0; 1039582ae64SMatthias Ringwald static uint8_t audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX]; 104379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer; 1052b89dbfcSMatthias Ringwald 1062b89dbfcSMatthias Ringwald // input 1072b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 108379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT 1093cf06407SMatthias Ringwald #else 1103cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR 1113cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data); 1126fb1424bSMatthias Ringwald #endif 113379c5f5fSMatthias Ringwald static int audio_input_paused = 0; 1149582ae64SMatthias Ringwald static uint8_t audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX]; 115379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer; 116f7c85330SMatthias Ringwald 117fcb08cdbSMilanka Ringwald static int count_sent = 0; 118fcb08cdbSMilanka Ringwald static int count_received = 0; 119c4e666bcSMatthias Ringwald 1201bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 121*79cc780fSMatthias Ringwald #define MSBC_MAX_NUM_SAMPLES (16*8) 122379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state; 1231bbecc2bSMatthias Ringwald #endif 1241bbecc2bSMatthias Ringwald 125379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state; 126379c5f5fSMatthias Ringwald 1272b89dbfcSMatthias Ringwald int num_samples_to_write; 1282b89dbfcSMatthias Ringwald int num_audio_frames; 1292b89dbfcSMatthias Ringwald 130bf958e42SMatthias Ringwald // generic codec support 131bf958e42SMatthias Ringwald typedef struct { 132bf958e42SMatthias Ringwald void (*init)(void); 133bf958e42SMatthias Ringwald void(*receive)(const uint8_t * packet, uint16_t size); 134bf958e42SMatthias Ringwald void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length); 135bf958e42SMatthias Ringwald void (*close)(void); 136*79cc780fSMatthias Ringwald // 137*79cc780fSMatthias Ringwald uint16_t sample_rate; 138bf958e42SMatthias Ringwald } codec_support_t; 139*79cc780fSMatthias Ringwald 140*79cc780fSMatthias Ringwald // current configuration 141bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL; 142bf958e42SMatthias Ringwald 1433cf06407SMatthias Ringwald // sine generator 144d6a06398SMatthias Ringwald 1453cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 1463cf06407SMatthias Ringwald static unsigned int phase; 14794381a69SMatthias Ringwald 1487556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz 149c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 1507556ab9fSMatthias Ringwald 0, 3135, 6237, 9270, 12202, 14999, 17633, 20073, 22294, 24270, 1517556ab9fSMatthias Ringwald 25980, 27406, 28531, 29344, 29835, 30000, 29835, 29344, 28531, 27406, 1527556ab9fSMatthias Ringwald 25980, 24270, 22294, 20073, 17633, 14999, 12202, 9270, 6237, 3135, 1537556ab9fSMatthias Ringwald 0, -3135, -6237, -9270, -12202, -14999, -17633, -20073, -22294, -24270, 1547556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406, 1557556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202, -9270, -6237, -3135, 15635fd3fb9SMatthias Ringwald }; 15735fd3fb9SMatthias Ringwald 15859c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian 1593cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_host_endian(uint16_t num_samples, int16_t * data){ 160249d94cfSMatthias Ringwald unsigned int i; 16159c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 1626fb1424bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase]; 16359c97ae1SMatthias Ringwald // ony use every second sample from 16khz table to get 8khz 16459c97ae1SMatthias Ringwald phase += 2; 165c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 16635fd3fb9SMatthias Ringwald phase = 0; 16735fd3fb9SMatthias Ringwald } 16835fd3fb9SMatthias Ringwald } 16935fd3fb9SMatthias Ringwald } 17035fd3fb9SMatthias Ringwald 1711bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess 1721bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 1733cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(uint16_t num_samples, int16_t * data){ 174249d94cfSMatthias Ringwald unsigned int i; 1751bbecc2bSMatthias Ringwald for (i=0; i < num_samples; i++){ 1761bbecc2bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase++]; 1771bbecc2bSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 1781bbecc2bSMatthias Ringwald phase = 0; 1791bbecc2bSMatthias Ringwald } 1801bbecc2bSMatthias Ringwald } 1811bbecc2bSMatthias Ringwald } 1822b89dbfcSMatthias Ringwald #endif 1831bbecc2bSMatthias Ringwald #endif 184dbb41bfeSMilanka Ringwald 18594381a69SMatthias Ringwald // Audio Playback / Recording 186d861f4bfSMatthias Ringwald 18794381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){ 1882b89dbfcSMatthias Ringwald 189c4e666bcSMatthias Ringwald // fill with silence while paused 190379c5f5fSMatthias Ringwald if (audio_output_paused){ 191bf958e42SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){ 192f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 193379c5f5fSMatthias Ringwald return; 194dbb41bfeSMilanka Ringwald } else { 195c4e666bcSMatthias Ringwald // resume playback 196379c5f5fSMatthias Ringwald audio_output_paused = 0; 197dbb41bfeSMilanka Ringwald } 198c4e666bcSMatthias Ringwald } 199c4e666bcSMatthias Ringwald 200c4e666bcSMatthias Ringwald // get data from ringbuffer 201c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 202f55ac442SMatthias Ringwald btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 203f55ac442SMatthias Ringwald num_samples -= bytes_read / BYTES_PER_FRAME; 204f55ac442SMatthias Ringwald buffer += bytes_read / BYTES_PER_FRAME; 205c4e666bcSMatthias Ringwald 206c4e666bcSMatthias Ringwald // fill with 0 if not enough 207f55ac442SMatthias Ringwald if (num_samples){ 208f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 209379c5f5fSMatthias Ringwald audio_output_paused = 1; 210c4e666bcSMatthias Ringwald } 211379c5f5fSMatthias Ringwald } 2128b29cfc6SMatthias Ringwald 213379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 21494381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){ 215379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2); 216c4e666bcSMatthias Ringwald } 217379c5f5fSMatthias Ringwald #endif 218c4e666bcSMatthias Ringwald 219c4e666bcSMatthias Ringwald // return 1 if ok 220379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){ 221c4e666bcSMatthias Ringwald 222d365bb51SMatthias Ringwald // -- output -- // 223d365bb51SMatthias Ringwald 224379c5f5fSMatthias Ringwald // init buffers 225379c5f5fSMatthias Ringwald memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage)); 226379c5f5fSMatthias Ringwald btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage)); 2272b89dbfcSMatthias Ringwald 228d365bb51SMatthias Ringwald // config and setup audio playback 229d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 230d365bb51SMatthias Ringwald if (!audio_sink) return 0; 2312b89dbfcSMatthias Ringwald 23294381a69SMatthias Ringwald audio_sink->init(1, sample_rate, &audio_playback_callback); 233d365bb51SMatthias Ringwald audio_sink->start_stream(); 234379c5f5fSMatthias Ringwald 235379c5f5fSMatthias Ringwald audio_output_paused = 1; 236d365bb51SMatthias Ringwald 237d365bb51SMatthias Ringwald // -- input -- // 238d365bb51SMatthias Ringwald 239d365bb51SMatthias Ringwald // init buffers 240d365bb51SMatthias Ringwald memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage)); 241d365bb51SMatthias Ringwald btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage)); 2426fb1424bSMatthias Ringwald audio_input_paused = 1; 243d365bb51SMatthias Ringwald 2446fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT 245d365bb51SMatthias Ringwald // config and setup audio recording 246d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance(); 247d365bb51SMatthias Ringwald if (!audio_source) return 0; 248d365bb51SMatthias Ringwald 24994381a69SMatthias Ringwald audio_source->init(1, sample_rate, &audio_recording_callback); 250d365bb51SMatthias Ringwald audio_source->start_stream(); 2512b89dbfcSMatthias Ringwald #endif 2522b89dbfcSMatthias Ringwald 253c4e666bcSMatthias Ringwald return 1; 254c4e666bcSMatthias Ringwald } 2552b89dbfcSMatthias Ringwald 256379c5f5fSMatthias Ringwald static void audio_terminate(void){ 257d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 258d365bb51SMatthias Ringwald if (!audio_sink) return; 259d365bb51SMatthias Ringwald audio_sink->close(); 260d365bb51SMatthias Ringwald 261d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT 262d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance(); 263d365bb51SMatthias Ringwald if (!audio_source) return; 264d365bb51SMatthias Ringwald audio_source->close(); 265d365bb51SMatthias Ringwald #endif 2662b89dbfcSMatthias Ringwald } 267c4e666bcSMatthias Ringwald 268d861f4bfSMatthias Ringwald 26994381a69SMatthias Ringwald // CVSD - 8 kHz 270fcb08cdbSMilanka Ringwald 271bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){ 272c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 273c4e666bcSMatthias Ringwald 274fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 275c4e666bcSMatthias Ringwald 276bf958e42SMatthias Ringwald audio_prebuffer_bytes = PREBUFFER_BYTES_8KHZ; 277bf958e42SMatthias Ringwald 278bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 279bf958e42SMatthias Ringwald sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_8000_hz_host_endian; 280bf958e42SMatthias Ringwald #endif 281b150a479SMatthias Ringwald 2822c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 283b150a479SMatthias Ringwald num_samples_to_write = SAMPLE_RATE_8KHZ * SCO_WAV_DURATION_IN_SECONDS; 284b150a479SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, SAMPLE_RATE_8KHZ); 2852c7ae6e1SMatthias Ringwald #endif 286dbb41bfeSMilanka Ringwald 287b150a479SMatthias Ringwald audio_initialize(SAMPLE_RATE_8KHZ); 288fbc7c9f2SMilanka Ringwald } 289fbc7c9f2SMilanka Ringwald 290bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){ 2912c7ae6e1SMatthias Ringwald 2925303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 2931f8694ccSMatthias Ringwald 2941f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 295bf958e42SMatthias Ringwald printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n"); 2961f8694ccSMatthias Ringwald return; 2971f8694ccSMatthias Ringwald } 2982c7ae6e1SMatthias Ringwald 299c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 300379c5f5fSMatthias Ringwald const int num_samples = audio_bytes_read / BYTES_PER_FRAME; 3015303ddeeSMatthias Ringwald 3025303ddeeSMatthias Ringwald // convert into host endian 3035303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 3045303ddeeSMatthias Ringwald int i; 3055303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 3065303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 3075303ddeeSMatthias Ringwald } 3085303ddeeSMatthias Ringwald 3095f4f94c7SMatthias Ringwald // treat packet as bad frame if controller does not report 'all good' 3105f4f94c7SMatthias Ringwald bool bad_frame = (packet[1] & 0x30) != 0; 3115f4f94c7SMatthias Ringwald 3125f4f94c7SMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out); 3135303ddeeSMatthias Ringwald 3142c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3152c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 3162c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 3172c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 3182c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 3192c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 3202c7ae6e1SMatthias Ringwald wav_writer_close(); 3212c7ae6e1SMatthias Ringwald } 3222c7ae6e1SMatthias Ringwald #endif 3232c7ae6e1SMatthias Ringwald 324379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 325fcb08cdbSMilanka Ringwald } 326fcb08cdbSMilanka Ringwald 327bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){ 3286fb1424bSMatthias Ringwald uint16_t bytes_to_copy = sco_payload_length; 3296fb1424bSMatthias Ringwald 3302b89dbfcSMatthias Ringwald // get data from ringbuffer 3312b89dbfcSMatthias Ringwald uint16_t pos = 0; 332379c5f5fSMatthias Ringwald if (!audio_input_paused){ 3336fb1424bSMatthias Ringwald uint16_t samples_to_copy = sco_payload_length / 2; 3342b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 3356fb1424bSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read); 3368fd6902dSMatthias Ringwald // flip 16 on big endian systems 3378fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 3388fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 3396fb1424bSMatthias Ringwald uint16_t i; 3406fb1424bSMatthias Ringwald for (i=0;i<samples_to_copy/2;i+=2){ 3416fb1424bSMatthias Ringwald uint8_t tmp = payload_buffer[i*2]; 3426fb1424bSMatthias Ringwald payload_buffer[i*2] = payload_buffer[i*2+1]; 3436fb1424bSMatthias Ringwald payload_buffer[i*2+1] = tmp; 3448fd6902dSMatthias Ringwald } 3458fd6902dSMatthias Ringwald } 3462b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 3472b89dbfcSMatthias Ringwald pos += bytes_read; 3482b89dbfcSMatthias Ringwald } 3492b89dbfcSMatthias Ringwald 3502b89dbfcSMatthias Ringwald // fill with 0 if not enough 3512b89dbfcSMatthias Ringwald if (bytes_to_copy){ 3526fb1424bSMatthias Ringwald memset(payload_buffer + pos, 0, bytes_to_copy); 353379c5f5fSMatthias Ringwald audio_input_paused = 1; 3542b89dbfcSMatthias Ringwald } 3552b89dbfcSMatthias Ringwald } 35694381a69SMatthias Ringwald 357bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){ 358bf958e42SMatthias 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); 359bf958e42SMatthias Ringwald } 360bf958e42SMatthias Ringwald 361bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = { 362bf958e42SMatthias Ringwald .init = &sco_demo_cvsd_init, 363bf958e42SMatthias Ringwald .receive = &sco_demo_cvsd_receive, 364bf958e42SMatthias Ringwald .fill_payload = &sco_demo_cvsd_fill_payload, 365*79cc780fSMatthias Ringwald .close = &sco_demo_cvsd_close, 366*79cc780fSMatthias Ringwald .sample_rate = SAMPLE_RATE_8KHZ 367bf958e42SMatthias Ringwald }; 368bf958e42SMatthias Ringwald 36994381a69SMatthias Ringwald // mSBC - 16 kHz 37094381a69SMatthias Ringwald 37194381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 37294381a69SMatthias Ringwald 37394381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 37494381a69SMatthias Ringwald UNUSED(context); 37594381a69SMatthias Ringwald UNUSED(sample_rate); 37694381a69SMatthias Ringwald UNUSED(data); 37794381a69SMatthias Ringwald UNUSED(num_samples); 37894381a69SMatthias Ringwald UNUSED(num_channels); 37994381a69SMatthias Ringwald 38094381a69SMatthias Ringwald // samples in callback in host endianess, ready for playback 38194381a69SMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 38294381a69SMatthias Ringwald 38394381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME 38494381a69SMatthias Ringwald if (!num_samples_to_write) return; 38594381a69SMatthias Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 38694381a69SMatthias Ringwald num_samples_to_write -= num_samples; 38794381a69SMatthias Ringwald wav_writer_write_int16(num_samples, data); 38894381a69SMatthias Ringwald if (num_samples_to_write == 0){ 38994381a69SMatthias Ringwald wav_writer_close(); 390f7c85330SMatthias Ringwald } 39194381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 3921a919128SMatthias Ringwald } 39394381a69SMatthias Ringwald 394bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){ 39594381a69SMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 39694381a69SMatthias Ringwald 39794381a69SMatthias Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 39894381a69SMatthias Ringwald hfp_msbc_init(); 39994381a69SMatthias Ringwald 400bf958e42SMatthias Ringwald audio_prebuffer_bytes = PREBUFFER_BYTES_16KHZ; 401bf958e42SMatthias Ringwald 402bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 403bf958e42SMatthias Ringwald sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_16000_hz_host_endian; 404bf958e42SMatthias Ringwald #endif 405b150a479SMatthias Ringwald 40694381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME 407b150a479SMatthias Ringwald num_samples_to_write = SAMPLE_RATE_16KHZ * SCO_WAV_DURATION_IN_SECONDS; 408b150a479SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, SAMPLE_RATE_16KHZ); 409f7c85330SMatthias Ringwald #endif 410220eb563SMilanka Ringwald 411b150a479SMatthias Ringwald audio_initialize(SAMPLE_RATE_16KHZ); 41294381a69SMatthias Ringwald } 41394381a69SMatthias Ringwald 414bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){ 41594381a69SMatthias Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 41694381a69SMatthias Ringwald } 41794381a69SMatthias Ringwald 418bf958e42SMatthias Ringwald void sco_demo_msbc_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){ 41994381a69SMatthias Ringwald if (!audio_input_paused){ 42094381a69SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 421*79cc780fSMatthias Ringwald btstack_assert(num_samples <= MSBC_MAX_NUM_SAMPLES); 42294381a69SMatthias 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)){ 423*79cc780fSMatthias Ringwald int16_t sample_buffer[MSBC_MAX_NUM_SAMPLES]; 42494381a69SMatthias Ringwald uint32_t bytes_read; 42594381a69SMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 42694381a69SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 42794381a69SMatthias Ringwald num_audio_frames++; 42894381a69SMatthias Ringwald } 429b89b876fSMatthias Ringwald btstack_assert(hfp_msbc_num_bytes_in_stream() >= sco_payload_length); 43094381a69SMatthias Ringwald } 431b89b876fSMatthias Ringwald 432b89b876fSMatthias Ringwald // get data from encoder, fill with 0 if not enough 43394381a69SMatthias Ringwald if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 43494381a69SMatthias Ringwald // just send '0's 43594381a69SMatthias Ringwald memset(payload_buffer, 0, sco_payload_length); 43694381a69SMatthias Ringwald audio_input_paused = 1; 43794381a69SMatthias Ringwald } else { 43894381a69SMatthias Ringwald hfp_msbc_read_from_stream(payload_buffer, sco_payload_length); 43994381a69SMatthias Ringwald } 44094381a69SMatthias Ringwald } 44194381a69SMatthias Ringwald 442bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){ 443bf958e42SMatthias 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); 444bf958e42SMatthias Ringwald } 445bf958e42SMatthias Ringwald 446bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = { 447bf958e42SMatthias Ringwald .init = &sco_demo_msbc_init, 448bf958e42SMatthias Ringwald .receive = &sco_demo_msbc_receive, 449bf958e42SMatthias Ringwald .fill_payload = &sco_demo_msbc_fill_payload, 450*79cc780fSMatthias Ringwald .close = &sco_demo_msbc_close, 451*79cc780fSMatthias Ringwald .sample_rate = SAMPLE_RATE_16KHZ 452bf958e42SMatthias Ringwald }; 453bf958e42SMatthias Ringwald 45494381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 45594381a69SMatthias Ringwald 45694381a69SMatthias Ringwald void sco_demo_init(void){ 45794381a69SMatthias Ringwald 45894381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS 45994381a69SMatthias Ringwald printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n"); 46094381a69SMatthias Ringwald gap_secure_connections_enable(false); 46194381a69SMatthias Ringwald #endif 46294381a69SMatthias Ringwald 46394381a69SMatthias Ringwald // status 46494381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 46594381a69SMatthias Ringwald printf("SCO Demo: Sending and receiving audio via btstack_audio.\n"); 46694381a69SMatthias Ringwald #endif 46794381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 46894381a69SMatthias Ringwald if (btstack_audio_sink_get_instance()){ 46994381a69SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n"); 47094381a69SMatthias Ringwald } else { 47194381a69SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 47294381a69SMatthias Ringwald } 47394381a69SMatthias Ringwald #endif 47494381a69SMatthias Ringwald 47594381a69SMatthias Ringwald // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode) 47694381a69SMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 47794381a69SMatthias Ringwald } 47894381a69SMatthias Ringwald 479bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){ 48094381a69SMatthias Ringwald switch (negotiated_codec){ 48194381a69SMatthias Ringwald case HFP_CODEC_CVSD: 482bf958e42SMatthias Ringwald codec_current = &codec_cvsd; 48394381a69SMatthias Ringwald break; 48494381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 48594381a69SMatthias Ringwald case HFP_CODEC_MSBC: 486bf958e42SMatthias Ringwald codec_current = &codec_msbc; 48794381a69SMatthias Ringwald break; 48894381a69SMatthias Ringwald #endif 48994381a69SMatthias Ringwald default: 49094381a69SMatthias Ringwald btstack_assert(false); 49194381a69SMatthias Ringwald break; 49294381a69SMatthias Ringwald } 493bf958e42SMatthias Ringwald 494bf958e42SMatthias Ringwald codec_current->init(); 49594381a69SMatthias Ringwald } 49694381a69SMatthias Ringwald 49794381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 49894381a69SMatthias Ringwald static uint32_t packets = 0; 49994381a69SMatthias Ringwald static uint32_t crc_errors = 0; 50094381a69SMatthias Ringwald static uint32_t data_received = 0; 50194381a69SMatthias Ringwald static uint32_t byte_errors = 0; 50294381a69SMatthias Ringwald 50394381a69SMatthias Ringwald count_received++; 50494381a69SMatthias Ringwald 50594381a69SMatthias Ringwald data_received += size - 3; 50694381a69SMatthias Ringwald packets++; 50794381a69SMatthias Ringwald if (data_received > 100000){ 50894381a69SMatthias 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); 50994381a69SMatthias Ringwald crc_errors = 0; 51094381a69SMatthias Ringwald byte_errors = 0; 51194381a69SMatthias Ringwald data_received = 0; 51294381a69SMatthias Ringwald packets = 0; 51394381a69SMatthias Ringwald } 51494381a69SMatthias Ringwald 515bf958e42SMatthias Ringwald codec_current->receive(packet, size); 51694381a69SMatthias Ringwald } 51794381a69SMatthias Ringwald 51894381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 51994381a69SMatthias Ringwald 52094381a69SMatthias Ringwald if (sco_handle == HCI_CON_HANDLE_INVALID) return; 52194381a69SMatthias Ringwald 52294381a69SMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 52394381a69SMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 52494381a69SMatthias Ringwald 52594381a69SMatthias Ringwald hci_reserve_packet_buffer(); 52694381a69SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 52794381a69SMatthias Ringwald 528bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 529bf958e42SMatthias Ringwald #define REFILL_SAMPLES 16 530bf958e42SMatthias Ringwald // re-fill audio buffer 531bf958e42SMatthias Ringwald uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2; 532bf958e42SMatthias Ringwald while (samples_free > 0){ 533bf958e42SMatthias Ringwald int16_t samples_buffer[REFILL_SAMPLES]; 534bf958e42SMatthias Ringwald uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES); 535bf958e42SMatthias Ringwald (*sco_demo_audio_generator)(samples_to_add, samples_buffer); 536bf958e42SMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2); 537bf958e42SMatthias Ringwald samples_free -= samples_to_add; 53894381a69SMatthias Ringwald } 539bf958e42SMatthias Ringwald #endif 540bf958e42SMatthias Ringwald 541bf958e42SMatthias Ringwald // resume if pre-buffer is filled 542bf958e42SMatthias Ringwald if (audio_input_paused){ 543bf958e42SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){ 544bf958e42SMatthias Ringwald // resume sending 545bf958e42SMatthias Ringwald audio_input_paused = 0; 546bf958e42SMatthias Ringwald } 547bf958e42SMatthias Ringwald } 548bf958e42SMatthias Ringwald 549bf958e42SMatthias Ringwald // fill payload by codec 550bf958e42SMatthias Ringwald codec_current->fill_payload(&sco_packet[3], sco_payload_length); 5512b89dbfcSMatthias Ringwald 552c4e666bcSMatthias Ringwald // set handle + flags 553c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 554c4e666bcSMatthias Ringwald // set len 555c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 556c4e666bcSMatthias Ringwald // finally send packet 557f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 558f7c85330SMatthias Ringwald 559f7c85330SMatthias Ringwald // request another send event 560f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 561f7c85330SMatthias Ringwald 5624a96141eSMatthias Ringwald count_sent++; 56394381a69SMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) { 56494381a69SMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 56594381a69SMatthias Ringwald } 566f7c85330SMatthias Ringwald } 567f7c85330SMatthias Ringwald 56894381a69SMatthias Ringwald void sco_demo_close(void){ 56994381a69SMatthias Ringwald printf("SCO demo close\n"); 5701a919128SMatthias Ringwald 57194381a69SMatthias Ringwald printf("SCO demo statistics: "); 572bf958e42SMatthias Ringwald codec_current->close(); 573bf958e42SMatthias Ringwald codec_current = NULL; 57494381a69SMatthias Ringwald 57594381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 57694381a69SMatthias Ringwald wav_writer_close(); 5778b29cfc6SMatthias Ringwald #endif 5788b29cfc6SMatthias Ringwald 57994381a69SMatthias Ringwald audio_terminate(); 580f7c85330SMatthias Ringwald } 581