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 68*1762039cSMatthias Ringwald #define SCO_DEMO_MODE_MODPLAYER 2 69f7c85330SMatthias Ringwald 70f7c85330SMatthias Ringwald // SCO demo configuration 71d365bb51SMatthias Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_MICROPHONE 72c4e666bcSMatthias Ringwald 73c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console 74f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 75f7c85330SMatthias Ringwald 76f55ac442SMatthias Ringwald 77d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 782c7ae6e1SMatthias Ringwald // length and name of wav file on disk 79c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15 808b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 81859f2bc5SMatthias Ringwald #endif 82859f2bc5SMatthias Ringwald 83c4e666bcSMatthias Ringwald // constants 84c4e666bcSMatthias Ringwald #define NUM_CHANNELS 1 85b150a479SMatthias Ringwald #define SAMPLE_RATE_8KHZ 8000 86b150a479SMatthias Ringwald #define SAMPLE_RATE_16KHZ 16000 87379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME 2 88f7c85330SMatthias Ringwald 89b150a479SMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency 90b150a479SMatthias Ringwald #define SCO_PREBUFFER_MS 50 91b150a479SMatthias Ringwald #define PREBUFFER_BYTES_8KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_8KHZ/1000 * BYTES_PER_FRAME) 92b150a479SMatthias Ringwald #define PREBUFFER_BYTES_16KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_16KHZ/1000 * BYTES_PER_FRAME) 93f7c85330SMatthias Ringwald 949582ae64SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH) 959582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_16KHZ 969582ae64SMatthias Ringwald #else 979582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_8KHZ 989582ae64SMatthias Ringwald #endif 999582ae64SMatthias Ringwald 100bf958e42SMatthias Ringwald static uint16_t audio_prebuffer_bytes; 101bf958e42SMatthias Ringwald 1022b89dbfcSMatthias Ringwald // output 103d861f4bfSMatthias Ringwald static int audio_output_paused = 0; 1049582ae64SMatthias Ringwald static uint8_t audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX]; 105379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer; 1062b89dbfcSMatthias Ringwald 1072b89dbfcSMatthias Ringwald // input 1082b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 109379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT 1103cf06407SMatthias Ringwald #else 1113cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR 1123cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data); 1136fb1424bSMatthias Ringwald #endif 114379c5f5fSMatthias Ringwald static int audio_input_paused = 0; 1159582ae64SMatthias Ringwald static uint8_t audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX]; 116379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer; 117f7c85330SMatthias Ringwald 118*1762039cSMatthias Ringwald // mod player 119*1762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER 120*1762039cSMatthias Ringwald #include "hxcmod.h" 121*1762039cSMatthias Ringwald #include "mods/mod.h" 122*1762039cSMatthias Ringwald static modcontext mod_context; 123*1762039cSMatthias Ringwald #endif 124*1762039cSMatthias Ringwald 125fcb08cdbSMilanka Ringwald static int count_sent = 0; 126fcb08cdbSMilanka Ringwald static int count_received = 0; 127c4e666bcSMatthias Ringwald 1281bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 12979cc780fSMatthias Ringwald #define MSBC_MAX_NUM_SAMPLES (16*8) 130379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state; 1311bbecc2bSMatthias Ringwald #endif 1321bbecc2bSMatthias Ringwald 133379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state; 134379c5f5fSMatthias Ringwald 1352b89dbfcSMatthias Ringwald int num_samples_to_write; 1362b89dbfcSMatthias Ringwald int num_audio_frames; 1372b89dbfcSMatthias Ringwald 138bf958e42SMatthias Ringwald // generic codec support 139bf958e42SMatthias Ringwald typedef struct { 140bf958e42SMatthias Ringwald void (*init)(void); 141bf958e42SMatthias Ringwald void(*receive)(const uint8_t * packet, uint16_t size); 142bf958e42SMatthias Ringwald void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length); 143bf958e42SMatthias Ringwald void (*close)(void); 14479cc780fSMatthias Ringwald // 14579cc780fSMatthias Ringwald uint16_t sample_rate; 146bf958e42SMatthias Ringwald } codec_support_t; 14779cc780fSMatthias Ringwald 14879cc780fSMatthias Ringwald // current configuration 149bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL; 150bf958e42SMatthias Ringwald 151d6a06398SMatthias Ringwald 1529ad691b0SMatthias Ringwald // Sine Wave 1539ad691b0SMatthias Ringwald 1549ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 1559ad691b0SMatthias Ringwald static uint16_t sine_wave_phase; 1569ad691b0SMatthias Ringwald static uint16_t sine_wave_steps_per_sample; 1579ad691b0SMatthias Ringwald #define SINE_WAVE_SAMPLE_RATE SAMPLE_RATE_16KHZ 15894381a69SMatthias Ringwald 1597556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz 160c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 1617556ab9fSMatthias Ringwald 0, 3135, 6237, 9270, 12202, 14999, 17633, 20073, 22294, 24270, 1627556ab9fSMatthias Ringwald 25980, 27406, 28531, 29344, 29835, 30000, 29835, 29344, 28531, 27406, 1637556ab9fSMatthias Ringwald 25980, 24270, 22294, 20073, 17633, 14999, 12202, 9270, 6237, 3135, 1647556ab9fSMatthias Ringwald 0, -3135, -6237, -9270, -12202, -14999, -17633, -20073, -22294, -24270, 1657556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406, 1667556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202, -9270, -6237, -3135, 16735fd3fb9SMatthias Ringwald }; 16835fd3fb9SMatthias Ringwald 1699ad691b0SMatthias Ringwald static void sco_demo_sine_wave_host_endian(uint16_t num_samples, int16_t * data){ 170249d94cfSMatthias Ringwald unsigned int i; 17159c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 1729ad691b0SMatthias Ringwald data[i] = sine_int16_at_16000hz[sine_wave_phase]; 1739ad691b0SMatthias Ringwald sine_wave_phase += sine_wave_steps_per_sample; 1749ad691b0SMatthias Ringwald if (sine_wave_phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 1759ad691b0SMatthias Ringwald sine_wave_phase = 0; 17635fd3fb9SMatthias Ringwald } 17735fd3fb9SMatthias Ringwald } 17835fd3fb9SMatthias Ringwald } 1791bbecc2bSMatthias Ringwald #endif 180dbb41bfeSMilanka Ringwald 181*1762039cSMatthias Ringwald // Mod Player 182*1762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER 183*1762039cSMatthias Ringwald #define NUM_SAMPLES_GENERATOR_BUFFER 30 184*1762039cSMatthias Ringwald static void sco_demo_modplayer(uint16_t num_samples, int16_t * data){ 185*1762039cSMatthias Ringwald // mix down stereo 186*1762039cSMatthias Ringwald signed short samples[NUM_SAMPLES_GENERATOR_BUFFER * 2]; 187*1762039cSMatthias Ringwald while (num_samples > 0){ 188*1762039cSMatthias Ringwald uint16_t next_samples = btstack_min(num_samples, NUM_SAMPLES_GENERATOR_BUFFER); 189*1762039cSMatthias Ringwald hxcmod_fillbuffer(&mod_context, (unsigned short *) samples, next_samples, NULL); 190*1762039cSMatthias Ringwald num_samples -= next_samples; 191*1762039cSMatthias Ringwald uint16_t i; 192*1762039cSMatthias Ringwald for (i=0;i<next_samples;i++){ 193*1762039cSMatthias Ringwald int32_t left = samples[2*i + 0]; 194*1762039cSMatthias Ringwald int32_t right = samples[2*i + 1]; 195*1762039cSMatthias Ringwald data[i] = (int16_t)((left + right) / 2); 196*1762039cSMatthias Ringwald } 197*1762039cSMatthias Ringwald } 198*1762039cSMatthias Ringwald } 199*1762039cSMatthias Ringwald #endif 200*1762039cSMatthias Ringwald 20194381a69SMatthias Ringwald // Audio Playback / Recording 202d861f4bfSMatthias Ringwald 20394381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){ 2042b89dbfcSMatthias Ringwald 205c4e666bcSMatthias Ringwald // fill with silence while paused 206379c5f5fSMatthias Ringwald if (audio_output_paused){ 207bf958e42SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){ 208f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 209379c5f5fSMatthias Ringwald return; 210dbb41bfeSMilanka Ringwald } else { 211c4e666bcSMatthias Ringwald // resume playback 212379c5f5fSMatthias Ringwald audio_output_paused = 0; 213dbb41bfeSMilanka Ringwald } 214c4e666bcSMatthias Ringwald } 215c4e666bcSMatthias Ringwald 216c4e666bcSMatthias Ringwald // get data from ringbuffer 217c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 218f55ac442SMatthias Ringwald btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 219f55ac442SMatthias Ringwald num_samples -= bytes_read / BYTES_PER_FRAME; 220f55ac442SMatthias Ringwald buffer += bytes_read / BYTES_PER_FRAME; 221c4e666bcSMatthias Ringwald 222c4e666bcSMatthias Ringwald // fill with 0 if not enough 223f55ac442SMatthias Ringwald if (num_samples){ 224f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 225379c5f5fSMatthias Ringwald audio_output_paused = 1; 226c4e666bcSMatthias Ringwald } 227379c5f5fSMatthias Ringwald } 2288b29cfc6SMatthias Ringwald 229379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 23094381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){ 231379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2); 232c4e666bcSMatthias Ringwald } 233379c5f5fSMatthias Ringwald #endif 234c4e666bcSMatthias Ringwald 235c4e666bcSMatthias Ringwald // return 1 if ok 236379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){ 237c4e666bcSMatthias Ringwald 238d365bb51SMatthias Ringwald // -- output -- // 239d365bb51SMatthias Ringwald 240379c5f5fSMatthias Ringwald // init buffers 241379c5f5fSMatthias Ringwald memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage)); 242379c5f5fSMatthias Ringwald btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage)); 2432b89dbfcSMatthias Ringwald 244d365bb51SMatthias Ringwald // config and setup audio playback 245d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 246d365bb51SMatthias Ringwald if (!audio_sink) return 0; 2472b89dbfcSMatthias Ringwald 24894381a69SMatthias Ringwald audio_sink->init(1, sample_rate, &audio_playback_callback); 249d365bb51SMatthias Ringwald audio_sink->start_stream(); 250379c5f5fSMatthias Ringwald 251379c5f5fSMatthias Ringwald audio_output_paused = 1; 252d365bb51SMatthias Ringwald 253d365bb51SMatthias Ringwald // -- input -- // 254d365bb51SMatthias Ringwald 255d365bb51SMatthias Ringwald // init buffers 256d365bb51SMatthias Ringwald memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage)); 257d365bb51SMatthias Ringwald btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage)); 2586fb1424bSMatthias Ringwald audio_input_paused = 1; 259d365bb51SMatthias Ringwald 2606fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT 261d365bb51SMatthias Ringwald // config and setup audio recording 262d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance(); 263d365bb51SMatthias Ringwald if (!audio_source) return 0; 264d365bb51SMatthias Ringwald 26594381a69SMatthias Ringwald audio_source->init(1, sample_rate, &audio_recording_callback); 266d365bb51SMatthias Ringwald audio_source->start_stream(); 2672b89dbfcSMatthias Ringwald #endif 2682b89dbfcSMatthias Ringwald 269c4e666bcSMatthias Ringwald return 1; 270c4e666bcSMatthias Ringwald } 2712b89dbfcSMatthias Ringwald 272379c5f5fSMatthias Ringwald static void audio_terminate(void){ 273d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 274d365bb51SMatthias Ringwald if (!audio_sink) return; 275d365bb51SMatthias Ringwald audio_sink->close(); 276d365bb51SMatthias Ringwald 277d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT 278d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance(); 279d365bb51SMatthias Ringwald if (!audio_source) return; 280d365bb51SMatthias Ringwald audio_source->close(); 281d365bb51SMatthias Ringwald #endif 2822b89dbfcSMatthias Ringwald } 283c4e666bcSMatthias Ringwald 284d861f4bfSMatthias Ringwald 28594381a69SMatthias Ringwald // CVSD - 8 kHz 286fcb08cdbSMilanka Ringwald 287bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){ 288c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 289fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 290fbc7c9f2SMilanka Ringwald } 291fbc7c9f2SMilanka Ringwald 292bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){ 2932c7ae6e1SMatthias Ringwald 2945303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 2951f8694ccSMatthias Ringwald 2961f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 297bf958e42SMatthias Ringwald printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n"); 2981f8694ccSMatthias Ringwald return; 2991f8694ccSMatthias Ringwald } 3002c7ae6e1SMatthias Ringwald 301c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 302379c5f5fSMatthias Ringwald const int num_samples = audio_bytes_read / BYTES_PER_FRAME; 3035303ddeeSMatthias Ringwald 3045303ddeeSMatthias Ringwald // convert into host endian 3055303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 3065303ddeeSMatthias Ringwald int i; 3075303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 3085303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 3095303ddeeSMatthias Ringwald } 3105303ddeeSMatthias Ringwald 3115f4f94c7SMatthias Ringwald // treat packet as bad frame if controller does not report 'all good' 3125f4f94c7SMatthias Ringwald bool bad_frame = (packet[1] & 0x30) != 0; 3135f4f94c7SMatthias Ringwald 3145f4f94c7SMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out); 3155303ddeeSMatthias Ringwald 3162c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3172c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 3182c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 3192c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 3202c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 3212c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 3222c7ae6e1SMatthias Ringwald wav_writer_close(); 3232c7ae6e1SMatthias Ringwald } 3242c7ae6e1SMatthias Ringwald #endif 3252c7ae6e1SMatthias Ringwald 326379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 327fcb08cdbSMilanka Ringwald } 328fcb08cdbSMilanka Ringwald 329bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){ 3306fb1424bSMatthias Ringwald uint16_t bytes_to_copy = sco_payload_length; 3316fb1424bSMatthias Ringwald 3322b89dbfcSMatthias Ringwald // get data from ringbuffer 3332b89dbfcSMatthias Ringwald uint16_t pos = 0; 334379c5f5fSMatthias Ringwald if (!audio_input_paused){ 3356fb1424bSMatthias Ringwald uint16_t samples_to_copy = sco_payload_length / 2; 3362b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 3376fb1424bSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read); 3388fd6902dSMatthias Ringwald // flip 16 on big endian systems 3398fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 3408fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 3416fb1424bSMatthias Ringwald uint16_t i; 3426fb1424bSMatthias Ringwald for (i=0;i<samples_to_copy/2;i+=2){ 3436fb1424bSMatthias Ringwald uint8_t tmp = payload_buffer[i*2]; 3446fb1424bSMatthias Ringwald payload_buffer[i*2] = payload_buffer[i*2+1]; 3456fb1424bSMatthias Ringwald payload_buffer[i*2+1] = tmp; 3468fd6902dSMatthias Ringwald } 3478fd6902dSMatthias Ringwald } 3482b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 3492b89dbfcSMatthias Ringwald pos += bytes_read; 3502b89dbfcSMatthias Ringwald } 3512b89dbfcSMatthias Ringwald 3522b89dbfcSMatthias Ringwald // fill with 0 if not enough 3532b89dbfcSMatthias Ringwald if (bytes_to_copy){ 3546fb1424bSMatthias Ringwald memset(payload_buffer + pos, 0, bytes_to_copy); 355379c5f5fSMatthias Ringwald audio_input_paused = 1; 3562b89dbfcSMatthias Ringwald } 3572b89dbfcSMatthias Ringwald } 35894381a69SMatthias Ringwald 359bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){ 360bf958e42SMatthias 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); 361bf958e42SMatthias Ringwald } 362bf958e42SMatthias Ringwald 363bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = { 364bf958e42SMatthias Ringwald .init = &sco_demo_cvsd_init, 365bf958e42SMatthias Ringwald .receive = &sco_demo_cvsd_receive, 366bf958e42SMatthias Ringwald .fill_payload = &sco_demo_cvsd_fill_payload, 36779cc780fSMatthias Ringwald .close = &sco_demo_cvsd_close, 36879cc780fSMatthias Ringwald .sample_rate = SAMPLE_RATE_8KHZ 369bf958e42SMatthias Ringwald }; 370bf958e42SMatthias Ringwald 37194381a69SMatthias Ringwald // mSBC - 16 kHz 37294381a69SMatthias Ringwald 37394381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 37494381a69SMatthias Ringwald 37594381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 37694381a69SMatthias Ringwald UNUSED(context); 37794381a69SMatthias Ringwald UNUSED(sample_rate); 37894381a69SMatthias Ringwald UNUSED(data); 37994381a69SMatthias Ringwald UNUSED(num_samples); 38094381a69SMatthias Ringwald UNUSED(num_channels); 38194381a69SMatthias Ringwald 38294381a69SMatthias Ringwald // samples in callback in host endianess, ready for playback 38394381a69SMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 38494381a69SMatthias Ringwald 38594381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME 38694381a69SMatthias Ringwald if (!num_samples_to_write) return; 38794381a69SMatthias Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 38894381a69SMatthias Ringwald num_samples_to_write -= num_samples; 38994381a69SMatthias Ringwald wav_writer_write_int16(num_samples, data); 39094381a69SMatthias Ringwald if (num_samples_to_write == 0){ 39194381a69SMatthias Ringwald wav_writer_close(); 392f7c85330SMatthias Ringwald } 39394381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 3941a919128SMatthias Ringwald } 39594381a69SMatthias Ringwald 396bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){ 39794381a69SMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 39894381a69SMatthias Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 39994381a69SMatthias Ringwald hfp_msbc_init(); 40094381a69SMatthias Ringwald } 40194381a69SMatthias Ringwald 402bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){ 40394381a69SMatthias Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 40494381a69SMatthias Ringwald } 40594381a69SMatthias Ringwald 406bf958e42SMatthias Ringwald void sco_demo_msbc_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){ 40794381a69SMatthias Ringwald if (!audio_input_paused){ 40894381a69SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 40979cc780fSMatthias Ringwald btstack_assert(num_samples <= MSBC_MAX_NUM_SAMPLES); 41094381a69SMatthias 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)){ 41179cc780fSMatthias Ringwald int16_t sample_buffer[MSBC_MAX_NUM_SAMPLES]; 41294381a69SMatthias Ringwald uint32_t bytes_read; 41394381a69SMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 41494381a69SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 41594381a69SMatthias Ringwald num_audio_frames++; 41694381a69SMatthias Ringwald } 417b89b876fSMatthias Ringwald btstack_assert(hfp_msbc_num_bytes_in_stream() >= sco_payload_length); 41894381a69SMatthias Ringwald } 419b89b876fSMatthias Ringwald 420b89b876fSMatthias Ringwald // get data from encoder, fill with 0 if not enough 42194381a69SMatthias Ringwald if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 42294381a69SMatthias Ringwald // just send '0's 42394381a69SMatthias Ringwald memset(payload_buffer, 0, sco_payload_length); 42494381a69SMatthias Ringwald audio_input_paused = 1; 42594381a69SMatthias Ringwald } else { 42694381a69SMatthias Ringwald hfp_msbc_read_from_stream(payload_buffer, sco_payload_length); 42794381a69SMatthias Ringwald } 42894381a69SMatthias Ringwald } 42994381a69SMatthias Ringwald 430bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){ 431bf958e42SMatthias 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); 432bf958e42SMatthias Ringwald } 433bf958e42SMatthias Ringwald 434bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = { 435bf958e42SMatthias Ringwald .init = &sco_demo_msbc_init, 436bf958e42SMatthias Ringwald .receive = &sco_demo_msbc_receive, 437bf958e42SMatthias Ringwald .fill_payload = &sco_demo_msbc_fill_payload, 43879cc780fSMatthias Ringwald .close = &sco_demo_msbc_close, 43979cc780fSMatthias Ringwald .sample_rate = SAMPLE_RATE_16KHZ 440bf958e42SMatthias Ringwald }; 441bf958e42SMatthias Ringwald 44294381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 44394381a69SMatthias Ringwald 44494381a69SMatthias Ringwald void sco_demo_init(void){ 44594381a69SMatthias Ringwald 44694381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS 44794381a69SMatthias Ringwald printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n"); 44894381a69SMatthias Ringwald gap_secure_connections_enable(false); 44994381a69SMatthias Ringwald #endif 45094381a69SMatthias Ringwald 45194381a69SMatthias Ringwald // status 45294381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 45394381a69SMatthias Ringwald printf("SCO Demo: Sending and receiving audio via btstack_audio.\n"); 45494381a69SMatthias Ringwald #endif 45594381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 45694381a69SMatthias Ringwald if (btstack_audio_sink_get_instance()){ 45794381a69SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n"); 45894381a69SMatthias Ringwald } else { 45994381a69SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 46094381a69SMatthias Ringwald } 46194381a69SMatthias Ringwald #endif 46294381a69SMatthias Ringwald 46394381a69SMatthias Ringwald // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode) 46494381a69SMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 465*1762039cSMatthias Ringwald 466*1762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER 467*1762039cSMatthias Ringwald // init mod 468*1762039cSMatthias Ringwald int hxcmod_initialized = hxcmod_init(&mod_context); 469*1762039cSMatthias Ringwald btstack_assert(hxcmod_initialized != 0); 470*1762039cSMatthias Ringwald #endif 47194381a69SMatthias Ringwald } 47294381a69SMatthias Ringwald 473bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){ 47494381a69SMatthias Ringwald switch (negotiated_codec){ 47594381a69SMatthias Ringwald case HFP_CODEC_CVSD: 476bf958e42SMatthias Ringwald codec_current = &codec_cvsd; 47794381a69SMatthias Ringwald break; 47894381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 47994381a69SMatthias Ringwald case HFP_CODEC_MSBC: 480bf958e42SMatthias Ringwald codec_current = &codec_msbc; 48194381a69SMatthias Ringwald break; 48294381a69SMatthias Ringwald #endif 48394381a69SMatthias Ringwald default: 48494381a69SMatthias Ringwald btstack_assert(false); 48594381a69SMatthias Ringwald break; 48694381a69SMatthias Ringwald } 487bf958e42SMatthias Ringwald 488bf958e42SMatthias Ringwald codec_current->init(); 4899ad691b0SMatthias Ringwald 4909ad691b0SMatthias Ringwald audio_initialize(codec_current->sample_rate); 4919ad691b0SMatthias Ringwald 4929ad691b0SMatthias Ringwald audio_prebuffer_bytes = SCO_PREBUFFER_MS * (codec_current->sample_rate/1000) * BYTES_PER_FRAME; 4939ad691b0SMatthias Ringwald 4949ad691b0SMatthias Ringwald #ifdef SCO_WAV_FILENAME 4959ad691b0SMatthias Ringwald num_samples_to_write = codec_current->sample_rate * SCO_WAV_DURATION_IN_SECONDS; 4969ad691b0SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, codec_current->sample_rate); 4979ad691b0SMatthias Ringwald #endif 4989ad691b0SMatthias Ringwald 4999ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 5009ad691b0SMatthias Ringwald sine_wave_steps_per_sample = SINE_WAVE_SAMPLE_RATE / codec_current->sample_rate; 5019ad691b0SMatthias Ringwald sco_demo_audio_generator = &sco_demo_sine_wave_host_endian; 5029ad691b0SMatthias Ringwald #endif 503*1762039cSMatthias Ringwald 504*1762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER 505*1762039cSMatthias Ringwald // load mod 506*1762039cSMatthias Ringwald hxcmod_setcfg(&mod_context, codec_current->sample_rate, 16, 1, 1, 1); 507*1762039cSMatthias Ringwald hxcmod_load(&mod_context, (void *) &mod_data, mod_len); 508*1762039cSMatthias Ringwald sco_demo_audio_generator = &sco_demo_modplayer; 509*1762039cSMatthias Ringwald #endif 51094381a69SMatthias Ringwald } 51194381a69SMatthias Ringwald 51294381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 51394381a69SMatthias Ringwald static uint32_t packets = 0; 51494381a69SMatthias Ringwald static uint32_t crc_errors = 0; 51594381a69SMatthias Ringwald static uint32_t data_received = 0; 51694381a69SMatthias Ringwald static uint32_t byte_errors = 0; 51794381a69SMatthias Ringwald 51894381a69SMatthias Ringwald count_received++; 51994381a69SMatthias Ringwald 52094381a69SMatthias Ringwald data_received += size - 3; 52194381a69SMatthias Ringwald packets++; 52294381a69SMatthias Ringwald if (data_received > 100000){ 52394381a69SMatthias 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); 52494381a69SMatthias Ringwald crc_errors = 0; 52594381a69SMatthias Ringwald byte_errors = 0; 52694381a69SMatthias Ringwald data_received = 0; 52794381a69SMatthias Ringwald packets = 0; 52894381a69SMatthias Ringwald } 52994381a69SMatthias Ringwald 530bf958e42SMatthias Ringwald codec_current->receive(packet, size); 53194381a69SMatthias Ringwald } 53294381a69SMatthias Ringwald 53394381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 53494381a69SMatthias Ringwald 53594381a69SMatthias Ringwald if (sco_handle == HCI_CON_HANDLE_INVALID) return; 53694381a69SMatthias Ringwald 53794381a69SMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 53894381a69SMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 53994381a69SMatthias Ringwald 54094381a69SMatthias Ringwald hci_reserve_packet_buffer(); 54194381a69SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 54294381a69SMatthias Ringwald 543bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 544bf958e42SMatthias Ringwald #define REFILL_SAMPLES 16 545bf958e42SMatthias Ringwald // re-fill audio buffer 546bf958e42SMatthias Ringwald uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2; 547bf958e42SMatthias Ringwald while (samples_free > 0){ 548bf958e42SMatthias Ringwald int16_t samples_buffer[REFILL_SAMPLES]; 549bf958e42SMatthias Ringwald uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES); 550bf958e42SMatthias Ringwald (*sco_demo_audio_generator)(samples_to_add, samples_buffer); 551bf958e42SMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2); 552bf958e42SMatthias Ringwald samples_free -= samples_to_add; 55394381a69SMatthias Ringwald } 554bf958e42SMatthias Ringwald #endif 555bf958e42SMatthias Ringwald 556bf958e42SMatthias Ringwald // resume if pre-buffer is filled 557bf958e42SMatthias Ringwald if (audio_input_paused){ 558bf958e42SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){ 559bf958e42SMatthias Ringwald // resume sending 560bf958e42SMatthias Ringwald audio_input_paused = 0; 561bf958e42SMatthias Ringwald } 562bf958e42SMatthias Ringwald } 563bf958e42SMatthias Ringwald 564bf958e42SMatthias Ringwald // fill payload by codec 565bf958e42SMatthias Ringwald codec_current->fill_payload(&sco_packet[3], sco_payload_length); 5662b89dbfcSMatthias Ringwald 567c4e666bcSMatthias Ringwald // set handle + flags 568c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 569c4e666bcSMatthias Ringwald // set len 570c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 571c4e666bcSMatthias Ringwald // finally send packet 572f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 573f7c85330SMatthias Ringwald 574f7c85330SMatthias Ringwald // request another send event 575f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 576f7c85330SMatthias Ringwald 5774a96141eSMatthias Ringwald count_sent++; 57894381a69SMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) { 57994381a69SMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 58094381a69SMatthias Ringwald } 581f7c85330SMatthias Ringwald } 582f7c85330SMatthias Ringwald 58394381a69SMatthias Ringwald void sco_demo_close(void){ 58494381a69SMatthias Ringwald printf("SCO demo close\n"); 5851a919128SMatthias Ringwald 58694381a69SMatthias Ringwald printf("SCO demo statistics: "); 587bf958e42SMatthias Ringwald codec_current->close(); 588bf958e42SMatthias Ringwald codec_current = NULL; 58994381a69SMatthias Ringwald 59094381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 59194381a69SMatthias Ringwald wav_writer_close(); 5928b29cfc6SMatthias Ringwald #endif 5938b29cfc6SMatthias Ringwald 59494381a69SMatthias Ringwald audio_terminate(); 595f7c85330SMatthias Ringwald } 596