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 */ 37f7c85330SMatthias Ringwald 38f7c85330SMatthias Ringwald /* 39f7c85330SMatthias Ringwald * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo 40f7c85330SMatthias Ringwald */ 41f7c85330SMatthias Ringwald 422ec72fbbSMilanka Ringwald #include <stdio.h> 432ec72fbbSMilanka Ringwald 44f7c85330SMatthias Ringwald #include "sco_demo_util.h" 45fcb08cdbSMilanka Ringwald #include "btstack_debug.h" 4635fd3fb9SMatthias Ringwald #include "classic/btstack_sbc.h" 4735fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h" 4835fd3fb9SMatthias Ringwald #include "classic/hfp_msbc.h" 4935fd3fb9SMatthias Ringwald #include "classic/hfp.h" 50fcb08cdbSMilanka Ringwald 5135fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 52fbc7c9f2SMilanka Ringwald #include "wav_util.h" 5335fd3fb9SMatthias Ringwald #endif 54fbc7c9f2SMilanka Ringwald 55c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 56c4e666bcSMatthias Ringwald #include <portaudio.h> 57c4e666bcSMatthias Ringwald #include "btstack_ring_buffer.h" 58c4e666bcSMatthias Ringwald #endif 59c4e666bcSMatthias Ringwald 60c4e666bcSMatthias Ringwald 61c4e666bcSMatthias Ringwald // test modes 62f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE 0 63f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII 1 64f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER 2 651a919128SMatthias Ringwald #define SCO_DEMO_MODE_55 3 661a919128SMatthias Ringwald #define SCO_DEMO_MODE_00 4 67463c9c89SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 5 68f7c85330SMatthias Ringwald 69f7c85330SMatthias Ringwald // SCO demo configuration 70fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE 71c4e666bcSMatthias Ringwald 72c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console 73f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 74f7c85330SMatthias Ringwald 75*d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 762c7ae6e1SMatthias Ringwald // length and name of wav file on disk 77c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15 788b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 79*d4f907a6SMatthias Ringwald #endif 80c4e666bcSMatthias Ringwald 81c4e666bcSMatthias Ringwald // name of sbc test files 82d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 832308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME "sco_input.msbc" 84220eb563SMilanka Ringwald 85c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency 86c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS 50 87c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS 50 888b29cfc6SMatthias Ringwald 89c4e666bcSMatthias Ringwald // constants 90c4e666bcSMatthias Ringwald #define NUM_CHANNELS 1 91c4e666bcSMatthias Ringwald #define CVSD_BYTES_PER_FRAME (2*NUM_CHANNELS) 92c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE 8000 93c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE 16000 94c4e666bcSMatthias Ringwald #define MSBC_BYTES_PER_FRAME (2*NUM_CHANNELS) 95f7c85330SMatthias Ringwald 962b89dbfcSMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE || SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 97f7c85330SMatthias Ringwald #define USE_PORTAUDIO 98c4e666bcSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME) 99c4e666bcSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME) 100f7c85330SMatthias Ringwald #endif 101f7c85330SMatthias Ringwald 102f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 1032b89dbfcSMatthias Ringwald 1042b89dbfcSMatthias Ringwald // bidirectional audio stream 1052b89dbfcSMatthias Ringwald static PaStream * pa_stream; 1062b89dbfcSMatthias Ringwald 1072b89dbfcSMatthias Ringwald // output 108463c9c89SMatthias Ringwald static int pa_output_started = 0; 109463c9c89SMatthias Ringwald static int pa_output_paused = 0; 110463c9c89SMatthias Ringwald static uint8_t pa_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES]; 111463c9c89SMatthias Ringwald static btstack_ring_buffer_t pa_output_ring_buffer; 1122b89dbfcSMatthias Ringwald 1132b89dbfcSMatthias Ringwald // input 1142b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 1152b89dbfcSMatthias Ringwald #define USE_PORTAUDIO_INPUT 1162b89dbfcSMatthias Ringwald static int pa_input_started = 0; 1172b89dbfcSMatthias Ringwald static int pa_input_paused = 0; 1182b89dbfcSMatthias Ringwald static uint8_t pa_input_ring_buffer_storage[2*8000]; // full second input buffer 1192b89dbfcSMatthias Ringwald static btstack_ring_buffer_t pa_input_ring_buffer; 1202b89dbfcSMatthias Ringwald static int pa_input_counter; 1212b89dbfcSMatthias Ringwald #endif 1222b89dbfcSMatthias Ringwald 123f7c85330SMatthias Ringwald #endif 124f7c85330SMatthias Ringwald 125fcb08cdbSMilanka Ringwald static int dump_data = 1; 126fcb08cdbSMilanka Ringwald static int count_sent = 0; 127fcb08cdbSMilanka Ringwald static int count_received = 0; 128c4e666bcSMatthias Ringwald static int negotiated_codec = -1; 129c4e666bcSMatthias Ringwald 1302b89dbfcSMatthias Ringwald btstack_sbc_decoder_state_t decoder_state; 1312b89dbfcSMatthias Ringwald btstack_cvsd_plc_state_t cvsd_plc_state; 132fcb08cdbSMilanka Ringwald 133d5e5f834SMatthias Ringwald FILE * msbc_file_in; 134d5e5f834SMatthias Ringwald FILE * msbc_file_out; 1357294d009SMatthias Ringwald 1362b89dbfcSMatthias Ringwald int num_samples_to_write; 1372b89dbfcSMatthias Ringwald int num_audio_frames; 1382b89dbfcSMatthias Ringwald int phase; 1392b89dbfcSMatthias Ringwald 140f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 141d6a06398SMatthias Ringwald 14235fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz 143c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 14435fd3fb9SMatthias Ringwald 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 14535fd3fb9SMatthias Ringwald 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 14635fd3fb9SMatthias Ringwald 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 14735fd3fb9SMatthias Ringwald 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 14835fd3fb9SMatthias Ringwald 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 14935fd3fb9SMatthias Ringwald 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 15035fd3fb9SMatthias Ringwald -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 15135fd3fb9SMatthias Ringwald -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 15235fd3fb9SMatthias Ringwald -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 15335fd3fb9SMatthias Ringwald -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 15435fd3fb9SMatthias Ringwald }; 15535fd3fb9SMatthias Ringwald 15659c97ae1SMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess 15759c97ae1SMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(int num_samples, int16_t * data){ 15835fd3fb9SMatthias Ringwald int i; 15935fd3fb9SMatthias Ringwald for (i=0; i < num_samples; i++){ 160c4e666bcSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase++]; 16159c97ae1SMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 16259c97ae1SMatthias Ringwald phase = 0; 16359c97ae1SMatthias Ringwald } 16459c97ae1SMatthias Ringwald } 16559c97ae1SMatthias Ringwald } 16659c97ae1SMatthias Ringwald 16759c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian 16859c97ae1SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(int num_samples, int16_t * data){ 16959c97ae1SMatthias Ringwald int i; 17059c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 17159c97ae1SMatthias Ringwald int16_t sample = sine_int16_at_16000hz[phase]; 17259c97ae1SMatthias Ringwald little_endian_store_16((uint8_t *) data, i * 2, sample); 17359c97ae1SMatthias Ringwald // ony use every second sample from 16khz table to get 8khz 17459c97ae1SMatthias Ringwald phase += 2; 175c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 17635fd3fb9SMatthias Ringwald phase = 0; 17735fd3fb9SMatthias Ringwald } 17835fd3fb9SMatthias Ringwald } 17935fd3fb9SMatthias Ringwald } 18035fd3fb9SMatthias Ringwald 181b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){ 18235fd3fb9SMatthias Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 18335fd3fb9SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 18435fd3fb9SMatthias Ringwald int16_t sample_buffer[num_samples]; 18559c97ae1SMatthias Ringwald sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer); 18635fd3fb9SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 18735fd3fb9SMatthias Ringwald num_audio_frames++; 18835fd3fb9SMatthias Ringwald } 1892b89dbfcSMatthias Ringwald #endif 190dbb41bfeSMilanka Ringwald 191dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 192c4e666bcSMatthias Ringwald static int portaudio_callback( const void *inputBuffer, void *outputBuffer, 193dbb41bfeSMilanka Ringwald unsigned long framesPerBuffer, 194dbb41bfeSMilanka Ringwald const PaStreamCallbackTimeInfo* timeInfo, 195dbb41bfeSMilanka Ringwald PaStreamCallbackFlags statusFlags, 196dbb41bfeSMilanka Ringwald void *userData ) { 197dbb41bfeSMilanka Ringwald (void) timeInfo; /* Prevent unused variable warnings. */ 198dbb41bfeSMilanka Ringwald (void) statusFlags; 199dbb41bfeSMilanka Ringwald (void) inputBuffer; 2003963d036SMatthias Ringwald (void) userData; 201dbb41bfeSMilanka Ringwald 2022b89dbfcSMatthias Ringwald // output part 2032b89dbfcSMatthias Ringwald 204c4e666bcSMatthias Ringwald // config based on codec 205c4e666bcSMatthias Ringwald int bytes_to_copy; 206c4e666bcSMatthias Ringwald int prebuffer_bytes; 207c4e666bcSMatthias Ringwald switch (negotiated_codec){ 208c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 209c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * MSBC_BYTES_PER_FRAME; 210c4e666bcSMatthias Ringwald prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES; 211c4e666bcSMatthias Ringwald break; 212c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 213c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * CVSD_BYTES_PER_FRAME; 214c4e666bcSMatthias Ringwald prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES; 215c4e666bcSMatthias Ringwald break; 216c4e666bcSMatthias Ringwald default: 217c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * 2; // assume 1 channel / 16 bit audio samples 218c4e666bcSMatthias Ringwald prebuffer_bytes = 0xfffffff; 219c4e666bcSMatthias Ringwald break; 220dbb41bfeSMilanka Ringwald } 221dbb41bfeSMilanka Ringwald 222c4e666bcSMatthias Ringwald // fill with silence while paused 223463c9c89SMatthias Ringwald if (pa_output_paused){ 224463c9c89SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){ 225c4e666bcSMatthias Ringwald memset(outputBuffer, 0, bytes_to_copy); 226c4e666bcSMatthias Ringwald return 0; 227dbb41bfeSMilanka Ringwald } else { 228c4e666bcSMatthias Ringwald // resume playback 229463c9c89SMatthias Ringwald pa_output_paused = 0; 230dbb41bfeSMilanka Ringwald } 231c4e666bcSMatthias Ringwald } 232c4e666bcSMatthias Ringwald 233c4e666bcSMatthias Ringwald // get data from ringbuffer 234c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 235463c9c89SMatthias Ringwald btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read); 236c4e666bcSMatthias Ringwald bytes_to_copy -= bytes_read; 237c4e666bcSMatthias Ringwald 238c4e666bcSMatthias Ringwald // fill with 0 if not enough 239c4e666bcSMatthias Ringwald if (bytes_to_copy){ 240c4e666bcSMatthias Ringwald memset(outputBuffer + bytes_read, 0, bytes_to_copy); 241463c9c89SMatthias Ringwald pa_output_paused = 1; 242c4e666bcSMatthias Ringwald } 2432b89dbfcSMatthias Ringwald // end of output part 2448b29cfc6SMatthias Ringwald 2452b89dbfcSMatthias Ringwald // input part -- just store in ring buffer 2462b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 2472b89dbfcSMatthias Ringwald btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2); 2482b89dbfcSMatthias Ringwald pa_input_counter += framesPerBuffer * 2; 2492b89dbfcSMatthias Ringwald #endif 2502b89dbfcSMatthias Ringwald 2512b89dbfcSMatthias Ringwald return 0; 252c4e666bcSMatthias Ringwald } 253c4e666bcSMatthias Ringwald 254c4e666bcSMatthias Ringwald // return 1 if ok 255c4e666bcSMatthias Ringwald static int portaudio_initialize(int sample_rate){ 256c4e666bcSMatthias Ringwald PaError err; 257c4e666bcSMatthias Ringwald 258c4e666bcSMatthias Ringwald /* -- initialize PortAudio -- */ 259c4e666bcSMatthias Ringwald printf("PortAudio: Initialize\n"); 260c4e666bcSMatthias Ringwald err = Pa_Initialize(); 261c4e666bcSMatthias Ringwald if( err != paNoError ) return 0; 2622b89dbfcSMatthias Ringwald 263c4e666bcSMatthias Ringwald /* -- setup input and output -- */ 2642b89dbfcSMatthias Ringwald const PaDeviceInfo *deviceInfo; 2652b89dbfcSMatthias Ringwald PaStreamParameters * inputParameters = NULL; 2662b89dbfcSMatthias Ringwald PaStreamParameters outputParameters; 267c4e666bcSMatthias Ringwald outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 268c4e666bcSMatthias Ringwald outputParameters.channelCount = NUM_CHANNELS; 269c4e666bcSMatthias Ringwald outputParameters.sampleFormat = paInt16; 270c4e666bcSMatthias Ringwald outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 271c4e666bcSMatthias Ringwald outputParameters.hostApiSpecificStreamInfo = NULL; 2722b89dbfcSMatthias Ringwald deviceInfo = Pa_GetDeviceInfo( outputParameters.device ); 2732b89dbfcSMatthias Ringwald log_info("PortAudio: Output device: %s", deviceInfo->name); 2742b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 2752b89dbfcSMatthias Ringwald PaStreamParameters theInputParameters; 2762b89dbfcSMatthias Ringwald theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ 2772b89dbfcSMatthias Ringwald theInputParameters.channelCount = NUM_CHANNELS; 2782b89dbfcSMatthias Ringwald theInputParameters.sampleFormat = paInt16; 2792b89dbfcSMatthias Ringwald theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighOutputLatency; 2802b89dbfcSMatthias Ringwald theInputParameters.hostApiSpecificStreamInfo = NULL; 2812b89dbfcSMatthias Ringwald inputParameters = &theInputParameters; 2822b89dbfcSMatthias Ringwald deviceInfo = Pa_GetDeviceInfo( inputParameters->device ); 2832b89dbfcSMatthias Ringwald log_info("PortAudio: Input device: %s", deviceInfo->name); 2842b89dbfcSMatthias Ringwald #endif 2852b89dbfcSMatthias Ringwald 2862b89dbfcSMatthias Ringwald /* -- setup output stream -- */ 287c4e666bcSMatthias Ringwald printf("PortAudio: Open stream\n"); 288c4e666bcSMatthias Ringwald err = Pa_OpenStream( 2892b89dbfcSMatthias Ringwald &pa_stream, 2902b89dbfcSMatthias Ringwald inputParameters, 291c4e666bcSMatthias Ringwald &outputParameters, 292c4e666bcSMatthias Ringwald sample_rate, 293c4e666bcSMatthias Ringwald 0, 294c4e666bcSMatthias Ringwald paClipOff, /* we won't output out of range samples so don't bother clipping them */ 295c4e666bcSMatthias Ringwald portaudio_callback, 296c4e666bcSMatthias Ringwald NULL ); 297c4e666bcSMatthias Ringwald if (err != paNoError){ 298c4e666bcSMatthias Ringwald printf("Error opening portaudio stream: \"%s\"\n", Pa_GetErrorText(err)); 299c4e666bcSMatthias Ringwald return 0; 300c4e666bcSMatthias Ringwald } 301463c9c89SMatthias Ringwald memset(pa_output_ring_buffer_storage, 0, sizeof(pa_output_ring_buffer_storage)); 302463c9c89SMatthias Ringwald btstack_ring_buffer_init(&pa_output_ring_buffer, pa_output_ring_buffer_storage, sizeof(pa_output_ring_buffer_storage)); 3032b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 3042b89dbfcSMatthias Ringwald memset(pa_input_ring_buffer_storage, 0, sizeof(pa_input_ring_buffer_storage)); 3052b89dbfcSMatthias Ringwald btstack_ring_buffer_init(&pa_input_ring_buffer, pa_input_ring_buffer_storage, sizeof(pa_input_ring_buffer_storage)); 3062b89dbfcSMatthias Ringwald printf("PortAudio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&pa_input_ring_buffer)); 3072b89dbfcSMatthias Ringwald #endif 3082b89dbfcSMatthias Ringwald 3092b89dbfcSMatthias Ringwald /* -- start stream -- */ 3102b89dbfcSMatthias Ringwald err = Pa_StartStream(pa_stream); 3112b89dbfcSMatthias Ringwald if (err != paNoError){ 3122b89dbfcSMatthias Ringwald printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); 3132b89dbfcSMatthias Ringwald return 0; 3142b89dbfcSMatthias Ringwald } 3152b89dbfcSMatthias Ringwald pa_output_started = 1; 3162b89dbfcSMatthias Ringwald pa_output_paused = 1; 3172b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 3182b89dbfcSMatthias Ringwald pa_input_started = 1; 3192b89dbfcSMatthias Ringwald pa_input_paused = 1; 3202b89dbfcSMatthias Ringwald #endif 3212b89dbfcSMatthias Ringwald 322c4e666bcSMatthias Ringwald return 1; 323c4e666bcSMatthias Ringwald } 3242b89dbfcSMatthias Ringwald 3252b89dbfcSMatthias Ringwald static void portaudio_terminate(void){ 3262b89dbfcSMatthias Ringwald if (!pa_stream) return; 3272b89dbfcSMatthias Ringwald 3282b89dbfcSMatthias Ringwald PaError err; 3292b89dbfcSMatthias Ringwald printf("PortAudio: Stop Stream\n"); 3302b89dbfcSMatthias Ringwald err = Pa_StopStream(pa_stream); 3312b89dbfcSMatthias Ringwald if (err != paNoError){ 3322b89dbfcSMatthias Ringwald printf("Error stopping the stream: \"%s\"\n", Pa_GetErrorText(err)); 3332b89dbfcSMatthias Ringwald return; 3342b89dbfcSMatthias Ringwald } 3352b89dbfcSMatthias Ringwald printf("PortAudio: Close Stream\n"); 3362b89dbfcSMatthias Ringwald err = Pa_CloseStream(pa_stream); 3372b89dbfcSMatthias Ringwald if (err != paNoError){ 3382b89dbfcSMatthias Ringwald printf("Error closing the stream: \"%s\"\n", Pa_GetErrorText(err)); 3392b89dbfcSMatthias Ringwald return; 3402b89dbfcSMatthias Ringwald } 3412b89dbfcSMatthias Ringwald pa_stream = NULL; 3422b89dbfcSMatthias Ringwald printf("PortAudio: Terminate\n"); 3432b89dbfcSMatthias Ringwald err = Pa_Terminate(); 3442b89dbfcSMatthias Ringwald if (err != paNoError){ 3452b89dbfcSMatthias Ringwald printf("Error terminating portaudio: \"%s\"\n", Pa_GetErrorText(err)); 3462b89dbfcSMatthias Ringwald return; 3472b89dbfcSMatthias Ringwald } 3482b89dbfcSMatthias Ringwald } 349c4e666bcSMatthias Ringwald #endif 350c4e666bcSMatthias Ringwald 3512c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 352c4e666bcSMatthias Ringwald 353c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 354c4e666bcSMatthias Ringwald UNUSED(context); 355c4e666bcSMatthias Ringwald UNUSED(sample_rate); 3562c7ae6e1SMatthias Ringwald UNUSED(data); 3572c7ae6e1SMatthias Ringwald UNUSED(num_samples); 3582c7ae6e1SMatthias Ringwald UNUSED(num_channels); 3592c7ae6e1SMatthias Ringwald 3602c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 361c4e666bcSMatthias Ringwald 362c4e666bcSMatthias Ringwald // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); 363c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 3645303ddeeSMatthias Ringwald // samples in callback in host endianess, ready for PortAudio playback 365463c9c89SMatthias Ringwald btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 366dbb41bfeSMilanka Ringwald #endif 367dbb41bfeSMilanka Ringwald 3682c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 369fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 370fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 371fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 372fbc7c9f2SMilanka Ringwald wav_writer_write_int16(num_samples, data); 373fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 3742c7ae6e1SMatthias Ringwald wav_writer_close(); 375fcb08cdbSMilanka Ringwald } 3762c7ae6e1SMatthias Ringwald #endif 3772c7ae6e1SMatthias Ringwald 3782c7ae6e1SMatthias Ringwald #endif 3792c7ae6e1SMatthias Ringwald 380fcb08cdbSMilanka Ringwald } 381fcb08cdbSMilanka Ringwald 382fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 383c4e666bcSMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 384c4e666bcSMatthias Ringwald 385fbc7c9f2SMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 386220eb563SMilanka Ringwald hfp_msbc_init(); 3872c7ae6e1SMatthias Ringwald 3882c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3892c7ae6e1SMatthias Ringwald num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 3902c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE); 3912c7ae6e1SMatthias Ringwald #endif 3922c7ae6e1SMatthias Ringwald 3932b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 394b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 3952b89dbfcSMatthias Ringwald #endif 396973d7173SMatthias Ringwald 397d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME 398d5e5f834SMatthias Ringwald msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 399d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 400d5e5f834SMatthias Ringwald #endif 4012b89dbfcSMatthias Ringwald 4027294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 403d5e5f834SMatthias Ringwald msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 404d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 4057294d009SMatthias Ringwald #endif 406dbb41bfeSMilanka Ringwald 407dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 408c4e666bcSMatthias Ringwald portaudio_initialize(MSBC_SAMPLE_RATE); 409dbb41bfeSMilanka Ringwald #endif 410fcb08cdbSMilanka Ringwald } 411fcb08cdbSMilanka Ringwald 412fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 413fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 414d5e5f834SMatthias Ringwald if (msbc_file_in){ 415d5e5f834SMatthias Ringwald // log incoming mSBC data for testing 416d5e5f834SMatthias Ringwald fwrite(packet+3, size-3, 1, msbc_file_in); 417d5e5f834SMatthias Ringwald } 418fcb08cdbSMilanka Ringwald } 419dbb41bfeSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 420fcb08cdbSMilanka Ringwald } 421fcb08cdbSMilanka Ringwald 422fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){ 423c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 424c4e666bcSMatthias Ringwald 425*d4f907a6SMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO) 426fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 427*d4f907a6SMatthias Ringwald #endif 428c4e666bcSMatthias Ringwald 4292c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 430c4e666bcSMatthias Ringwald num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 4312c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE); 4322c7ae6e1SMatthias Ringwald #endif 433dbb41bfeSMilanka Ringwald 434dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 435c4e666bcSMatthias Ringwald portaudio_initialize(CVSD_SAMPLE_RATE); 436dbb41bfeSMilanka Ringwald #endif 437fbc7c9f2SMilanka Ringwald } 438fbc7c9f2SMilanka Ringwald 439fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 440dbb41bfeSMilanka Ringwald if (!num_samples_to_write) return; 4412c7ae6e1SMatthias Ringwald 4425303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 4431f8694ccSMatthias Ringwald 4441f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 4451f8694ccSMatthias Ringwald printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); 4461f8694ccSMatthias Ringwald return; 4471f8694ccSMatthias Ringwald } 4482c7ae6e1SMatthias Ringwald 449c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 450c4e666bcSMatthias Ringwald const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME; 4515303ddeeSMatthias Ringwald 4525303ddeeSMatthias Ringwald // convert into host endian 4535303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 4545303ddeeSMatthias Ringwald int i; 4555303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 4565303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 4575303ddeeSMatthias Ringwald } 4585303ddeeSMatthias Ringwald 459*d4f907a6SMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO) 460e36764ddSMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out); 461*d4f907a6SMatthias Ringwald #endif 4625303ddeeSMatthias Ringwald 4632c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 4642c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 4652c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 4662c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 4672c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 4682c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 4692c7ae6e1SMatthias Ringwald wav_writer_close(); 4702c7ae6e1SMatthias Ringwald } 4712c7ae6e1SMatthias Ringwald #endif 4722c7ae6e1SMatthias Ringwald 473dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 474463c9c89SMatthias Ringwald btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 475dbb41bfeSMilanka Ringwald #endif 476fcb08cdbSMilanka Ringwald } 477fcb08cdbSMilanka Ringwald 4782c7ae6e1SMatthias Ringwald #endif 4792c7ae6e1SMatthias Ringwald 4802c7ae6e1SMatthias Ringwald 481fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 482c4e666bcSMatthias Ringwald printf("SCO demo close\n"); 4832b89dbfcSMatthias Ringwald 48426463303SMilanka Ringwald printf("SCO demo statistics: "); 48526463303SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 4862c7ae6e1SMatthias 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); 48726463303SMilanka Ringwald } else { 4882c7ae6e1SMatthias 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); 48926463303SMilanka Ringwald } 49026463303SMilanka Ringwald 4912c7ae6e1SMatthias Ringwald negotiated_codec = -1; 4922c7ae6e1SMatthias Ringwald 4932c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 4942c7ae6e1SMatthias Ringwald 4952c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 4962c7ae6e1SMatthias Ringwald wav_writer_close(); 4972c7ae6e1SMatthias Ringwald #endif 4982c7ae6e1SMatthias Ringwald 499dbb41bfeSMilanka Ringwald #ifdef HAVE_PORTAUDIO 5002b89dbfcSMatthias Ringwald portaudio_terminate(); 501dbb41bfeSMilanka Ringwald #endif 502fcb08cdbSMilanka Ringwald 503fcb08cdbSMilanka Ringwald #endif 504fcb08cdbSMilanka Ringwald } 505fcb08cdbSMilanka Ringwald 506fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 507fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 508fcb08cdbSMilanka Ringwald negotiated_codec = codec; 5092c7ae6e1SMatthias Ringwald 5102b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 511220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 512fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 513fcb08cdbSMilanka Ringwald } else { 514fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 515fcb08cdbSMilanka Ringwald } 516fcb08cdbSMilanka Ringwald #endif 517fcb08cdbSMilanka Ringwald } 518fcb08cdbSMilanka Ringwald 519f7c85330SMatthias Ringwald void sco_demo_init(void){ 520f7c85330SMatthias Ringwald // status 5212b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 5222b89dbfcSMatthias Ringwald printf("SCO Demo: Sending and receiving audio via portaudio.\n"); 5232b89dbfcSMatthias Ringwald #endif 524f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 525f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 526f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 527f7c85330SMatthias Ringwald #else 528f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 529f7c85330SMatthias Ringwald #endif 530f7c85330SMatthias Ringwald #endif 531f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 532f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 533f7c85330SMatthias Ringwald #endif 534f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 535f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 536f7c85330SMatthias Ringwald #endif 537f7c85330SMatthias Ringwald 5382b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 539c4e666bcSMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 540c4e666bcSMatthias Ringwald #else 541f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 5427294d009SMatthias Ringwald #endif 543f7c85330SMatthias Ringwald 544f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 545f7c85330SMatthias Ringwald phase = 'a'; 546f7c85330SMatthias Ringwald #endif 547f7c85330SMatthias Ringwald } 548f7c85330SMatthias Ringwald 5491a919128SMatthias Ringwald void sco_report(void); 5501a919128SMatthias Ringwald void sco_report(void){ 5514a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 5524a96141eSMatthias Ringwald } 553f7c85330SMatthias Ringwald 554f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 555f7c85330SMatthias Ringwald 556f7c85330SMatthias Ringwald if (!sco_handle) return; 557f7c85330SMatthias Ringwald 558c4e666bcSMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 559c4e666bcSMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 560f7c85330SMatthias Ringwald 561f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 562f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 563f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 564220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 565c4e666bcSMatthias Ringwald // overwrite 566c4e666bcSMatthias Ringwald sco_payload_length = 24; 567c4e666bcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 568c4e666bcSMatthias Ringwald 569220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 570220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 571220eb563SMilanka Ringwald } 572220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 573d5e5f834SMatthias Ringwald if (msbc_file_out){ 574d76591efSMatthias Ringwald // log outgoing mSBC data for testing 575d5e5f834SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 576d76591efSMatthias Ringwald } 5777294d009SMatthias Ringwald 578b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 579220eb563SMilanka Ringwald } else { 580c4e666bcSMatthias Ringwald const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME; 58159c97ae1SMatthias Ringwald sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, (int16_t *) (sco_packet+3)); 582220eb563SMilanka Ringwald } 5831a919128SMatthias Ringwald #endif 5842b89dbfcSMatthias Ringwald 5852b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 5862b89dbfcSMatthias Ringwald 5872b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 5882b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 5892b89dbfcSMatthias Ringwald // MSBC 5902b89dbfcSMatthias Ringwald 5912b89dbfcSMatthias Ringwald // overwrite 5922b89dbfcSMatthias Ringwald sco_payload_length = 24; 5932b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 5942b89dbfcSMatthias Ringwald 595b025eb5fSMatthias Ringwald if (pa_input_paused){ 596b025eb5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ 597b025eb5fSMatthias Ringwald // resume sending 598b025eb5fSMatthias Ringwald pa_input_paused = 0; 5992b89dbfcSMatthias Ringwald } 600b025eb5fSMatthias Ringwald } 601b025eb5fSMatthias Ringwald 602b025eb5fSMatthias Ringwald if (!pa_input_paused){ 603b025eb5fSMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 604b025eb5fSMatthias Ringwald if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){ 605b025eb5fSMatthias Ringwald int16_t sample_buffer[num_samples]; 606b025eb5fSMatthias Ringwald uint32_t bytes_read; 607b025eb5fSMatthias Ringwald btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read); 608b025eb5fSMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 609b025eb5fSMatthias Ringwald num_audio_frames++; 610b025eb5fSMatthias Ringwald } 611b025eb5fSMatthias Ringwald } 612b025eb5fSMatthias Ringwald 613b025eb5fSMatthias Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 614b025eb5fSMatthias Ringwald log_error("mSBC stream should not be empty."); 615b025eb5fSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 616b025eb5fSMatthias Ringwald pa_input_paused = 1; 617b025eb5fSMatthias Ringwald } else { 6182b89dbfcSMatthias Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 6192b89dbfcSMatthias Ringwald if (msbc_file_out){ 6202b89dbfcSMatthias Ringwald // log outgoing mSBC data for testing 6212b89dbfcSMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 6222b89dbfcSMatthias Ringwald } 623b025eb5fSMatthias Ringwald } 6242b89dbfcSMatthias Ringwald 6252b89dbfcSMatthias Ringwald } else { 6262b89dbfcSMatthias Ringwald // CVSD 6272b89dbfcSMatthias Ringwald 6282b89dbfcSMatthias 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); 6292b89dbfcSMatthias Ringwald // fill with silence while paused 6302b89dbfcSMatthias Ringwald int bytes_to_copy = sco_payload_length; 6312b89dbfcSMatthias Ringwald if (pa_input_paused){ 6322b89dbfcSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ 6332b89dbfcSMatthias Ringwald // resume sending 6342b89dbfcSMatthias Ringwald pa_input_paused = 0; 6352b89dbfcSMatthias Ringwald } 6362b89dbfcSMatthias Ringwald } 6372b89dbfcSMatthias Ringwald 6382b89dbfcSMatthias Ringwald // get data from ringbuffer 6392b89dbfcSMatthias Ringwald uint16_t pos = 0; 6408fd6902dSMatthias Ringwald uint8_t * sample_data = &sco_packet[3]; 6412b89dbfcSMatthias Ringwald if (!pa_input_paused){ 6422b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 6438fd6902dSMatthias Ringwald btstack_ring_buffer_read(&pa_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read); 6448fd6902dSMatthias Ringwald // flip 16 on big endian systems 6458fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 6468fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 6478fd6902dSMatthias Ringwald int i; 6488fd6902dSMatthias Ringwald for (i=0;i<bytes_read;i+=2){ 6498fd6902dSMatthias Ringwald uint8_t tmp = sample_data[i*2]; 6508fd6902dSMatthias Ringwald sample_data[i*2] = sample_data[i*2+1]; 6518fd6902dSMatthias Ringwald sample_data[i*2+1] = tmp; 6528fd6902dSMatthias Ringwald } 6538fd6902dSMatthias Ringwald } 6542b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 6552b89dbfcSMatthias Ringwald pos += bytes_read; 6562b89dbfcSMatthias Ringwald } 6572b89dbfcSMatthias Ringwald 6582b89dbfcSMatthias Ringwald // fill with 0 if not enough 6592b89dbfcSMatthias Ringwald if (bytes_to_copy){ 6608fd6902dSMatthias Ringwald memset(sample_data + pos, 0, bytes_to_copy); 6612b89dbfcSMatthias Ringwald pa_input_paused = 1; 6622b89dbfcSMatthias Ringwald } 6632b89dbfcSMatthias Ringwald } 6642b89dbfcSMatthias Ringwald #else 6652b89dbfcSMatthias Ringwald // just send '0's 6662b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 6672b89dbfcSMatthias Ringwald sco_payload_length = 24; 6682b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 6692b89dbfcSMatthias Ringwald } 6702b89dbfcSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 6712b89dbfcSMatthias Ringwald #endif 6722b89dbfcSMatthias Ringwald #endif 6732b89dbfcSMatthias Ringwald 674f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 675c4e666bcSMatthias Ringwald memset(&sco_packet[3], phase++, sco_payload_length); 676f7c85330SMatthias Ringwald if (phase > 'z') phase = 'a'; 6771a919128SMatthias Ringwald #endif 6781a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 67938b2eaafSMatthias Ringwald int j; 680c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 68138b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 682f7c85330SMatthias Ringwald } 683f7c85330SMatthias Ringwald #endif 6841a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 6851a919128SMatthias Ringwald int j; 686c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6871a919128SMatthias Ringwald // sco_packet[3+j] = j & 1 ? 0x35 : 0x53; 6881a919128SMatthias Ringwald sco_packet[3+j] = 0x55; 6891a919128SMatthias Ringwald } 6901a919128SMatthias Ringwald #endif 6911a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00 6921a919128SMatthias Ringwald int j; 693c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6941a919128SMatthias Ringwald sco_packet[3+j] = 0x00; 6951a919128SMatthias Ringwald } 6961a919128SMatthias Ringwald // additional hack 6971a919128SMatthias Ringwald // big_endian_store_16(sco_packet, 5, phase++); 6981a919128SMatthias Ringwald (void) phase; 699f7c85330SMatthias Ringwald #endif 700220eb563SMilanka Ringwald 7012b89dbfcSMatthias Ringwald // test silence 7022b89dbfcSMatthias Ringwald // memset(sco_packet+3, 0, sco_payload_length); 7032b89dbfcSMatthias Ringwald 704c4e666bcSMatthias Ringwald // set handle + flags 705c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 706c4e666bcSMatthias Ringwald // set len 707c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 708c4e666bcSMatthias Ringwald // finally send packet 709f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 710f7c85330SMatthias Ringwald 711f7c85330SMatthias Ringwald // request another send event 712f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 713f7c85330SMatthias Ringwald 7144a96141eSMatthias Ringwald count_sent++; 7151a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55 7164a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 7171a919128SMatthias Ringwald #endif 718f7c85330SMatthias Ringwald } 719f7c85330SMatthias Ringwald 720f7c85330SMatthias Ringwald /** 721f7c85330SMatthias Ringwald * @brief Process received data 722f7c85330SMatthias Ringwald */ 7231a919128SMatthias Ringwald #define ANSI_COLOR_RED "\x1b[31m" 7241a919128SMatthias Ringwald #define ANSI_COLOR_GREEN "\x1b[32m" 7251a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW "\x1b[33m" 7261a919128SMatthias Ringwald #define ANSI_COLOR_BLUE "\x1b[34m" 7271a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m" 7281a919128SMatthias Ringwald #define ANSI_COLOR_CYAN "\x1b[36m" 7291a919128SMatthias Ringwald #define ANSI_COLOR_RESET "\x1b[0m" 7301a919128SMatthias Ringwald 731f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 732f7c85330SMatthias Ringwald 733fcb08cdbSMilanka Ringwald dump_data = 1; 7348b29cfc6SMatthias Ringwald 7354a96141eSMatthias Ringwald count_received++; 7361a919128SMatthias Ringwald static uint32_t packets = 0; 7371a919128SMatthias Ringwald static uint32_t crc_errors = 0; 7381a919128SMatthias Ringwald static uint32_t data_received = 0; 7391a919128SMatthias Ringwald static uint32_t byte_errors = 0; 7404a96141eSMatthias Ringwald 7411a919128SMatthias Ringwald data_received += size - 3; 7421a919128SMatthias Ringwald packets++; 7431a919128SMatthias Ringwald if (data_received > 100000){ 744*d4f907a6SMatthias 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); 7451a919128SMatthias Ringwald crc_errors = 0; 7461a919128SMatthias Ringwald byte_errors = 0; 7471a919128SMatthias Ringwald data_received = 0; 7481a919128SMatthias Ringwald packets = 0; 7491a919128SMatthias Ringwald } 7504a96141eSMatthias Ringwald 7512b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 752c4e666bcSMatthias Ringwald switch (negotiated_codec){ 753c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 754fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 755c4e666bcSMatthias Ringwald break; 756c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 757fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 758c4e666bcSMatthias Ringwald break; 759c4e666bcSMatthias Ringwald default: 760c4e666bcSMatthias Ringwald break; 7618b29cfc6SMatthias Ringwald } 762dbb41bfeSMilanka Ringwald dump_data = 0; 7638b29cfc6SMatthias Ringwald #endif 7648b29cfc6SMatthias Ringwald 765b3f76298SMilanka Ringwald if (packet[1] & 0x30){ 7661a919128SMatthias Ringwald crc_errors++; 7671a919128SMatthias Ringwald // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 7681a919128SMatthias Ringwald // printf_hexdump(&packet[3], size-3); 769f7c85330SMatthias Ringwald return; 770f7c85330SMatthias Ringwald } 7718b29cfc6SMatthias Ringwald if (dump_data){ 772f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 7731a919128SMatthias Ringwald printf("data: "); 774f7c85330SMatthias Ringwald int i; 775f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 776f7c85330SMatthias Ringwald printf("%c", packet[i]); 777f7c85330SMatthias Ringwald } 778f7c85330SMatthias Ringwald printf("\n"); 7798b29cfc6SMatthias Ringwald dump_data = 0; 7801a919128SMatthias Ringwald #endif 7811a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 7821a919128SMatthias Ringwald // colored hexdump with expected 7831a919128SMatthias Ringwald static uint8_t expected_byte = 0; 7841a919128SMatthias Ringwald int i; 7851a919128SMatthias Ringwald printf("data: "); 7861a919128SMatthias Ringwald for (i=3;i<size;i++){ 7871a919128SMatthias Ringwald if (packet[i] != expected_byte){ 7881a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7891a919128SMatthias Ringwald } else { 7901a919128SMatthias Ringwald printf("%02x ", packet[i]); 7911a919128SMatthias Ringwald } 7921a919128SMatthias Ringwald expected_byte = packet[i]+1; 7931a919128SMatthias Ringwald } 7941a919128SMatthias Ringwald printf("\n"); 7951a919128SMatthias Ringwald #endif 796a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00 7971a919128SMatthias Ringwald int i; 7981a919128SMatthias Ringwald int contains_error = 0; 7991a919128SMatthias Ringwald for (i=3;i<size;i++){ 8001a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 8011a919128SMatthias Ringwald contains_error = 1; 8021a919128SMatthias Ringwald byte_errors++; 8031a919128SMatthias Ringwald } 8041a919128SMatthias Ringwald } 8051a919128SMatthias Ringwald if (contains_error){ 8061a919128SMatthias Ringwald printf("data: "); 8071a919128SMatthias Ringwald for (i=0;i<3;i++){ 8081a919128SMatthias Ringwald printf("%02x ", packet[i]); 8091a919128SMatthias Ringwald } 8101a919128SMatthias Ringwald for (i=3;i<size;i++){ 8111a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 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 } 8171a919128SMatthias Ringwald printf("\n"); 8181a919128SMatthias Ringwald } 819f7c85330SMatthias Ringwald #endif 8208b29cfc6SMatthias Ringwald } 821f7c85330SMatthias Ringwald } 822