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 23f7c85330SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24f7c85330SMatthias Ringwald * RINGWALD 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 */ 37*ab2c6ae4SMatthias Ringwald 38*ab2c6ae4SMatthias 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" 47fcb08cdbSMilanka Ringwald #include "btstack_debug.h" 4835fd3fb9SMatthias Ringwald #include "classic/btstack_sbc.h" 4935fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h" 5035fd3fb9SMatthias Ringwald #include "classic/hfp_msbc.h" 5135fd3fb9SMatthias Ringwald #include "classic/hfp.h" 52fcb08cdbSMilanka Ringwald 5335fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 54fbc7c9f2SMilanka Ringwald #include "wav_util.h" 5535fd3fb9SMatthias Ringwald #endif 56fbc7c9f2SMilanka Ringwald 57c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 58c4e666bcSMatthias Ringwald #include <portaudio.h> 59c4e666bcSMatthias Ringwald #include "btstack_ring_buffer.h" 60c4e666bcSMatthias Ringwald #endif 61c4e666bcSMatthias Ringwald 62c4e666bcSMatthias Ringwald 63c4e666bcSMatthias Ringwald // test modes 64f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE 0 65f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII 1 66f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER 2 671a919128SMatthias Ringwald #define SCO_DEMO_MODE_55 3 681a919128SMatthias Ringwald #define SCO_DEMO_MODE_00 4 69463c9c89SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 5 70f7c85330SMatthias Ringwald 71f7c85330SMatthias Ringwald // SCO demo configuration 72fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE 73c4e666bcSMatthias Ringwald 74c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console 75f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 76f7c85330SMatthias 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" 81d4f907a6SMatthias Ringwald #endif 82c4e666bcSMatthias Ringwald 83c4e666bcSMatthias Ringwald // name of sbc test files 84d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 852308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME "sco_input.msbc" 86220eb563SMilanka Ringwald 87c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency 88c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS 50 89c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS 50 908b29cfc6SMatthias Ringwald 91c4e666bcSMatthias Ringwald // constants 92c4e666bcSMatthias Ringwald #define NUM_CHANNELS 1 93c4e666bcSMatthias Ringwald #define CVSD_BYTES_PER_FRAME (2*NUM_CHANNELS) 94c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE 8000 95c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE 16000 96c4e666bcSMatthias Ringwald #define MSBC_BYTES_PER_FRAME (2*NUM_CHANNELS) 97f7c85330SMatthias Ringwald 982b89dbfcSMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE || SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 99f7c85330SMatthias Ringwald #define USE_PORTAUDIO 100c4e666bcSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME) 101c4e666bcSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME) 102f7c85330SMatthias Ringwald #endif 103f7c85330SMatthias Ringwald 104f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 1052b89dbfcSMatthias Ringwald 1062b89dbfcSMatthias Ringwald // bidirectional audio stream 1072b89dbfcSMatthias Ringwald static PaStream * pa_stream; 1082b89dbfcSMatthias Ringwald 1092b89dbfcSMatthias Ringwald // output 110463c9c89SMatthias Ringwald static int pa_output_started = 0; 111463c9c89SMatthias Ringwald static int pa_output_paused = 0; 112463c9c89SMatthias Ringwald static uint8_t pa_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES]; 113463c9c89SMatthias Ringwald static btstack_ring_buffer_t pa_output_ring_buffer; 1142b89dbfcSMatthias Ringwald 1152b89dbfcSMatthias Ringwald // input 1162b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 1172b89dbfcSMatthias Ringwald #define USE_PORTAUDIO_INPUT 1182b89dbfcSMatthias Ringwald static int pa_input_started = 0; 1192b89dbfcSMatthias Ringwald static int pa_input_paused = 0; 1202b89dbfcSMatthias Ringwald static uint8_t pa_input_ring_buffer_storage[2*8000]; // full second input buffer 1212b89dbfcSMatthias Ringwald static btstack_ring_buffer_t pa_input_ring_buffer; 1222b89dbfcSMatthias Ringwald static int pa_input_counter; 1232b89dbfcSMatthias Ringwald #endif 1242b89dbfcSMatthias Ringwald 125f7c85330SMatthias Ringwald #endif 126f7c85330SMatthias Ringwald 127fcb08cdbSMilanka Ringwald static int dump_data = 1; 128fcb08cdbSMilanka Ringwald static int count_sent = 0; 129fcb08cdbSMilanka Ringwald static int count_received = 0; 130c4e666bcSMatthias Ringwald static int negotiated_codec = -1; 131c4e666bcSMatthias Ringwald 1321bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 1332b89dbfcSMatthias Ringwald btstack_sbc_decoder_state_t decoder_state; 1341bbecc2bSMatthias Ringwald #endif 1351bbecc2bSMatthias Ringwald 1362b89dbfcSMatthias Ringwald btstack_cvsd_plc_state_t cvsd_plc_state; 137fcb08cdbSMilanka Ringwald 1381bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 139d5e5f834SMatthias Ringwald FILE * msbc_file_in; 140d5e5f834SMatthias Ringwald FILE * msbc_file_out; 1411bbecc2bSMatthias Ringwald #endif 1427294d009SMatthias Ringwald 1432b89dbfcSMatthias Ringwald int num_samples_to_write; 1442b89dbfcSMatthias Ringwald int num_audio_frames; 1452b89dbfcSMatthias Ringwald int phase; 1462b89dbfcSMatthias Ringwald 147f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 148d6a06398SMatthias Ringwald 14935fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz 150c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 15135fd3fb9SMatthias Ringwald 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 15235fd3fb9SMatthias Ringwald 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 15335fd3fb9SMatthias Ringwald 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 15435fd3fb9SMatthias Ringwald 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 15535fd3fb9SMatthias Ringwald 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 15635fd3fb9SMatthias Ringwald 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 15735fd3fb9SMatthias Ringwald -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 15835fd3fb9SMatthias Ringwald -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 15935fd3fb9SMatthias Ringwald -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 16035fd3fb9SMatthias Ringwald -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 16135fd3fb9SMatthias Ringwald }; 16235fd3fb9SMatthias Ringwald 16359c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian 16459c97ae1SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(int num_samples, int16_t * data){ 16559c97ae1SMatthias Ringwald int i; 16659c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 16759c97ae1SMatthias Ringwald int16_t sample = sine_int16_at_16000hz[phase]; 16859c97ae1SMatthias Ringwald little_endian_store_16((uint8_t *) data, i * 2, sample); 16959c97ae1SMatthias Ringwald // ony use every second sample from 16khz table to get 8khz 17059c97ae1SMatthias Ringwald phase += 2; 171c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 17235fd3fb9SMatthias Ringwald phase = 0; 17335fd3fb9SMatthias Ringwald } 17435fd3fb9SMatthias Ringwald } 17535fd3fb9SMatthias Ringwald } 17635fd3fb9SMatthias Ringwald 1771bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess 1781bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 1791bbecc2bSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(int num_samples, int16_t * data){ 1801bbecc2bSMatthias Ringwald int i; 1811bbecc2bSMatthias Ringwald for (i=0; i < num_samples; i++){ 1821bbecc2bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase++]; 1831bbecc2bSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 1841bbecc2bSMatthias Ringwald phase = 0; 1851bbecc2bSMatthias Ringwald } 1861bbecc2bSMatthias Ringwald } 1871bbecc2bSMatthias Ringwald } 1881bbecc2bSMatthias Ringwald 189b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){ 19035fd3fb9SMatthias Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 19135fd3fb9SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 19235fd3fb9SMatthias Ringwald int16_t sample_buffer[num_samples]; 19359c97ae1SMatthias Ringwald sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer); 19435fd3fb9SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 19535fd3fb9SMatthias Ringwald num_audio_frames++; 19635fd3fb9SMatthias Ringwald } 1972b89dbfcSMatthias Ringwald #endif 1981bbecc2bSMatthias Ringwald #endif 199dbb41bfeSMilanka Ringwald 200dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 201c4e666bcSMatthias Ringwald static int portaudio_callback( const void *inputBuffer, void *outputBuffer, 202dbb41bfeSMilanka Ringwald unsigned long framesPerBuffer, 203dbb41bfeSMilanka Ringwald const PaStreamCallbackTimeInfo* timeInfo, 204dbb41bfeSMilanka Ringwald PaStreamCallbackFlags statusFlags, 205dbb41bfeSMilanka Ringwald void *userData ) { 206dbb41bfeSMilanka Ringwald (void) timeInfo; /* Prevent unused variable warnings. */ 207dbb41bfeSMilanka Ringwald (void) statusFlags; 208dbb41bfeSMilanka Ringwald (void) inputBuffer; 2093963d036SMatthias Ringwald (void) userData; 210dbb41bfeSMilanka Ringwald 2112b89dbfcSMatthias Ringwald // output part 2122b89dbfcSMatthias Ringwald 213c4e666bcSMatthias Ringwald // config based on codec 214c4e666bcSMatthias Ringwald int bytes_to_copy; 215c4e666bcSMatthias Ringwald int prebuffer_bytes; 216c4e666bcSMatthias Ringwald switch (negotiated_codec){ 217c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 218c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * MSBC_BYTES_PER_FRAME; 219c4e666bcSMatthias Ringwald prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES; 220c4e666bcSMatthias Ringwald break; 221c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 222c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * CVSD_BYTES_PER_FRAME; 223c4e666bcSMatthias Ringwald prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES; 224c4e666bcSMatthias Ringwald break; 225c4e666bcSMatthias Ringwald default: 226c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * 2; // assume 1 channel / 16 bit audio samples 227c4e666bcSMatthias Ringwald prebuffer_bytes = 0xfffffff; 228c4e666bcSMatthias Ringwald break; 229dbb41bfeSMilanka Ringwald } 230dbb41bfeSMilanka Ringwald 231c4e666bcSMatthias Ringwald // fill with silence while paused 232463c9c89SMatthias Ringwald if (pa_output_paused){ 233463c9c89SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){ 234c4e666bcSMatthias Ringwald memset(outputBuffer, 0, bytes_to_copy); 235c4e666bcSMatthias Ringwald return 0; 236dbb41bfeSMilanka Ringwald } else { 237c4e666bcSMatthias Ringwald // resume playback 238463c9c89SMatthias Ringwald pa_output_paused = 0; 239dbb41bfeSMilanka Ringwald } 240c4e666bcSMatthias Ringwald } 241c4e666bcSMatthias Ringwald 242c4e666bcSMatthias Ringwald // get data from ringbuffer 243c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 244463c9c89SMatthias Ringwald btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read); 245c4e666bcSMatthias Ringwald bytes_to_copy -= bytes_read; 246c4e666bcSMatthias Ringwald 247c4e666bcSMatthias Ringwald // fill with 0 if not enough 248c4e666bcSMatthias Ringwald if (bytes_to_copy){ 249c4e666bcSMatthias Ringwald memset(outputBuffer + bytes_read, 0, bytes_to_copy); 250463c9c89SMatthias Ringwald pa_output_paused = 1; 251c4e666bcSMatthias Ringwald } 2522b89dbfcSMatthias Ringwald // end of output part 2538b29cfc6SMatthias Ringwald 2542b89dbfcSMatthias Ringwald // input part -- just store in ring buffer 2552b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 2562b89dbfcSMatthias Ringwald btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2); 2572b89dbfcSMatthias Ringwald pa_input_counter += framesPerBuffer * 2; 2582b89dbfcSMatthias Ringwald #endif 2592b89dbfcSMatthias Ringwald 2602b89dbfcSMatthias Ringwald return 0; 261c4e666bcSMatthias Ringwald } 262c4e666bcSMatthias Ringwald 263c4e666bcSMatthias Ringwald // return 1 if ok 264c4e666bcSMatthias Ringwald static int portaudio_initialize(int sample_rate){ 265c4e666bcSMatthias Ringwald PaError err; 266c4e666bcSMatthias Ringwald 267c4e666bcSMatthias Ringwald /* -- initialize PortAudio -- */ 268c4e666bcSMatthias Ringwald printf("PortAudio: Initialize\n"); 269c4e666bcSMatthias Ringwald err = Pa_Initialize(); 270c4e666bcSMatthias Ringwald if( err != paNoError ) return 0; 2712b89dbfcSMatthias Ringwald 272c4e666bcSMatthias Ringwald /* -- setup input and output -- */ 2732b89dbfcSMatthias Ringwald const PaDeviceInfo *deviceInfo; 2742b89dbfcSMatthias Ringwald PaStreamParameters * inputParameters = NULL; 2752b89dbfcSMatthias Ringwald PaStreamParameters outputParameters; 276c4e666bcSMatthias Ringwald outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 277c4e666bcSMatthias Ringwald outputParameters.channelCount = NUM_CHANNELS; 278c4e666bcSMatthias Ringwald outputParameters.sampleFormat = paInt16; 279c4e666bcSMatthias Ringwald outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 280c4e666bcSMatthias Ringwald outputParameters.hostApiSpecificStreamInfo = NULL; 2812b89dbfcSMatthias Ringwald deviceInfo = Pa_GetDeviceInfo( outputParameters.device ); 2822b89dbfcSMatthias Ringwald log_info("PortAudio: Output device: %s", deviceInfo->name); 2832b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 2842b89dbfcSMatthias Ringwald PaStreamParameters theInputParameters; 2852b89dbfcSMatthias Ringwald theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ 2862b89dbfcSMatthias Ringwald theInputParameters.channelCount = NUM_CHANNELS; 2872b89dbfcSMatthias Ringwald theInputParameters.sampleFormat = paInt16; 2882b89dbfcSMatthias Ringwald theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighOutputLatency; 2892b89dbfcSMatthias Ringwald theInputParameters.hostApiSpecificStreamInfo = NULL; 2902b89dbfcSMatthias Ringwald inputParameters = &theInputParameters; 2912b89dbfcSMatthias Ringwald deviceInfo = Pa_GetDeviceInfo( inputParameters->device ); 2922b89dbfcSMatthias Ringwald log_info("PortAudio: Input device: %s", deviceInfo->name); 2932b89dbfcSMatthias Ringwald #endif 2942b89dbfcSMatthias Ringwald 2952b89dbfcSMatthias Ringwald /* -- setup output stream -- */ 296c4e666bcSMatthias Ringwald printf("PortAudio: Open stream\n"); 297c4e666bcSMatthias Ringwald err = Pa_OpenStream( 2982b89dbfcSMatthias Ringwald &pa_stream, 2992b89dbfcSMatthias Ringwald inputParameters, 300c4e666bcSMatthias Ringwald &outputParameters, 301c4e666bcSMatthias Ringwald sample_rate, 302c4e666bcSMatthias Ringwald 0, 303c4e666bcSMatthias Ringwald paClipOff, /* we won't output out of range samples so don't bother clipping them */ 304c4e666bcSMatthias Ringwald portaudio_callback, 305c4e666bcSMatthias Ringwald NULL ); 306c4e666bcSMatthias Ringwald if (err != paNoError){ 307c4e666bcSMatthias Ringwald printf("Error opening portaudio stream: \"%s\"\n", Pa_GetErrorText(err)); 308c4e666bcSMatthias Ringwald return 0; 309c4e666bcSMatthias Ringwald } 310463c9c89SMatthias Ringwald memset(pa_output_ring_buffer_storage, 0, sizeof(pa_output_ring_buffer_storage)); 311463c9c89SMatthias Ringwald btstack_ring_buffer_init(&pa_output_ring_buffer, pa_output_ring_buffer_storage, sizeof(pa_output_ring_buffer_storage)); 3122b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 3132b89dbfcSMatthias Ringwald memset(pa_input_ring_buffer_storage, 0, sizeof(pa_input_ring_buffer_storage)); 3142b89dbfcSMatthias Ringwald btstack_ring_buffer_init(&pa_input_ring_buffer, pa_input_ring_buffer_storage, sizeof(pa_input_ring_buffer_storage)); 3152b89dbfcSMatthias Ringwald printf("PortAudio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&pa_input_ring_buffer)); 3162b89dbfcSMatthias Ringwald #endif 3172b89dbfcSMatthias Ringwald 3182b89dbfcSMatthias Ringwald /* -- start stream -- */ 3192b89dbfcSMatthias Ringwald err = Pa_StartStream(pa_stream); 3202b89dbfcSMatthias Ringwald if (err != paNoError){ 3212b89dbfcSMatthias Ringwald printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); 3222b89dbfcSMatthias Ringwald return 0; 3232b89dbfcSMatthias Ringwald } 3242b89dbfcSMatthias Ringwald pa_output_started = 1; 3252b89dbfcSMatthias Ringwald pa_output_paused = 1; 3262b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 3272b89dbfcSMatthias Ringwald pa_input_started = 1; 3282b89dbfcSMatthias Ringwald pa_input_paused = 1; 3292b89dbfcSMatthias Ringwald #endif 3302b89dbfcSMatthias Ringwald 331c4e666bcSMatthias Ringwald return 1; 332c4e666bcSMatthias Ringwald } 3332b89dbfcSMatthias Ringwald 3342b89dbfcSMatthias Ringwald static void portaudio_terminate(void){ 3352b89dbfcSMatthias Ringwald if (!pa_stream) return; 3362b89dbfcSMatthias Ringwald 3372b89dbfcSMatthias Ringwald PaError err; 3382b89dbfcSMatthias Ringwald printf("PortAudio: Stop Stream\n"); 3392b89dbfcSMatthias Ringwald err = Pa_StopStream(pa_stream); 3402b89dbfcSMatthias Ringwald if (err != paNoError){ 3412b89dbfcSMatthias Ringwald printf("Error stopping the stream: \"%s\"\n", Pa_GetErrorText(err)); 3422b89dbfcSMatthias Ringwald return; 3432b89dbfcSMatthias Ringwald } 3442b89dbfcSMatthias Ringwald printf("PortAudio: Close Stream\n"); 3452b89dbfcSMatthias Ringwald err = Pa_CloseStream(pa_stream); 3462b89dbfcSMatthias Ringwald if (err != paNoError){ 3472b89dbfcSMatthias Ringwald printf("Error closing the stream: \"%s\"\n", Pa_GetErrorText(err)); 3482b89dbfcSMatthias Ringwald return; 3492b89dbfcSMatthias Ringwald } 3502b89dbfcSMatthias Ringwald pa_stream = NULL; 3512b89dbfcSMatthias Ringwald printf("PortAudio: Terminate\n"); 3522b89dbfcSMatthias Ringwald err = Pa_Terminate(); 3532b89dbfcSMatthias Ringwald if (err != paNoError){ 3542b89dbfcSMatthias Ringwald printf("Error terminating portaudio: \"%s\"\n", Pa_GetErrorText(err)); 3552b89dbfcSMatthias Ringwald return; 3562b89dbfcSMatthias Ringwald } 3572b89dbfcSMatthias Ringwald } 358c4e666bcSMatthias Ringwald #endif 359c4e666bcSMatthias Ringwald 3602c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 361c4e666bcSMatthias Ringwald 3621bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 363c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 364c4e666bcSMatthias Ringwald UNUSED(context); 365c4e666bcSMatthias Ringwald UNUSED(sample_rate); 3662c7ae6e1SMatthias Ringwald UNUSED(data); 3672c7ae6e1SMatthias Ringwald UNUSED(num_samples); 3682c7ae6e1SMatthias Ringwald UNUSED(num_channels); 3692c7ae6e1SMatthias Ringwald 3702c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 371c4e666bcSMatthias Ringwald 372c4e666bcSMatthias Ringwald // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); 373c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 3745303ddeeSMatthias Ringwald // samples in callback in host endianess, ready for PortAudio playback 375463c9c89SMatthias Ringwald btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 3761bbecc2bSMatthias Ringwald #endif /* HAVE_PORTAUDIO */ 377dbb41bfeSMilanka Ringwald 3782c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 379fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 380fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 381fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 382fbc7c9f2SMilanka Ringwald wav_writer_write_int16(num_samples, data); 383fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 3842c7ae6e1SMatthias Ringwald wav_writer_close(); 385fcb08cdbSMilanka Ringwald } 3861bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 3872c7ae6e1SMatthias Ringwald 3881bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */ 389fcb08cdbSMilanka Ringwald } 3901bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 3911bbecc2bSMatthias Ringwald 3921bbecc2bSMatthias Ringwald 3931bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 394fcb08cdbSMilanka Ringwald 395fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 396c4e666bcSMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 397c4e666bcSMatthias Ringwald 398fbc7c9f2SMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 399220eb563SMilanka Ringwald hfp_msbc_init(); 4002c7ae6e1SMatthias Ringwald 4012c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 4022c7ae6e1SMatthias Ringwald num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 4032c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE); 4042c7ae6e1SMatthias Ringwald #endif 4052c7ae6e1SMatthias Ringwald 4062b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 407b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 4082b89dbfcSMatthias Ringwald #endif 409973d7173SMatthias Ringwald 410d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME 411d5e5f834SMatthias Ringwald msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 412d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 413d5e5f834SMatthias Ringwald #endif 4142b89dbfcSMatthias Ringwald 4157294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 416d5e5f834SMatthias Ringwald msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 417d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 4187294d009SMatthias Ringwald #endif 419dbb41bfeSMilanka Ringwald 420dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 421c4e666bcSMatthias Ringwald portaudio_initialize(MSBC_SAMPLE_RATE); 422dbb41bfeSMilanka Ringwald #endif 423fcb08cdbSMilanka Ringwald } 424fcb08cdbSMilanka Ringwald 425fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 426fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 427d5e5f834SMatthias Ringwald if (msbc_file_in){ 428d5e5f834SMatthias Ringwald // log incoming mSBC data for testing 429d5e5f834SMatthias Ringwald fwrite(packet+3, size-3, 1, msbc_file_in); 430d5e5f834SMatthias Ringwald } 431fcb08cdbSMilanka Ringwald } 432dbb41bfeSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 433fcb08cdbSMilanka Ringwald } 4341bbecc2bSMatthias Ringwald #endif 435fcb08cdbSMilanka Ringwald 436fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){ 437c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 438c4e666bcSMatthias Ringwald 439d4f907a6SMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO) 440fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 441d4f907a6SMatthias Ringwald #endif 442c4e666bcSMatthias Ringwald 4432c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 444c4e666bcSMatthias Ringwald num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 4452c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE); 4462c7ae6e1SMatthias Ringwald #endif 447dbb41bfeSMilanka Ringwald 448dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 449c4e666bcSMatthias Ringwald portaudio_initialize(CVSD_SAMPLE_RATE); 450dbb41bfeSMilanka Ringwald #endif 451fbc7c9f2SMilanka Ringwald } 452fbc7c9f2SMilanka Ringwald 453fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 454dbb41bfeSMilanka Ringwald if (!num_samples_to_write) return; 4552c7ae6e1SMatthias Ringwald 4565303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 4571f8694ccSMatthias Ringwald 4581f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 4591f8694ccSMatthias Ringwald printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); 4601f8694ccSMatthias Ringwald return; 4611f8694ccSMatthias Ringwald } 4622c7ae6e1SMatthias Ringwald 463c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 464c4e666bcSMatthias Ringwald const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME; 4655303ddeeSMatthias Ringwald 4665303ddeeSMatthias Ringwald // convert into host endian 4675303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 4685303ddeeSMatthias Ringwald int i; 4695303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 4705303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 4715303ddeeSMatthias Ringwald } 4725303ddeeSMatthias Ringwald 473d4f907a6SMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO) 474e36764ddSMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out); 475d4f907a6SMatthias Ringwald #endif 4765303ddeeSMatthias Ringwald 4772c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 4782c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 4792c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 4802c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 4812c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 4822c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 4832c7ae6e1SMatthias Ringwald wav_writer_close(); 4842c7ae6e1SMatthias Ringwald } 4852c7ae6e1SMatthias Ringwald #endif 4862c7ae6e1SMatthias Ringwald 487dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 488463c9c89SMatthias Ringwald btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 489dbb41bfeSMilanka Ringwald #endif 490fcb08cdbSMilanka Ringwald } 491fcb08cdbSMilanka Ringwald 4922c7ae6e1SMatthias Ringwald #endif 4932c7ae6e1SMatthias Ringwald 4942c7ae6e1SMatthias Ringwald 495fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 496c4e666bcSMatthias Ringwald printf("SCO demo close\n"); 4972b89dbfcSMatthias Ringwald 49826463303SMilanka Ringwald printf("SCO demo statistics: "); 4991bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 50026463303SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 5012c7ae6e1SMatthias 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); 5021bbecc2bSMatthias Ringwald } else 5031bbecc2bSMatthias Ringwald #endif 5041bbecc2bSMatthias Ringwald { 5052c7ae6e1SMatthias 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); 50626463303SMilanka Ringwald } 50726463303SMilanka Ringwald 5082c7ae6e1SMatthias Ringwald negotiated_codec = -1; 5092c7ae6e1SMatthias Ringwald 5102c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 5112c7ae6e1SMatthias Ringwald 5122c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 5132c7ae6e1SMatthias Ringwald wav_writer_close(); 5142c7ae6e1SMatthias Ringwald #endif 5152c7ae6e1SMatthias Ringwald 516dbb41bfeSMilanka Ringwald #ifdef HAVE_PORTAUDIO 5172b89dbfcSMatthias Ringwald portaudio_terminate(); 518dbb41bfeSMilanka Ringwald #endif 519fcb08cdbSMilanka Ringwald 520fcb08cdbSMilanka Ringwald #endif 521fcb08cdbSMilanka Ringwald } 522fcb08cdbSMilanka Ringwald 523fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 524fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 525fcb08cdbSMilanka Ringwald negotiated_codec = codec; 5262c7ae6e1SMatthias Ringwald 5272b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 528220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 5291bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 530fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 5311bbecc2bSMatthias Ringwald #endif 532fcb08cdbSMilanka Ringwald } else { 533fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 534fcb08cdbSMilanka Ringwald } 535fcb08cdbSMilanka Ringwald #endif 536fcb08cdbSMilanka Ringwald } 537fcb08cdbSMilanka Ringwald 538f7c85330SMatthias Ringwald void sco_demo_init(void){ 539f7c85330SMatthias Ringwald // status 5402b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 5412b89dbfcSMatthias Ringwald printf("SCO Demo: Sending and receiving audio via portaudio.\n"); 5422b89dbfcSMatthias Ringwald #endif 543f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 544f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 545f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 546f7c85330SMatthias Ringwald #else 547f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 548f7c85330SMatthias Ringwald #endif 549f7c85330SMatthias Ringwald #endif 550f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 551f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 552f7c85330SMatthias Ringwald #endif 553f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 554f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 555f7c85330SMatthias Ringwald #endif 556f7c85330SMatthias Ringwald 5572b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 558c4e666bcSMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 559c4e666bcSMatthias Ringwald #else 560f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 5617294d009SMatthias Ringwald #endif 562f7c85330SMatthias Ringwald 563f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 564f7c85330SMatthias Ringwald phase = 'a'; 565f7c85330SMatthias Ringwald #endif 566f7c85330SMatthias Ringwald } 567f7c85330SMatthias Ringwald 5681a919128SMatthias Ringwald void sco_report(void); 5691a919128SMatthias Ringwald void sco_report(void){ 5704a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 5714a96141eSMatthias Ringwald } 572f7c85330SMatthias Ringwald 573f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 574f7c85330SMatthias Ringwald 575f7c85330SMatthias Ringwald if (!sco_handle) return; 576f7c85330SMatthias Ringwald 577c4e666bcSMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 578c4e666bcSMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 579f7c85330SMatthias Ringwald 580f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 581f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 582f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 5831bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 584220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 585c4e666bcSMatthias Ringwald // overwrite 586c4e666bcSMatthias Ringwald sco_payload_length = 24; 587c4e666bcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 588c4e666bcSMatthias Ringwald 589220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 590220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 591220eb563SMilanka Ringwald } 592220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 593d5e5f834SMatthias Ringwald if (msbc_file_out){ 594d76591efSMatthias Ringwald // log outgoing mSBC data for testing 595d5e5f834SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 596d76591efSMatthias Ringwald } 5977294d009SMatthias Ringwald 598b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 5991bbecc2bSMatthias Ringwald } else 6001bbecc2bSMatthias Ringwald #endif 6011bbecc2bSMatthias Ringwald { 602c4e666bcSMatthias Ringwald const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME; 60359c97ae1SMatthias Ringwald sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, (int16_t *) (sco_packet+3)); 604220eb563SMilanka Ringwald } 6051a919128SMatthias Ringwald #endif 6062b89dbfcSMatthias Ringwald 6072b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 6082b89dbfcSMatthias Ringwald 6092b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 6102b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 6112b89dbfcSMatthias Ringwald // MSBC 6122b89dbfcSMatthias Ringwald 6132b89dbfcSMatthias Ringwald // overwrite 6142b89dbfcSMatthias Ringwald sco_payload_length = 24; 6152b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 6162b89dbfcSMatthias Ringwald 617b025eb5fSMatthias Ringwald if (pa_input_paused){ 618b025eb5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ 619b025eb5fSMatthias Ringwald // resume sending 620b025eb5fSMatthias Ringwald pa_input_paused = 0; 6212b89dbfcSMatthias Ringwald } 622b025eb5fSMatthias Ringwald } 623b025eb5fSMatthias Ringwald 624b025eb5fSMatthias Ringwald if (!pa_input_paused){ 625b025eb5fSMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 626b025eb5fSMatthias Ringwald if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){ 627b025eb5fSMatthias Ringwald int16_t sample_buffer[num_samples]; 628b025eb5fSMatthias Ringwald uint32_t bytes_read; 629b025eb5fSMatthias Ringwald btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read); 630b025eb5fSMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 631b025eb5fSMatthias Ringwald num_audio_frames++; 632b025eb5fSMatthias Ringwald } 633b025eb5fSMatthias Ringwald } 634b025eb5fSMatthias Ringwald 635b025eb5fSMatthias Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 636b025eb5fSMatthias Ringwald log_error("mSBC stream should not be empty."); 637b025eb5fSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 638b025eb5fSMatthias Ringwald pa_input_paused = 1; 639b025eb5fSMatthias Ringwald } else { 6402b89dbfcSMatthias Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 6412b89dbfcSMatthias Ringwald if (msbc_file_out){ 6422b89dbfcSMatthias Ringwald // log outgoing mSBC data for testing 6432b89dbfcSMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 6442b89dbfcSMatthias Ringwald } 645b025eb5fSMatthias Ringwald } 6462b89dbfcSMatthias Ringwald 6472b89dbfcSMatthias Ringwald } else { 6482b89dbfcSMatthias Ringwald // CVSD 6492b89dbfcSMatthias Ringwald 6502b89dbfcSMatthias Ringwald log_info("send: bytes avail %u, free %u, counter %u", btstack_ring_buffer_bytes_available(&pa_input_ring_buffer), btstack_ring_buffer_bytes_free(&pa_input_ring_buffer), pa_input_counter); 6512b89dbfcSMatthias Ringwald // fill with silence while paused 6522b89dbfcSMatthias Ringwald int bytes_to_copy = sco_payload_length; 6532b89dbfcSMatthias Ringwald if (pa_input_paused){ 6542b89dbfcSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ 6552b89dbfcSMatthias Ringwald // resume sending 6562b89dbfcSMatthias Ringwald pa_input_paused = 0; 6572b89dbfcSMatthias Ringwald } 6582b89dbfcSMatthias Ringwald } 6592b89dbfcSMatthias Ringwald 6602b89dbfcSMatthias Ringwald // get data from ringbuffer 6612b89dbfcSMatthias Ringwald uint16_t pos = 0; 6628fd6902dSMatthias Ringwald uint8_t * sample_data = &sco_packet[3]; 6632b89dbfcSMatthias Ringwald if (!pa_input_paused){ 6642b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 6658fd6902dSMatthias Ringwald btstack_ring_buffer_read(&pa_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read); 6668fd6902dSMatthias Ringwald // flip 16 on big endian systems 6678fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 6688fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 6698fd6902dSMatthias Ringwald int i; 6708fd6902dSMatthias Ringwald for (i=0;i<bytes_read;i+=2){ 6718fd6902dSMatthias Ringwald uint8_t tmp = sample_data[i*2]; 6728fd6902dSMatthias Ringwald sample_data[i*2] = sample_data[i*2+1]; 6738fd6902dSMatthias Ringwald sample_data[i*2+1] = tmp; 6748fd6902dSMatthias Ringwald } 6758fd6902dSMatthias Ringwald } 6762b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 6772b89dbfcSMatthias Ringwald pos += bytes_read; 6782b89dbfcSMatthias Ringwald } 6792b89dbfcSMatthias Ringwald 6802b89dbfcSMatthias Ringwald // fill with 0 if not enough 6812b89dbfcSMatthias Ringwald if (bytes_to_copy){ 6828fd6902dSMatthias Ringwald memset(sample_data + pos, 0, bytes_to_copy); 6832b89dbfcSMatthias Ringwald pa_input_paused = 1; 6842b89dbfcSMatthias Ringwald } 6852b89dbfcSMatthias Ringwald } 6862b89dbfcSMatthias Ringwald #else 6872b89dbfcSMatthias Ringwald // just send '0's 6882b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 6892b89dbfcSMatthias Ringwald sco_payload_length = 24; 6902b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 6912b89dbfcSMatthias Ringwald } 6922b89dbfcSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 6932b89dbfcSMatthias Ringwald #endif 6942b89dbfcSMatthias Ringwald #endif 6952b89dbfcSMatthias Ringwald 696f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 697c4e666bcSMatthias Ringwald memset(&sco_packet[3], phase++, sco_payload_length); 698f7c85330SMatthias Ringwald if (phase > 'z') phase = 'a'; 6991a919128SMatthias Ringwald #endif 7001a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 70138b2eaafSMatthias Ringwald int j; 702c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 70338b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 704f7c85330SMatthias Ringwald } 705f7c85330SMatthias Ringwald #endif 7061a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 7071a919128SMatthias Ringwald int j; 708c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 7091a919128SMatthias Ringwald // sco_packet[3+j] = j & 1 ? 0x35 : 0x53; 7101a919128SMatthias Ringwald sco_packet[3+j] = 0x55; 7111a919128SMatthias Ringwald } 7121a919128SMatthias Ringwald #endif 7131a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00 7141a919128SMatthias Ringwald int j; 715c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 7161a919128SMatthias Ringwald sco_packet[3+j] = 0x00; 7171a919128SMatthias Ringwald } 7181a919128SMatthias Ringwald // additional hack 7191a919128SMatthias Ringwald // big_endian_store_16(sco_packet, 5, phase++); 7201a919128SMatthias Ringwald (void) phase; 721f7c85330SMatthias Ringwald #endif 722220eb563SMilanka Ringwald 7232b89dbfcSMatthias Ringwald // test silence 7242b89dbfcSMatthias Ringwald // memset(sco_packet+3, 0, sco_payload_length); 7252b89dbfcSMatthias Ringwald 726c4e666bcSMatthias Ringwald // set handle + flags 727c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 728c4e666bcSMatthias Ringwald // set len 729c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 730c4e666bcSMatthias Ringwald // finally send packet 731f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 732f7c85330SMatthias Ringwald 733f7c85330SMatthias Ringwald // request another send event 734f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 735f7c85330SMatthias Ringwald 7364a96141eSMatthias Ringwald count_sent++; 7371a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55 7384a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 7391a919128SMatthias Ringwald #endif 740f7c85330SMatthias Ringwald } 741f7c85330SMatthias Ringwald 742f7c85330SMatthias Ringwald /** 743f7c85330SMatthias Ringwald * @brief Process received data 744f7c85330SMatthias Ringwald */ 7451a919128SMatthias Ringwald #define ANSI_COLOR_RED "\x1b[31m" 7461a919128SMatthias Ringwald #define ANSI_COLOR_GREEN "\x1b[32m" 7471a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW "\x1b[33m" 7481a919128SMatthias Ringwald #define ANSI_COLOR_BLUE "\x1b[34m" 7491a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m" 7501a919128SMatthias Ringwald #define ANSI_COLOR_CYAN "\x1b[36m" 7511a919128SMatthias Ringwald #define ANSI_COLOR_RESET "\x1b[0m" 7521a919128SMatthias Ringwald 753f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 754f7c85330SMatthias Ringwald 755fcb08cdbSMilanka Ringwald dump_data = 1; 7568b29cfc6SMatthias Ringwald 7574a96141eSMatthias Ringwald count_received++; 7581a919128SMatthias Ringwald static uint32_t packets = 0; 7591a919128SMatthias Ringwald static uint32_t crc_errors = 0; 7601a919128SMatthias Ringwald static uint32_t data_received = 0; 7611a919128SMatthias Ringwald static uint32_t byte_errors = 0; 7624a96141eSMatthias Ringwald 7631a919128SMatthias Ringwald data_received += size - 3; 7641a919128SMatthias Ringwald packets++; 7651a919128SMatthias Ringwald if (data_received > 100000){ 766d4f907a6SMatthias 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); 7671a919128SMatthias Ringwald crc_errors = 0; 7681a919128SMatthias Ringwald byte_errors = 0; 7691a919128SMatthias Ringwald data_received = 0; 7701a919128SMatthias Ringwald packets = 0; 7711a919128SMatthias Ringwald } 7724a96141eSMatthias Ringwald 7732b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 774c4e666bcSMatthias Ringwald switch (negotiated_codec){ 7751bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 776c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 777fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 778c4e666bcSMatthias Ringwald break; 7791bbecc2bSMatthias Ringwald #endif 780c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 781fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 782c4e666bcSMatthias Ringwald break; 783c4e666bcSMatthias Ringwald default: 784c4e666bcSMatthias Ringwald break; 7858b29cfc6SMatthias Ringwald } 786dbb41bfeSMilanka Ringwald dump_data = 0; 7878b29cfc6SMatthias Ringwald #endif 7888b29cfc6SMatthias Ringwald 789b3f76298SMilanka Ringwald if (packet[1] & 0x30){ 7901a919128SMatthias Ringwald crc_errors++; 7911a919128SMatthias Ringwald // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 7921a919128SMatthias Ringwald // printf_hexdump(&packet[3], size-3); 793f7c85330SMatthias Ringwald return; 794f7c85330SMatthias Ringwald } 7958b29cfc6SMatthias Ringwald if (dump_data){ 796f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 7971a919128SMatthias Ringwald printf("data: "); 798f7c85330SMatthias Ringwald int i; 799f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 800f7c85330SMatthias Ringwald printf("%c", packet[i]); 801f7c85330SMatthias Ringwald } 802f7c85330SMatthias Ringwald printf("\n"); 8038b29cfc6SMatthias Ringwald dump_data = 0; 8041a919128SMatthias Ringwald #endif 8051a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 8061a919128SMatthias Ringwald // colored hexdump with expected 8071a919128SMatthias Ringwald static uint8_t expected_byte = 0; 8081a919128SMatthias Ringwald int i; 8091a919128SMatthias Ringwald printf("data: "); 8101a919128SMatthias Ringwald for (i=3;i<size;i++){ 8111a919128SMatthias Ringwald if (packet[i] != expected_byte){ 8121a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 8131a919128SMatthias Ringwald } else { 8141a919128SMatthias Ringwald printf("%02x ", packet[i]); 8151a919128SMatthias Ringwald } 8161a919128SMatthias Ringwald expected_byte = packet[i]+1; 8171a919128SMatthias Ringwald } 8181a919128SMatthias Ringwald printf("\n"); 8191a919128SMatthias Ringwald #endif 820a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00 8211a919128SMatthias Ringwald int i; 8221a919128SMatthias Ringwald int contains_error = 0; 8231a919128SMatthias Ringwald for (i=3;i<size;i++){ 8241a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 8251a919128SMatthias Ringwald contains_error = 1; 8261a919128SMatthias Ringwald byte_errors++; 8271a919128SMatthias Ringwald } 8281a919128SMatthias Ringwald } 8291a919128SMatthias Ringwald if (contains_error){ 8301a919128SMatthias Ringwald printf("data: "); 8311a919128SMatthias Ringwald for (i=0;i<3;i++){ 8321a919128SMatthias Ringwald printf("%02x ", packet[i]); 8331a919128SMatthias Ringwald } 8341a919128SMatthias Ringwald for (i=3;i<size;i++){ 8351a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 8361a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 8371a919128SMatthias Ringwald } else { 8381a919128SMatthias Ringwald printf("%02x ", packet[i]); 8391a919128SMatthias Ringwald } 8401a919128SMatthias Ringwald } 8411a919128SMatthias Ringwald printf("\n"); 8421a919128SMatthias Ringwald } 843f7c85330SMatthias Ringwald #endif 8448b29cfc6SMatthias Ringwald } 845f7c85330SMatthias Ringwald } 846