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 75c4e666bcSMatthias Ringwald // length and name of wav file on disc 76c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15 778b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 78c4e666bcSMatthias Ringwald 79c4e666bcSMatthias Ringwald // name of sbc test files 80d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 812308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME "sco_input.msbc" 82220eb563SMilanka Ringwald 83c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency 84c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS 50 85c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS 50 868b29cfc6SMatthias Ringwald 87c4e666bcSMatthias Ringwald // constants 88c4e666bcSMatthias Ringwald #define NUM_CHANNELS 1 89c4e666bcSMatthias Ringwald #define CVSD_BYTES_PER_FRAME (2*NUM_CHANNELS) 90c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE 8000 91c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE 16000 92c4e666bcSMatthias Ringwald #define MSBC_BYTES_PER_FRAME (2*NUM_CHANNELS) 93f7c85330SMatthias Ringwald 942b89dbfcSMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE || SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 95f7c85330SMatthias Ringwald #define USE_PORTAUDIO 96c4e666bcSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME) 97c4e666bcSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME) 98f7c85330SMatthias Ringwald #endif 99f7c85330SMatthias Ringwald 100f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 1012b89dbfcSMatthias Ringwald 1022b89dbfcSMatthias Ringwald // bidirectional audio stream 1032b89dbfcSMatthias Ringwald static PaStream * pa_stream; 1042b89dbfcSMatthias Ringwald 1052b89dbfcSMatthias Ringwald // output 106463c9c89SMatthias Ringwald static int pa_output_started = 0; 107463c9c89SMatthias Ringwald static int pa_output_paused = 0; 108463c9c89SMatthias Ringwald static uint8_t pa_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES]; 109463c9c89SMatthias Ringwald static btstack_ring_buffer_t pa_output_ring_buffer; 1102b89dbfcSMatthias Ringwald 1112b89dbfcSMatthias Ringwald // input 1122b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 1132b89dbfcSMatthias Ringwald #define USE_PORTAUDIO_INPUT 1142b89dbfcSMatthias Ringwald static int pa_input_started = 0; 1152b89dbfcSMatthias Ringwald static int pa_input_paused = 0; 1162b89dbfcSMatthias Ringwald static uint8_t pa_input_ring_buffer_storage[2*8000]; // full second input buffer 1172b89dbfcSMatthias Ringwald static btstack_ring_buffer_t pa_input_ring_buffer; 1182b89dbfcSMatthias Ringwald static int pa_input_counter; 1192b89dbfcSMatthias Ringwald #endif 1202b89dbfcSMatthias Ringwald 121f7c85330SMatthias Ringwald #endif 122f7c85330SMatthias Ringwald 123fcb08cdbSMilanka Ringwald static int dump_data = 1; 124fcb08cdbSMilanka Ringwald static int count_sent = 0; 125fcb08cdbSMilanka Ringwald static int count_received = 0; 126c4e666bcSMatthias Ringwald static int negotiated_codec = -1; 127c4e666bcSMatthias Ringwald 1282b89dbfcSMatthias Ringwald btstack_sbc_decoder_state_t decoder_state; 1292b89dbfcSMatthias Ringwald btstack_cvsd_plc_state_t cvsd_plc_state; 130fcb08cdbSMilanka Ringwald 131d5e5f834SMatthias Ringwald FILE * msbc_file_in; 132d5e5f834SMatthias Ringwald FILE * msbc_file_out; 1337294d009SMatthias Ringwald 1342b89dbfcSMatthias Ringwald int num_samples_to_write; 1352b89dbfcSMatthias Ringwald int num_audio_frames; 1362b89dbfcSMatthias Ringwald int phase; 1372b89dbfcSMatthias Ringwald 138f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 139d6a06398SMatthias Ringwald 14035fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz 141c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 14235fd3fb9SMatthias Ringwald 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 14335fd3fb9SMatthias Ringwald 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 14435fd3fb9SMatthias Ringwald 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 14535fd3fb9SMatthias Ringwald 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 14635fd3fb9SMatthias Ringwald 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 14735fd3fb9SMatthias Ringwald 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 14835fd3fb9SMatthias Ringwald -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 14935fd3fb9SMatthias Ringwald -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 15035fd3fb9SMatthias Ringwald -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 15135fd3fb9SMatthias Ringwald -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 15235fd3fb9SMatthias Ringwald }; 15335fd3fb9SMatthias Ringwald 154c4e666bcSMatthias Ringwald // ony use every second value from 16khz table 155c4e666bcSMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz(int num_samples, int16_t * data){ 15635fd3fb9SMatthias Ringwald int i; 15735fd3fb9SMatthias Ringwald for (i=0; i < num_samples; i++){ 158c4e666bcSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase++]; 15935fd3fb9SMatthias Ringwald phase++; 160c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 16135fd3fb9SMatthias Ringwald phase = 0; 16235fd3fb9SMatthias Ringwald } 16335fd3fb9SMatthias Ringwald } 16435fd3fb9SMatthias Ringwald } 16535fd3fb9SMatthias Ringwald 166*b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){ 16735fd3fb9SMatthias Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 16835fd3fb9SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 16935fd3fb9SMatthias Ringwald int16_t sample_buffer[num_samples]; 170c4e666bcSMatthias Ringwald sco_demo_sine_wave_int16_at_8000_hz(num_samples, sample_buffer); 17135fd3fb9SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 17235fd3fb9SMatthias Ringwald num_audio_frames++; 17335fd3fb9SMatthias Ringwald } 1742b89dbfcSMatthias Ringwald #endif 175dbb41bfeSMilanka Ringwald 176dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 177c4e666bcSMatthias Ringwald static int portaudio_callback( const void *inputBuffer, void *outputBuffer, 178dbb41bfeSMilanka Ringwald unsigned long framesPerBuffer, 179dbb41bfeSMilanka Ringwald const PaStreamCallbackTimeInfo* timeInfo, 180dbb41bfeSMilanka Ringwald PaStreamCallbackFlags statusFlags, 181dbb41bfeSMilanka Ringwald void *userData ) { 182dbb41bfeSMilanka Ringwald (void) timeInfo; /* Prevent unused variable warnings. */ 183dbb41bfeSMilanka Ringwald (void) statusFlags; 184dbb41bfeSMilanka Ringwald (void) inputBuffer; 1853963d036SMatthias Ringwald (void) userData; 186dbb41bfeSMilanka Ringwald 1872b89dbfcSMatthias Ringwald // output part 1882b89dbfcSMatthias Ringwald 189c4e666bcSMatthias Ringwald // config based on codec 190c4e666bcSMatthias Ringwald int bytes_to_copy; 191c4e666bcSMatthias Ringwald int prebuffer_bytes; 192c4e666bcSMatthias Ringwald switch (negotiated_codec){ 193c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 194c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * MSBC_BYTES_PER_FRAME; 195c4e666bcSMatthias Ringwald prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES; 196c4e666bcSMatthias Ringwald break; 197c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 198c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * CVSD_BYTES_PER_FRAME; 199c4e666bcSMatthias Ringwald prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES; 200c4e666bcSMatthias Ringwald break; 201c4e666bcSMatthias Ringwald default: 202c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * 2; // assume 1 channel / 16 bit audio samples 203c4e666bcSMatthias Ringwald prebuffer_bytes = 0xfffffff; 204c4e666bcSMatthias Ringwald break; 205dbb41bfeSMilanka Ringwald } 206dbb41bfeSMilanka Ringwald 207c4e666bcSMatthias Ringwald // fill with silence while paused 208463c9c89SMatthias Ringwald if (pa_output_paused){ 209463c9c89SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){ 210c4e666bcSMatthias Ringwald memset(outputBuffer, 0, bytes_to_copy); 211c4e666bcSMatthias Ringwald return 0; 212dbb41bfeSMilanka Ringwald } else { 213c4e666bcSMatthias Ringwald // resume playback 214463c9c89SMatthias Ringwald pa_output_paused = 0; 215dbb41bfeSMilanka Ringwald } 216c4e666bcSMatthias Ringwald } 217c4e666bcSMatthias Ringwald 218c4e666bcSMatthias Ringwald // get data from ringbuffer 219c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 220463c9c89SMatthias Ringwald btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read); 221c4e666bcSMatthias Ringwald bytes_to_copy -= bytes_read; 222c4e666bcSMatthias Ringwald 223c4e666bcSMatthias Ringwald // fill with 0 if not enough 224c4e666bcSMatthias Ringwald if (bytes_to_copy){ 225c4e666bcSMatthias Ringwald memset(outputBuffer + bytes_read, 0, bytes_to_copy); 226463c9c89SMatthias Ringwald pa_output_paused = 1; 227c4e666bcSMatthias Ringwald } 2282b89dbfcSMatthias Ringwald // end of output part 2298b29cfc6SMatthias Ringwald 2302b89dbfcSMatthias Ringwald // input part -- just store in ring buffer 2312b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 2322b89dbfcSMatthias Ringwald btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2); 2332b89dbfcSMatthias Ringwald pa_input_counter += framesPerBuffer * 2; 2342b89dbfcSMatthias Ringwald #endif 2352b89dbfcSMatthias Ringwald 2362b89dbfcSMatthias Ringwald return 0; 237c4e666bcSMatthias Ringwald } 238c4e666bcSMatthias Ringwald 239c4e666bcSMatthias Ringwald // return 1 if ok 240c4e666bcSMatthias Ringwald static int portaudio_initialize(int sample_rate){ 241c4e666bcSMatthias Ringwald PaError err; 242c4e666bcSMatthias Ringwald 243c4e666bcSMatthias Ringwald /* -- initialize PortAudio -- */ 244c4e666bcSMatthias Ringwald printf("PortAudio: Initialize\n"); 245c4e666bcSMatthias Ringwald err = Pa_Initialize(); 246c4e666bcSMatthias Ringwald if( err != paNoError ) return 0; 2472b89dbfcSMatthias Ringwald 248c4e666bcSMatthias Ringwald /* -- setup input and output -- */ 2492b89dbfcSMatthias Ringwald const PaDeviceInfo *deviceInfo; 2502b89dbfcSMatthias Ringwald PaStreamParameters * inputParameters = NULL; 2512b89dbfcSMatthias Ringwald PaStreamParameters outputParameters; 252c4e666bcSMatthias Ringwald outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 253c4e666bcSMatthias Ringwald outputParameters.channelCount = NUM_CHANNELS; 254c4e666bcSMatthias Ringwald outputParameters.sampleFormat = paInt16; 255c4e666bcSMatthias Ringwald outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 256c4e666bcSMatthias Ringwald outputParameters.hostApiSpecificStreamInfo = NULL; 2572b89dbfcSMatthias Ringwald deviceInfo = Pa_GetDeviceInfo( outputParameters.device ); 2582b89dbfcSMatthias Ringwald log_info("PortAudio: Output device: %s", deviceInfo->name); 2592b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 2602b89dbfcSMatthias Ringwald PaStreamParameters theInputParameters; 2612b89dbfcSMatthias Ringwald theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ 2622b89dbfcSMatthias Ringwald theInputParameters.channelCount = NUM_CHANNELS; 2632b89dbfcSMatthias Ringwald theInputParameters.sampleFormat = paInt16; 2642b89dbfcSMatthias Ringwald theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighOutputLatency; 2652b89dbfcSMatthias Ringwald theInputParameters.hostApiSpecificStreamInfo = NULL; 2662b89dbfcSMatthias Ringwald inputParameters = &theInputParameters; 2672b89dbfcSMatthias Ringwald deviceInfo = Pa_GetDeviceInfo( inputParameters->device ); 2682b89dbfcSMatthias Ringwald log_info("PortAudio: Input device: %s", deviceInfo->name); 2692b89dbfcSMatthias Ringwald #endif 2702b89dbfcSMatthias Ringwald 2712b89dbfcSMatthias Ringwald /* -- setup output stream -- */ 272c4e666bcSMatthias Ringwald printf("PortAudio: Open stream\n"); 273c4e666bcSMatthias Ringwald err = Pa_OpenStream( 2742b89dbfcSMatthias Ringwald &pa_stream, 2752b89dbfcSMatthias Ringwald inputParameters, 276c4e666bcSMatthias Ringwald &outputParameters, 277c4e666bcSMatthias Ringwald sample_rate, 278c4e666bcSMatthias Ringwald 0, 279c4e666bcSMatthias Ringwald paClipOff, /* we won't output out of range samples so don't bother clipping them */ 280c4e666bcSMatthias Ringwald portaudio_callback, 281c4e666bcSMatthias Ringwald NULL ); 282c4e666bcSMatthias Ringwald if (err != paNoError){ 283c4e666bcSMatthias Ringwald printf("Error opening portaudio stream: \"%s\"\n", Pa_GetErrorText(err)); 284c4e666bcSMatthias Ringwald return 0; 285c4e666bcSMatthias Ringwald } 286463c9c89SMatthias Ringwald memset(pa_output_ring_buffer_storage, 0, sizeof(pa_output_ring_buffer_storage)); 287463c9c89SMatthias Ringwald btstack_ring_buffer_init(&pa_output_ring_buffer, pa_output_ring_buffer_storage, sizeof(pa_output_ring_buffer_storage)); 2882b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 2892b89dbfcSMatthias Ringwald memset(pa_input_ring_buffer_storage, 0, sizeof(pa_input_ring_buffer_storage)); 2902b89dbfcSMatthias Ringwald btstack_ring_buffer_init(&pa_input_ring_buffer, pa_input_ring_buffer_storage, sizeof(pa_input_ring_buffer_storage)); 2912b89dbfcSMatthias Ringwald printf("PortAudio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&pa_input_ring_buffer)); 2922b89dbfcSMatthias Ringwald #endif 2932b89dbfcSMatthias Ringwald 2942b89dbfcSMatthias Ringwald /* -- start stream -- */ 2952b89dbfcSMatthias Ringwald err = Pa_StartStream(pa_stream); 2962b89dbfcSMatthias Ringwald if (err != paNoError){ 2972b89dbfcSMatthias Ringwald printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); 2982b89dbfcSMatthias Ringwald return 0; 2992b89dbfcSMatthias Ringwald } 3002b89dbfcSMatthias Ringwald pa_output_started = 1; 3012b89dbfcSMatthias Ringwald pa_output_paused = 1; 3022b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 3032b89dbfcSMatthias Ringwald pa_input_started = 1; 3042b89dbfcSMatthias Ringwald pa_input_paused = 1; 3052b89dbfcSMatthias Ringwald #endif 3062b89dbfcSMatthias Ringwald 307c4e666bcSMatthias Ringwald return 1; 308c4e666bcSMatthias Ringwald } 3092b89dbfcSMatthias Ringwald 3102b89dbfcSMatthias Ringwald static void portaudio_terminate(void){ 3112b89dbfcSMatthias Ringwald if (!pa_stream) return; 3122b89dbfcSMatthias Ringwald 3132b89dbfcSMatthias Ringwald PaError err; 3142b89dbfcSMatthias Ringwald printf("PortAudio: Stop Stream\n"); 3152b89dbfcSMatthias Ringwald err = Pa_StopStream(pa_stream); 3162b89dbfcSMatthias Ringwald if (err != paNoError){ 3172b89dbfcSMatthias Ringwald printf("Error stopping the stream: \"%s\"\n", Pa_GetErrorText(err)); 3182b89dbfcSMatthias Ringwald return; 3192b89dbfcSMatthias Ringwald } 3202b89dbfcSMatthias Ringwald printf("PortAudio: Close Stream\n"); 3212b89dbfcSMatthias Ringwald err = Pa_CloseStream(pa_stream); 3222b89dbfcSMatthias Ringwald if (err != paNoError){ 3232b89dbfcSMatthias Ringwald printf("Error closing the stream: \"%s\"\n", Pa_GetErrorText(err)); 3242b89dbfcSMatthias Ringwald return; 3252b89dbfcSMatthias Ringwald } 3262b89dbfcSMatthias Ringwald pa_stream = NULL; 3272b89dbfcSMatthias Ringwald printf("PortAudio: Terminate\n"); 3282b89dbfcSMatthias Ringwald err = Pa_Terminate(); 3292b89dbfcSMatthias Ringwald if (err != paNoError){ 3302b89dbfcSMatthias Ringwald printf("Error terminating portaudio: \"%s\"\n", Pa_GetErrorText(err)); 3312b89dbfcSMatthias Ringwald return; 3322b89dbfcSMatthias Ringwald } 3332b89dbfcSMatthias Ringwald } 334c4e666bcSMatthias Ringwald #endif 335c4e666bcSMatthias Ringwald 336c4e666bcSMatthias Ringwald 337c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 338c4e666bcSMatthias Ringwald UNUSED(context); 339c4e666bcSMatthias Ringwald UNUSED(sample_rate); 340c4e666bcSMatthias Ringwald 341c4e666bcSMatthias Ringwald // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); 342c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 343463c9c89SMatthias Ringwald btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 3449ec2630cSMatthias Ringwald #else 3459ec2630cSMatthias Ringwald UNUSED(num_channels); 346dbb41bfeSMilanka Ringwald #endif 347dbb41bfeSMilanka Ringwald 348fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 349fcb08cdbSMilanka Ringwald 350fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 351fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 352fcb08cdbSMilanka Ringwald 353fbc7c9f2SMilanka Ringwald wav_writer_write_int16(num_samples, data); 354fcb08cdbSMilanka Ringwald 355fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 356fcb08cdbSMilanka Ringwald sco_demo_close(); 357fcb08cdbSMilanka Ringwald } 358fcb08cdbSMilanka Ringwald } 359fcb08cdbSMilanka Ringwald 360fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 361c4e666bcSMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 362c4e666bcSMatthias Ringwald 363c4e666bcSMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE); 364fbc7c9f2SMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 365fcb08cdbSMilanka Ringwald 366c4e666bcSMatthias Ringwald num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 367220eb563SMilanka Ringwald 368220eb563SMilanka Ringwald hfp_msbc_init(); 3692b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 370*b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 3712b89dbfcSMatthias Ringwald #endif 372973d7173SMatthias Ringwald 373d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME 374d5e5f834SMatthias Ringwald msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 375d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 376d5e5f834SMatthias Ringwald #endif 3772b89dbfcSMatthias Ringwald 3787294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 379d5e5f834SMatthias Ringwald msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 380d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 3817294d009SMatthias Ringwald #endif 382dbb41bfeSMilanka Ringwald 383dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 384c4e666bcSMatthias Ringwald portaudio_initialize(MSBC_SAMPLE_RATE); 385dbb41bfeSMilanka Ringwald #endif 386fcb08cdbSMilanka Ringwald } 387fcb08cdbSMilanka Ringwald 388fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 389fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 390d5e5f834SMatthias Ringwald if (msbc_file_in){ 391d5e5f834SMatthias Ringwald // log incoming mSBC data for testing 392d5e5f834SMatthias Ringwald fwrite(packet+3, size-3, 1, msbc_file_in); 393d5e5f834SMatthias Ringwald } 394fcb08cdbSMilanka Ringwald } 395dbb41bfeSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 396fcb08cdbSMilanka Ringwald } 397fcb08cdbSMilanka Ringwald 398fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){ 399c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 400c4e666bcSMatthias Ringwald 401c4e666bcSMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE); 402fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 403c4e666bcSMatthias Ringwald 404c4e666bcSMatthias Ringwald num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 405dbb41bfeSMilanka Ringwald 406dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 407c4e666bcSMatthias Ringwald portaudio_initialize(CVSD_SAMPLE_RATE); 408dbb41bfeSMilanka Ringwald #endif 409fbc7c9f2SMilanka Ringwald } 410fbc7c9f2SMilanka Ringwald 411fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 412dbb41bfeSMilanka Ringwald if (!num_samples_to_write) return; 413c4e666bcSMatthias Ringwald int16_t audio_frame_out[255]; // 4141f8694ccSMatthias Ringwald 4151f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 4161f8694ccSMatthias Ringwald printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); 4171f8694ccSMatthias Ringwald return; 4181f8694ccSMatthias Ringwald } 419c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 420c4e666bcSMatthias Ringwald const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME; 421fcb08cdbSMilanka Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 422379d044eSMilanka Ringwald 423c4e666bcSMatthias Ringwald #if 0 424fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, (int8_t *)(packet+3), num_samples, audio_frame_out); 425c4e666bcSMatthias Ringwald #else 426c4e666bcSMatthias Ringwald memcpy(audio_frame_out, packet+3, audio_bytes_read); 427c4e666bcSMatthias Ringwald #endif 428379d044eSMilanka Ringwald 429c4e666bcSMatthias Ringwald wav_writer_write_int16(samples_to_write, audio_frame_out); 430fcb08cdbSMilanka Ringwald num_samples_to_write -= samples_to_write; 431fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 432fcb08cdbSMilanka Ringwald sco_demo_close(); 433fcb08cdbSMilanka Ringwald } 434dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 435463c9c89SMatthias Ringwald btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 436dbb41bfeSMilanka Ringwald #endif 437fcb08cdbSMilanka Ringwald } 438fcb08cdbSMilanka Ringwald 439fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 440c4e666bcSMatthias Ringwald printf("SCO demo close\n"); 4412b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 4422b89dbfcSMatthias Ringwald 44326463303SMilanka Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 444fbc7c9f2SMilanka Ringwald wav_writer_close(); 4452b89dbfcSMatthias Ringwald #endif 44626463303SMilanka Ringwald printf("SCO demo statistics: "); 44726463303SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 44826463303SMilanka Ringwald printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr); 44926463303SMilanka Ringwald } else { 45026463303SMilanka Ringwald printf("Used CVSD with PLC, number of proccesed frames: \n - %d good frames, \n - %d bad frames.", cvsd_plc_state.good_frames_nr, cvsd_plc_state.bad_frames_nr); 45126463303SMilanka Ringwald } 45226463303SMilanka Ringwald 453dbb41bfeSMilanka Ringwald #ifdef HAVE_PORTAUDIO 4542b89dbfcSMatthias Ringwald portaudio_terminate(); 455dbb41bfeSMilanka Ringwald #endif 456fcb08cdbSMilanka Ringwald 457c4e666bcSMatthias Ringwald #ifdef SCO_WAV_FILENAME 458613518d1SMilanka Ringwald #if 0 459fcb08cdbSMilanka Ringwald printf("SCO Demo: closing wav file\n"); 460220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 4616e046a36SMatthias Ringwald wav_writer_state_t * writer_state = &wav_writer_state; 462fcb08cdbSMilanka Ringwald if (!writer_state->wav_file) return; 463fcb08cdbSMilanka Ringwald rewind(writer_state->wav_file); 4642afeea7fSMilanka Ringwald write_wav_header(writer_state->wav_file, writer_state->total_num_samples, btstack_sbc_decoder_num_channels(&decoder_state), btstack_sbc_decoder_sample_rate(&decoder_state),2); 465fcb08cdbSMilanka Ringwald fclose(writer_state->wav_file); 466fcb08cdbSMilanka Ringwald writer_state->wav_file = NULL; 467fcb08cdbSMilanka Ringwald } 468613518d1SMilanka Ringwald #endif 469fcb08cdbSMilanka Ringwald #endif 470c4e666bcSMatthias Ringwald 471c4e666bcSMatthias Ringwald negotiated_codec = -1; 472c4e666bcSMatthias Ringwald 473fcb08cdbSMilanka Ringwald #endif 474fcb08cdbSMilanka Ringwald } 475fcb08cdbSMilanka Ringwald 476fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 477fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 478fcb08cdbSMilanka Ringwald negotiated_codec = codec; 4792b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 48017cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 481220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 482fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 483fcb08cdbSMilanka Ringwald } else { 484fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 485fcb08cdbSMilanka Ringwald } 486fcb08cdbSMilanka Ringwald #endif 487fcb08cdbSMilanka Ringwald #endif 488fcb08cdbSMilanka Ringwald } 489fcb08cdbSMilanka Ringwald 490f7c85330SMatthias Ringwald void sco_demo_init(void){ 491f7c85330SMatthias Ringwald // status 4922b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 4932b89dbfcSMatthias Ringwald printf("SCO Demo: Sending and receiving audio via portaudio.\n"); 4942b89dbfcSMatthias Ringwald #endif 495f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 496f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 497f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 498f7c85330SMatthias Ringwald #else 499f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 500f7c85330SMatthias Ringwald #endif 501f7c85330SMatthias Ringwald #endif 502f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 503f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 504f7c85330SMatthias Ringwald #endif 505f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 506f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 507f7c85330SMatthias Ringwald #endif 508f7c85330SMatthias Ringwald 5092b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 510c4e666bcSMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 511c4e666bcSMatthias Ringwald #else 512f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 5137294d009SMatthias Ringwald #endif 514f7c85330SMatthias Ringwald 515f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 516f7c85330SMatthias Ringwald phase = 'a'; 517f7c85330SMatthias Ringwald #endif 518f7c85330SMatthias Ringwald } 519f7c85330SMatthias Ringwald 5201a919128SMatthias Ringwald void sco_report(void); 5211a919128SMatthias Ringwald void sco_report(void){ 5224a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 5234a96141eSMatthias Ringwald } 524f7c85330SMatthias Ringwald 525f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 526f7c85330SMatthias Ringwald 527f7c85330SMatthias Ringwald if (!sco_handle) return; 528f7c85330SMatthias Ringwald 529c4e666bcSMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 530c4e666bcSMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 531f7c85330SMatthias Ringwald 532f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 533f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 534f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 535220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 536c4e666bcSMatthias Ringwald // overwrite 537c4e666bcSMatthias Ringwald sco_payload_length = 24; 538c4e666bcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 539c4e666bcSMatthias Ringwald 540220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 541220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 542220eb563SMilanka Ringwald } 543220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 544d5e5f834SMatthias Ringwald if (msbc_file_out){ 545d76591efSMatthias Ringwald // log outgoing mSBC data for testing 546d5e5f834SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 547d76591efSMatthias Ringwald } 5487294d009SMatthias Ringwald 549*b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 550220eb563SMilanka Ringwald } else { 551c4e666bcSMatthias Ringwald const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME; 552c4e666bcSMatthias Ringwald sco_demo_sine_wave_int16_at_8000_hz(audio_samples_per_packet, (int16_t *) (sco_packet+3)); 553220eb563SMilanka Ringwald } 5541a919128SMatthias Ringwald #endif 5552b89dbfcSMatthias Ringwald 5562b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 5572b89dbfcSMatthias Ringwald 5582b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 5592b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 5602b89dbfcSMatthias Ringwald // MSBC 5612b89dbfcSMatthias Ringwald 5622b89dbfcSMatthias Ringwald // overwrite 5632b89dbfcSMatthias Ringwald sco_payload_length = 24; 5642b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 5652b89dbfcSMatthias Ringwald 566*b025eb5fSMatthias Ringwald if (pa_input_paused){ 567*b025eb5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ 568*b025eb5fSMatthias Ringwald // resume sending 569*b025eb5fSMatthias Ringwald pa_input_paused = 0; 5702b89dbfcSMatthias Ringwald } 571*b025eb5fSMatthias Ringwald } 572*b025eb5fSMatthias Ringwald 573*b025eb5fSMatthias Ringwald if (!pa_input_paused){ 574*b025eb5fSMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 575*b025eb5fSMatthias Ringwald if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){ 576*b025eb5fSMatthias Ringwald int16_t sample_buffer[num_samples]; 577*b025eb5fSMatthias Ringwald uint32_t bytes_read; 578*b025eb5fSMatthias Ringwald btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read); 579*b025eb5fSMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 580*b025eb5fSMatthias Ringwald num_audio_frames++; 581*b025eb5fSMatthias Ringwald } 582*b025eb5fSMatthias Ringwald } 583*b025eb5fSMatthias Ringwald 584*b025eb5fSMatthias Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 585*b025eb5fSMatthias Ringwald log_error("mSBC stream should not be empty."); 586*b025eb5fSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 587*b025eb5fSMatthias Ringwald pa_input_paused = 1; 588*b025eb5fSMatthias Ringwald } else { 5892b89dbfcSMatthias Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 5902b89dbfcSMatthias Ringwald if (msbc_file_out){ 5912b89dbfcSMatthias Ringwald // log outgoing mSBC data for testing 5922b89dbfcSMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 5932b89dbfcSMatthias Ringwald } 594*b025eb5fSMatthias Ringwald } 5952b89dbfcSMatthias Ringwald 5962b89dbfcSMatthias Ringwald } else { 5972b89dbfcSMatthias Ringwald // CVSD 5982b89dbfcSMatthias Ringwald 5992b89dbfcSMatthias 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); 6002b89dbfcSMatthias Ringwald // fill with silence while paused 6012b89dbfcSMatthias Ringwald int bytes_to_copy = sco_payload_length; 6022b89dbfcSMatthias Ringwald if (pa_input_paused){ 6032b89dbfcSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ 6042b89dbfcSMatthias Ringwald // resume sending 6052b89dbfcSMatthias Ringwald pa_input_paused = 0; 6062b89dbfcSMatthias Ringwald } 6072b89dbfcSMatthias Ringwald } 6082b89dbfcSMatthias Ringwald 6092b89dbfcSMatthias Ringwald // get data from ringbuffer 6102b89dbfcSMatthias Ringwald uint16_t pos = 0; 6112b89dbfcSMatthias Ringwald if (!pa_input_paused){ 6122b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 6132b89dbfcSMatthias Ringwald btstack_ring_buffer_read(&pa_input_ring_buffer, sco_packet + 3, bytes_to_copy, &bytes_read); 6142b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 6152b89dbfcSMatthias Ringwald pos += bytes_read; 6162b89dbfcSMatthias Ringwald } 6172b89dbfcSMatthias Ringwald 6182b89dbfcSMatthias Ringwald // fill with 0 if not enough 6192b89dbfcSMatthias Ringwald if (bytes_to_copy){ 6202b89dbfcSMatthias Ringwald memset(sco_packet + 3 + pos, 0, bytes_to_copy); 6212b89dbfcSMatthias Ringwald pa_input_paused = 1; 6222b89dbfcSMatthias Ringwald } 6232b89dbfcSMatthias Ringwald } 6242b89dbfcSMatthias Ringwald #else 6252b89dbfcSMatthias Ringwald // just send '0's 6262b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 6272b89dbfcSMatthias Ringwald sco_payload_length = 24; 6282b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 6292b89dbfcSMatthias Ringwald } 6302b89dbfcSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 6312b89dbfcSMatthias Ringwald #endif 6322b89dbfcSMatthias Ringwald #endif 6332b89dbfcSMatthias Ringwald 634f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 635c4e666bcSMatthias Ringwald memset(&sco_packet[3], phase++, sco_payload_length); 636f7c85330SMatthias Ringwald if (phase > 'z') phase = 'a'; 6371a919128SMatthias Ringwald #endif 6381a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 63938b2eaafSMatthias Ringwald int j; 640c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 64138b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 642f7c85330SMatthias Ringwald } 643f7c85330SMatthias Ringwald #endif 6441a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 6451a919128SMatthias Ringwald int j; 646c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6471a919128SMatthias Ringwald // sco_packet[3+j] = j & 1 ? 0x35 : 0x53; 6481a919128SMatthias Ringwald sco_packet[3+j] = 0x55; 6491a919128SMatthias Ringwald } 6501a919128SMatthias Ringwald #endif 6511a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00 6521a919128SMatthias Ringwald int j; 653c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6541a919128SMatthias Ringwald sco_packet[3+j] = 0x00; 6551a919128SMatthias Ringwald } 6561a919128SMatthias Ringwald // additional hack 6571a919128SMatthias Ringwald // big_endian_store_16(sco_packet, 5, phase++); 6581a919128SMatthias Ringwald (void) phase; 659f7c85330SMatthias Ringwald #endif 660220eb563SMilanka Ringwald 6612b89dbfcSMatthias Ringwald // test silence 6622b89dbfcSMatthias Ringwald // memset(sco_packet+3, 0, sco_payload_length); 6632b89dbfcSMatthias Ringwald 664c4e666bcSMatthias Ringwald // set handle + flags 665c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 666c4e666bcSMatthias Ringwald // set len 667c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 668c4e666bcSMatthias Ringwald // finally send packet 669f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 670f7c85330SMatthias Ringwald 671f7c85330SMatthias Ringwald // request another send event 672f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 673f7c85330SMatthias Ringwald 6744a96141eSMatthias Ringwald count_sent++; 6751a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55 6764a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 6771a919128SMatthias Ringwald #endif 678f7c85330SMatthias Ringwald } 679f7c85330SMatthias Ringwald 680f7c85330SMatthias Ringwald /** 681f7c85330SMatthias Ringwald * @brief Process received data 682f7c85330SMatthias Ringwald */ 6831a919128SMatthias Ringwald #define ANSI_COLOR_RED "\x1b[31m" 6841a919128SMatthias Ringwald #define ANSI_COLOR_GREEN "\x1b[32m" 6851a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW "\x1b[33m" 6861a919128SMatthias Ringwald #define ANSI_COLOR_BLUE "\x1b[34m" 6871a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m" 6881a919128SMatthias Ringwald #define ANSI_COLOR_CYAN "\x1b[36m" 6891a919128SMatthias Ringwald #define ANSI_COLOR_RESET "\x1b[0m" 6901a919128SMatthias Ringwald 691f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 692f7c85330SMatthias Ringwald 693fcb08cdbSMilanka Ringwald dump_data = 1; 6948b29cfc6SMatthias Ringwald 6954a96141eSMatthias Ringwald count_received++; 6961a919128SMatthias Ringwald static uint32_t packets = 0; 6971a919128SMatthias Ringwald static uint32_t crc_errors = 0; 6981a919128SMatthias Ringwald static uint32_t data_received = 0; 6991a919128SMatthias Ringwald static uint32_t byte_errors = 0; 7004a96141eSMatthias Ringwald 7011a919128SMatthias Ringwald data_received += size - 3; 7021a919128SMatthias Ringwald packets++; 7031a919128SMatthias Ringwald if (data_received > 100000){ 7041a919128SMatthias Ringwald printf("Summary: data %07u, packets %04u, packet with crc errors %0u, byte errors %04u\n", data_received, packets, crc_errors, byte_errors); 7051a919128SMatthias Ringwald crc_errors = 0; 7061a919128SMatthias Ringwald byte_errors = 0; 7071a919128SMatthias Ringwald data_received = 0; 7081a919128SMatthias Ringwald packets = 0; 7091a919128SMatthias Ringwald } 7104a96141eSMatthias Ringwald 7112b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 712c4e666bcSMatthias Ringwald switch (negotiated_codec){ 713c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 714fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 715c4e666bcSMatthias Ringwald break; 716c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 717fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 718c4e666bcSMatthias Ringwald break; 719c4e666bcSMatthias Ringwald default: 720c4e666bcSMatthias Ringwald break; 7218b29cfc6SMatthias Ringwald } 722dbb41bfeSMilanka Ringwald dump_data = 0; 7238b29cfc6SMatthias Ringwald #endif 7248b29cfc6SMatthias Ringwald 725b3f76298SMilanka Ringwald if (packet[1] & 0x30){ 7261a919128SMatthias Ringwald crc_errors++; 7271a919128SMatthias Ringwald // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 7281a919128SMatthias Ringwald // printf_hexdump(&packet[3], size-3); 729f7c85330SMatthias Ringwald return; 730f7c85330SMatthias Ringwald } 7318b29cfc6SMatthias Ringwald if (dump_data){ 732f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 7331a919128SMatthias Ringwald printf("data: "); 734f7c85330SMatthias Ringwald int i; 735f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 736f7c85330SMatthias Ringwald printf("%c", packet[i]); 737f7c85330SMatthias Ringwald } 738f7c85330SMatthias Ringwald printf("\n"); 7398b29cfc6SMatthias Ringwald dump_data = 0; 7401a919128SMatthias Ringwald #endif 7411a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 7421a919128SMatthias Ringwald // colored hexdump with expected 7431a919128SMatthias Ringwald static uint8_t expected_byte = 0; 7441a919128SMatthias Ringwald int i; 7451a919128SMatthias Ringwald printf("data: "); 7461a919128SMatthias Ringwald for (i=3;i<size;i++){ 7471a919128SMatthias Ringwald if (packet[i] != expected_byte){ 7481a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7491a919128SMatthias Ringwald } else { 7501a919128SMatthias Ringwald printf("%02x ", packet[i]); 7511a919128SMatthias Ringwald } 7521a919128SMatthias Ringwald expected_byte = packet[i]+1; 7531a919128SMatthias Ringwald } 7541a919128SMatthias Ringwald printf("\n"); 7551a919128SMatthias Ringwald #endif 756a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00 7571a919128SMatthias Ringwald int i; 7581a919128SMatthias Ringwald int contains_error = 0; 7591a919128SMatthias Ringwald for (i=3;i<size;i++){ 7601a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 7611a919128SMatthias Ringwald contains_error = 1; 7621a919128SMatthias Ringwald byte_errors++; 7631a919128SMatthias Ringwald } 7641a919128SMatthias Ringwald } 7651a919128SMatthias Ringwald if (contains_error){ 7661a919128SMatthias Ringwald printf("data: "); 7671a919128SMatthias Ringwald for (i=0;i<3;i++){ 7681a919128SMatthias Ringwald printf("%02x ", packet[i]); 7691a919128SMatthias Ringwald } 7701a919128SMatthias Ringwald for (i=3;i<size;i++){ 7711a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 7721a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7731a919128SMatthias Ringwald } else { 7741a919128SMatthias Ringwald printf("%02x ", packet[i]); 7751a919128SMatthias Ringwald } 7761a919128SMatthias Ringwald } 7771a919128SMatthias Ringwald printf("\n"); 7781a919128SMatthias Ringwald } 779f7c85330SMatthias Ringwald #endif 7808b29cfc6SMatthias Ringwald } 781f7c85330SMatthias Ringwald } 782