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 93*bf958e42SMatthias Ringwald static uint16_t audio_prebuffer_bytes; 94*bf958e42SMatthias Ringwald 952b89dbfcSMatthias Ringwald // output 96d861f4bfSMatthias Ringwald static int audio_output_paused = 0; 97b150a479SMatthias Ringwald static uint8_t audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_16KHZ]; 98379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer; 992b89dbfcSMatthias Ringwald 1002b89dbfcSMatthias Ringwald // input 1012b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 102379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT 1033cf06407SMatthias Ringwald #else 1043cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR 1053cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data); 1066fb1424bSMatthias Ringwald #endif 107379c5f5fSMatthias Ringwald static int audio_input_paused = 0; 108b150a479SMatthias Ringwald static uint8_t audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_16KHZ]; 109379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer; 110f7c85330SMatthias Ringwald 111fcb08cdbSMilanka Ringwald static int count_sent = 0; 112fcb08cdbSMilanka Ringwald static int count_received = 0; 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 125*bf958e42SMatthias Ringwald // generic codec support 126*bf958e42SMatthias Ringwald typedef struct { 127*bf958e42SMatthias Ringwald void (*init)(void); 128*bf958e42SMatthias Ringwald void(*receive)(const uint8_t * packet, uint16_t size); 129*bf958e42SMatthias Ringwald void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length); 130*bf958e42SMatthias Ringwald void (*close)(void); 131*bf958e42SMatthias Ringwald } codec_support_t; 132*bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL; 133*bf958e42SMatthias Ringwald 1343cf06407SMatthias Ringwald // sine generator 135d6a06398SMatthias Ringwald 1363cf06407SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 1373cf06407SMatthias Ringwald static unsigned int phase; 13894381a69SMatthias Ringwald 1397556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz 140c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 1417556ab9fSMatthias Ringwald 0, 3135, 6237, 9270, 12202, 14999, 17633, 20073, 22294, 24270, 1427556ab9fSMatthias Ringwald 25980, 27406, 28531, 29344, 29835, 30000, 29835, 29344, 28531, 27406, 1437556ab9fSMatthias Ringwald 25980, 24270, 22294, 20073, 17633, 14999, 12202, 9270, 6237, 3135, 1447556ab9fSMatthias Ringwald 0, -3135, -6237, -9270, -12202, -14999, -17633, -20073, -22294, -24270, 1457556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406, 1467556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202, -9270, -6237, -3135, 14735fd3fb9SMatthias Ringwald }; 14835fd3fb9SMatthias Ringwald 14959c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian 1503cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_host_endian(uint16_t num_samples, int16_t * data){ 151249d94cfSMatthias Ringwald unsigned int i; 15259c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 1536fb1424bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase]; 15459c97ae1SMatthias Ringwald // ony use every second sample from 16khz table to get 8khz 15559c97ae1SMatthias Ringwald phase += 2; 156c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 15735fd3fb9SMatthias Ringwald phase = 0; 15835fd3fb9SMatthias Ringwald } 15935fd3fb9SMatthias Ringwald } 16035fd3fb9SMatthias Ringwald } 16135fd3fb9SMatthias Ringwald 1621bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess 1631bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 1643cf06407SMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(uint16_t num_samples, int16_t * data){ 165249d94cfSMatthias Ringwald unsigned int i; 1661bbecc2bSMatthias Ringwald for (i=0; i < num_samples; i++){ 1671bbecc2bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase++]; 1681bbecc2bSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 1691bbecc2bSMatthias Ringwald phase = 0; 1701bbecc2bSMatthias Ringwald } 1711bbecc2bSMatthias Ringwald } 1721bbecc2bSMatthias Ringwald } 1732b89dbfcSMatthias Ringwald #endif 1741bbecc2bSMatthias Ringwald #endif 175dbb41bfeSMilanka Ringwald 17694381a69SMatthias Ringwald // Audio Playback / Recording 177d861f4bfSMatthias Ringwald 17894381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){ 1792b89dbfcSMatthias Ringwald 180c4e666bcSMatthias Ringwald // fill with silence while paused 181379c5f5fSMatthias Ringwald if (audio_output_paused){ 182*bf958e42SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){ 183f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 184379c5f5fSMatthias Ringwald return; 185dbb41bfeSMilanka Ringwald } else { 186c4e666bcSMatthias Ringwald // resume playback 187379c5f5fSMatthias Ringwald audio_output_paused = 0; 188dbb41bfeSMilanka Ringwald } 189c4e666bcSMatthias Ringwald } 190c4e666bcSMatthias Ringwald 191c4e666bcSMatthias Ringwald // get data from ringbuffer 192c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 193f55ac442SMatthias Ringwald btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 194f55ac442SMatthias Ringwald num_samples -= bytes_read / BYTES_PER_FRAME; 195f55ac442SMatthias Ringwald buffer += bytes_read / BYTES_PER_FRAME; 196c4e666bcSMatthias Ringwald 197c4e666bcSMatthias Ringwald // fill with 0 if not enough 198f55ac442SMatthias Ringwald if (num_samples){ 199f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 200379c5f5fSMatthias Ringwald audio_output_paused = 1; 201c4e666bcSMatthias Ringwald } 202379c5f5fSMatthias Ringwald } 2038b29cfc6SMatthias Ringwald 204379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 20594381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){ 206379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2); 207c4e666bcSMatthias Ringwald } 208379c5f5fSMatthias Ringwald #endif 209c4e666bcSMatthias Ringwald 210c4e666bcSMatthias Ringwald // return 1 if ok 211379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){ 212c4e666bcSMatthias Ringwald 213d365bb51SMatthias Ringwald // -- output -- // 214d365bb51SMatthias Ringwald 215379c5f5fSMatthias Ringwald // init buffers 216379c5f5fSMatthias Ringwald memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage)); 217379c5f5fSMatthias Ringwald btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage)); 2182b89dbfcSMatthias Ringwald 219d365bb51SMatthias Ringwald // config and setup audio playback 220d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 221d365bb51SMatthias Ringwald if (!audio_sink) return 0; 2222b89dbfcSMatthias Ringwald 22394381a69SMatthias Ringwald audio_sink->init(1, sample_rate, &audio_playback_callback); 224d365bb51SMatthias Ringwald audio_sink->start_stream(); 225379c5f5fSMatthias Ringwald 226379c5f5fSMatthias Ringwald audio_output_paused = 1; 227d365bb51SMatthias Ringwald 228d365bb51SMatthias Ringwald // -- input -- // 229d365bb51SMatthias Ringwald 230d365bb51SMatthias Ringwald // init buffers 231d365bb51SMatthias Ringwald memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage)); 232d365bb51SMatthias Ringwald btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage)); 2336fb1424bSMatthias Ringwald audio_input_paused = 1; 234d365bb51SMatthias Ringwald 2356fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT 236d365bb51SMatthias Ringwald // config and setup audio recording 237d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance(); 238d365bb51SMatthias Ringwald if (!audio_source) return 0; 239d365bb51SMatthias Ringwald 24094381a69SMatthias Ringwald audio_source->init(1, sample_rate, &audio_recording_callback); 241d365bb51SMatthias Ringwald audio_source->start_stream(); 2422b89dbfcSMatthias Ringwald #endif 2432b89dbfcSMatthias Ringwald 244c4e666bcSMatthias Ringwald return 1; 245c4e666bcSMatthias Ringwald } 2462b89dbfcSMatthias Ringwald 247379c5f5fSMatthias Ringwald static void audio_terminate(void){ 248d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 249d365bb51SMatthias Ringwald if (!audio_sink) return; 250d365bb51SMatthias Ringwald audio_sink->close(); 251d365bb51SMatthias Ringwald 252d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT 253d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance(); 254d365bb51SMatthias Ringwald if (!audio_source) return; 255d365bb51SMatthias Ringwald audio_source->close(); 256d365bb51SMatthias Ringwald #endif 2572b89dbfcSMatthias Ringwald } 258c4e666bcSMatthias Ringwald 259d861f4bfSMatthias Ringwald 26094381a69SMatthias Ringwald // CVSD - 8 kHz 261fcb08cdbSMilanka Ringwald 262*bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){ 263c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 264c4e666bcSMatthias Ringwald 265fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 266c4e666bcSMatthias Ringwald 267*bf958e42SMatthias Ringwald audio_prebuffer_bytes = PREBUFFER_BYTES_8KHZ; 268*bf958e42SMatthias Ringwald 269*bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 270*bf958e42SMatthias Ringwald sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_8000_hz_host_endian; 271*bf958e42SMatthias Ringwald #endif 272b150a479SMatthias Ringwald 2732c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 274b150a479SMatthias Ringwald num_samples_to_write = SAMPLE_RATE_8KHZ * SCO_WAV_DURATION_IN_SECONDS; 275b150a479SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, SAMPLE_RATE_8KHZ); 2762c7ae6e1SMatthias Ringwald #endif 277dbb41bfeSMilanka Ringwald 278b150a479SMatthias Ringwald audio_initialize(SAMPLE_RATE_8KHZ); 279fbc7c9f2SMilanka Ringwald } 280fbc7c9f2SMilanka Ringwald 281*bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){ 2822c7ae6e1SMatthias Ringwald 2835303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 2841f8694ccSMatthias Ringwald 2851f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 286*bf958e42SMatthias Ringwald printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n"); 2871f8694ccSMatthias Ringwald return; 2881f8694ccSMatthias Ringwald } 2892c7ae6e1SMatthias Ringwald 290c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 291379c5f5fSMatthias Ringwald const int num_samples = audio_bytes_read / BYTES_PER_FRAME; 2925303ddeeSMatthias Ringwald 2935303ddeeSMatthias Ringwald // convert into host endian 2945303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 2955303ddeeSMatthias Ringwald int i; 2965303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 2975303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 2985303ddeeSMatthias Ringwald } 2995303ddeeSMatthias Ringwald 3005f4f94c7SMatthias Ringwald // treat packet as bad frame if controller does not report 'all good' 3015f4f94c7SMatthias Ringwald bool bad_frame = (packet[1] & 0x30) != 0; 3025f4f94c7SMatthias Ringwald 3035f4f94c7SMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out); 3045303ddeeSMatthias Ringwald 3052c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3062c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 3072c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 3082c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 3092c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 3102c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 3112c7ae6e1SMatthias Ringwald wav_writer_close(); 3122c7ae6e1SMatthias Ringwald } 3132c7ae6e1SMatthias Ringwald #endif 3142c7ae6e1SMatthias Ringwald 315379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 316fcb08cdbSMilanka Ringwald } 317fcb08cdbSMilanka Ringwald 318*bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){ 3196fb1424bSMatthias Ringwald uint16_t bytes_to_copy = sco_payload_length; 3206fb1424bSMatthias Ringwald 3212b89dbfcSMatthias Ringwald // get data from ringbuffer 3222b89dbfcSMatthias Ringwald uint16_t pos = 0; 323379c5f5fSMatthias Ringwald if (!audio_input_paused){ 3246fb1424bSMatthias Ringwald uint16_t samples_to_copy = sco_payload_length / 2; 3252b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 3266fb1424bSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read); 3278fd6902dSMatthias Ringwald // flip 16 on big endian systems 3288fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 3298fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 3306fb1424bSMatthias Ringwald uint16_t i; 3316fb1424bSMatthias Ringwald for (i=0;i<samples_to_copy/2;i+=2){ 3326fb1424bSMatthias Ringwald uint8_t tmp = payload_buffer[i*2]; 3336fb1424bSMatthias Ringwald payload_buffer[i*2] = payload_buffer[i*2+1]; 3346fb1424bSMatthias Ringwald payload_buffer[i*2+1] = tmp; 3358fd6902dSMatthias Ringwald } 3368fd6902dSMatthias Ringwald } 3372b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 3382b89dbfcSMatthias Ringwald pos += bytes_read; 3392b89dbfcSMatthias Ringwald } 3402b89dbfcSMatthias Ringwald 3412b89dbfcSMatthias Ringwald // fill with 0 if not enough 3422b89dbfcSMatthias Ringwald if (bytes_to_copy){ 3436fb1424bSMatthias Ringwald memset(payload_buffer + pos, 0, bytes_to_copy); 344379c5f5fSMatthias Ringwald audio_input_paused = 1; 3452b89dbfcSMatthias Ringwald } 3462b89dbfcSMatthias Ringwald } 34794381a69SMatthias Ringwald 348*bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){ 349*bf958e42SMatthias 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); 350*bf958e42SMatthias Ringwald } 351*bf958e42SMatthias Ringwald 352*bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = { 353*bf958e42SMatthias Ringwald .init = &sco_demo_cvsd_init, 354*bf958e42SMatthias Ringwald .receive = &sco_demo_cvsd_receive, 355*bf958e42SMatthias Ringwald .fill_payload = &sco_demo_cvsd_fill_payload, 356*bf958e42SMatthias Ringwald .close = &sco_demo_cvsd_close 357*bf958e42SMatthias Ringwald }; 358*bf958e42SMatthias Ringwald 35994381a69SMatthias Ringwald // mSBC - 16 kHz 36094381a69SMatthias Ringwald 36194381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 36294381a69SMatthias Ringwald 36394381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 36494381a69SMatthias Ringwald UNUSED(context); 36594381a69SMatthias Ringwald UNUSED(sample_rate); 36694381a69SMatthias Ringwald UNUSED(data); 36794381a69SMatthias Ringwald UNUSED(num_samples); 36894381a69SMatthias Ringwald UNUSED(num_channels); 36994381a69SMatthias Ringwald 37094381a69SMatthias Ringwald // samples in callback in host endianess, ready for playback 37194381a69SMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 37294381a69SMatthias Ringwald 37394381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME 37494381a69SMatthias Ringwald if (!num_samples_to_write) return; 37594381a69SMatthias Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 37694381a69SMatthias Ringwald num_samples_to_write -= num_samples; 37794381a69SMatthias Ringwald wav_writer_write_int16(num_samples, data); 37894381a69SMatthias Ringwald if (num_samples_to_write == 0){ 37994381a69SMatthias Ringwald wav_writer_close(); 380f7c85330SMatthias Ringwald } 38194381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 3821a919128SMatthias Ringwald } 38394381a69SMatthias Ringwald 384*bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){ 38594381a69SMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 38694381a69SMatthias Ringwald 38794381a69SMatthias Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 38894381a69SMatthias Ringwald hfp_msbc_init(); 38994381a69SMatthias Ringwald 390*bf958e42SMatthias Ringwald audio_prebuffer_bytes = PREBUFFER_BYTES_16KHZ; 391*bf958e42SMatthias Ringwald 392*bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 393*bf958e42SMatthias Ringwald sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_16000_hz_host_endian; 394*bf958e42SMatthias Ringwald #endif 395b150a479SMatthias Ringwald 39694381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME 397b150a479SMatthias Ringwald num_samples_to_write = SAMPLE_RATE_16KHZ * SCO_WAV_DURATION_IN_SECONDS; 398b150a479SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, SAMPLE_RATE_16KHZ); 399f7c85330SMatthias Ringwald #endif 400220eb563SMilanka Ringwald 401b150a479SMatthias Ringwald audio_initialize(SAMPLE_RATE_16KHZ); 40294381a69SMatthias Ringwald } 40394381a69SMatthias Ringwald 404*bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){ 40594381a69SMatthias Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 40694381a69SMatthias Ringwald } 40794381a69SMatthias Ringwald 408*bf958e42SMatthias Ringwald void sco_demo_msbc_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){ 40994381a69SMatthias Ringwald if (!audio_input_paused){ 41094381a69SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 411b89b876fSMatthias Ringwald btstack_assert(num_samples <= MAX_NUM_MSBC_SAMPLES); 41294381a69SMatthias 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)){ 41394381a69SMatthias Ringwald int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES]; 41494381a69SMatthias Ringwald uint32_t bytes_read; 41594381a69SMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 41694381a69SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 41794381a69SMatthias Ringwald num_audio_frames++; 41894381a69SMatthias Ringwald } 419b89b876fSMatthias Ringwald btstack_assert(hfp_msbc_num_bytes_in_stream() >= sco_payload_length); 42094381a69SMatthias Ringwald } 421b89b876fSMatthias Ringwald 422b89b876fSMatthias Ringwald // get data from encoder, fill with 0 if not enough 42394381a69SMatthias Ringwald if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 42494381a69SMatthias Ringwald // just send '0's 42594381a69SMatthias Ringwald memset(payload_buffer, 0, sco_payload_length); 42694381a69SMatthias Ringwald audio_input_paused = 1; 42794381a69SMatthias Ringwald } else { 42894381a69SMatthias Ringwald hfp_msbc_read_from_stream(payload_buffer, sco_payload_length); 42994381a69SMatthias Ringwald } 43094381a69SMatthias Ringwald } 43194381a69SMatthias Ringwald 432*bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){ 433*bf958e42SMatthias 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); 434*bf958e42SMatthias Ringwald } 435*bf958e42SMatthias Ringwald 436*bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = { 437*bf958e42SMatthias Ringwald .init = &sco_demo_msbc_init, 438*bf958e42SMatthias Ringwald .receive = &sco_demo_msbc_receive, 439*bf958e42SMatthias Ringwald .fill_payload = &sco_demo_msbc_fill_payload, 440*bf958e42SMatthias Ringwald .close = &sco_demo_msbc_close 441*bf958e42SMatthias Ringwald }; 442*bf958e42SMatthias Ringwald 44394381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 44494381a69SMatthias Ringwald 44594381a69SMatthias Ringwald void sco_demo_init(void){ 44694381a69SMatthias Ringwald 44794381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS 44894381a69SMatthias Ringwald printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n"); 44994381a69SMatthias Ringwald gap_secure_connections_enable(false); 45094381a69SMatthias Ringwald #endif 45194381a69SMatthias Ringwald 45294381a69SMatthias Ringwald // status 45394381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 45494381a69SMatthias Ringwald printf("SCO Demo: Sending and receiving audio via btstack_audio.\n"); 45594381a69SMatthias Ringwald #endif 45694381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 45794381a69SMatthias Ringwald if (btstack_audio_sink_get_instance()){ 45894381a69SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n"); 45994381a69SMatthias Ringwald } else { 46094381a69SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 46194381a69SMatthias Ringwald } 46294381a69SMatthias Ringwald #endif 46394381a69SMatthias Ringwald 46494381a69SMatthias Ringwald // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode) 46594381a69SMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 46694381a69SMatthias Ringwald } 46794381a69SMatthias Ringwald 468*bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){ 46994381a69SMatthias Ringwald switch (negotiated_codec){ 47094381a69SMatthias Ringwald case HFP_CODEC_CVSD: 471*bf958e42SMatthias Ringwald codec_current = &codec_cvsd; 47294381a69SMatthias Ringwald break; 47394381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 47494381a69SMatthias Ringwald case HFP_CODEC_MSBC: 475*bf958e42SMatthias Ringwald codec_current = &codec_msbc; 47694381a69SMatthias Ringwald break; 47794381a69SMatthias Ringwald #endif 47894381a69SMatthias Ringwald default: 47994381a69SMatthias Ringwald btstack_assert(false); 48094381a69SMatthias Ringwald break; 48194381a69SMatthias Ringwald } 482*bf958e42SMatthias Ringwald 483*bf958e42SMatthias Ringwald codec_current->init(); 48494381a69SMatthias Ringwald } 48594381a69SMatthias Ringwald 48694381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 48794381a69SMatthias Ringwald static uint32_t packets = 0; 48894381a69SMatthias Ringwald static uint32_t crc_errors = 0; 48994381a69SMatthias Ringwald static uint32_t data_received = 0; 49094381a69SMatthias Ringwald static uint32_t byte_errors = 0; 49194381a69SMatthias Ringwald 49294381a69SMatthias Ringwald count_received++; 49394381a69SMatthias Ringwald 49494381a69SMatthias Ringwald data_received += size - 3; 49594381a69SMatthias Ringwald packets++; 49694381a69SMatthias Ringwald if (data_received > 100000){ 49794381a69SMatthias 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); 49894381a69SMatthias Ringwald crc_errors = 0; 49994381a69SMatthias Ringwald byte_errors = 0; 50094381a69SMatthias Ringwald data_received = 0; 50194381a69SMatthias Ringwald packets = 0; 50294381a69SMatthias Ringwald } 50394381a69SMatthias Ringwald 504*bf958e42SMatthias Ringwald codec_current->receive(packet, size); 50594381a69SMatthias Ringwald } 50694381a69SMatthias Ringwald 50794381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 50894381a69SMatthias Ringwald 50994381a69SMatthias Ringwald if (sco_handle == HCI_CON_HANDLE_INVALID) return; 51094381a69SMatthias Ringwald 51194381a69SMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 51294381a69SMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 51394381a69SMatthias Ringwald 51494381a69SMatthias Ringwald hci_reserve_packet_buffer(); 51594381a69SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 51694381a69SMatthias Ringwald 517*bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 518*bf958e42SMatthias Ringwald #define REFILL_SAMPLES 16 519*bf958e42SMatthias Ringwald // re-fill audio buffer 520*bf958e42SMatthias Ringwald uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2; 521*bf958e42SMatthias Ringwald while (samples_free > 0){ 522*bf958e42SMatthias Ringwald int16_t samples_buffer[REFILL_SAMPLES]; 523*bf958e42SMatthias Ringwald uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES); 524*bf958e42SMatthias Ringwald (*sco_demo_audio_generator)(samples_to_add, samples_buffer); 525*bf958e42SMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2); 526*bf958e42SMatthias Ringwald samples_free -= samples_to_add; 52794381a69SMatthias Ringwald } 528*bf958e42SMatthias Ringwald #endif 529*bf958e42SMatthias Ringwald 530*bf958e42SMatthias Ringwald // resume if pre-buffer is filled 531*bf958e42SMatthias Ringwald if (audio_input_paused){ 532*bf958e42SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){ 533*bf958e42SMatthias Ringwald // resume sending 534*bf958e42SMatthias Ringwald audio_input_paused = 0; 535*bf958e42SMatthias Ringwald } 536*bf958e42SMatthias Ringwald } 537*bf958e42SMatthias Ringwald 538*bf958e42SMatthias Ringwald // fill payload by codec 539*bf958e42SMatthias Ringwald codec_current->fill_payload(&sco_packet[3], sco_payload_length); 5402b89dbfcSMatthias Ringwald 541c4e666bcSMatthias Ringwald // set handle + flags 542c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 543c4e666bcSMatthias Ringwald // set len 544c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 545c4e666bcSMatthias Ringwald // finally send packet 546f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 547f7c85330SMatthias Ringwald 548f7c85330SMatthias Ringwald // request another send event 549f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 550f7c85330SMatthias Ringwald 5514a96141eSMatthias Ringwald count_sent++; 55294381a69SMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) { 55394381a69SMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 55494381a69SMatthias Ringwald } 555f7c85330SMatthias Ringwald } 556f7c85330SMatthias Ringwald 55794381a69SMatthias Ringwald void sco_demo_close(void){ 55894381a69SMatthias Ringwald printf("SCO demo close\n"); 5591a919128SMatthias Ringwald 56094381a69SMatthias Ringwald printf("SCO demo statistics: "); 561*bf958e42SMatthias Ringwald codec_current->close(); 562*bf958e42SMatthias Ringwald codec_current = NULL; 56394381a69SMatthias Ringwald 56494381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 56594381a69SMatthias Ringwald wav_writer_close(); 5668b29cfc6SMatthias Ringwald #endif 5678b29cfc6SMatthias Ringwald 56894381a69SMatthias Ringwald audio_terminate(); 569f7c85330SMatthias Ringwald } 570