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 15459c97ae1SMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess 15559c97ae1SMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(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++]; 15959c97ae1SMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 16059c97ae1SMatthias Ringwald phase = 0; 16159c97ae1SMatthias Ringwald } 16259c97ae1SMatthias Ringwald } 16359c97ae1SMatthias Ringwald } 16459c97ae1SMatthias Ringwald 16559c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian 16659c97ae1SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(int num_samples, int16_t * data){ 16759c97ae1SMatthias Ringwald int i; 16859c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 16959c97ae1SMatthias Ringwald int16_t sample = sine_int16_at_16000hz[phase]; 17059c97ae1SMatthias Ringwald little_endian_store_16((uint8_t *) data, i * 2, sample); 17159c97ae1SMatthias Ringwald // ony use every second sample from 16khz table to get 8khz 17259c97ae1SMatthias Ringwald phase += 2; 173c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 17435fd3fb9SMatthias Ringwald phase = 0; 17535fd3fb9SMatthias Ringwald } 17635fd3fb9SMatthias Ringwald } 17735fd3fb9SMatthias Ringwald } 17835fd3fb9SMatthias Ringwald 179b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){ 18035fd3fb9SMatthias Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 18135fd3fb9SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 18235fd3fb9SMatthias Ringwald int16_t sample_buffer[num_samples]; 18359c97ae1SMatthias Ringwald sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer); 18435fd3fb9SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 18535fd3fb9SMatthias Ringwald num_audio_frames++; 18635fd3fb9SMatthias Ringwald } 1872b89dbfcSMatthias Ringwald #endif 188dbb41bfeSMilanka Ringwald 189dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 190c4e666bcSMatthias Ringwald static int portaudio_callback( const void *inputBuffer, void *outputBuffer, 191dbb41bfeSMilanka Ringwald unsigned long framesPerBuffer, 192dbb41bfeSMilanka Ringwald const PaStreamCallbackTimeInfo* timeInfo, 193dbb41bfeSMilanka Ringwald PaStreamCallbackFlags statusFlags, 194dbb41bfeSMilanka Ringwald void *userData ) { 195dbb41bfeSMilanka Ringwald (void) timeInfo; /* Prevent unused variable warnings. */ 196dbb41bfeSMilanka Ringwald (void) statusFlags; 197dbb41bfeSMilanka Ringwald (void) inputBuffer; 1983963d036SMatthias Ringwald (void) userData; 199dbb41bfeSMilanka Ringwald 2002b89dbfcSMatthias Ringwald // output part 2012b89dbfcSMatthias Ringwald 202c4e666bcSMatthias Ringwald // config based on codec 203c4e666bcSMatthias Ringwald int bytes_to_copy; 204c4e666bcSMatthias Ringwald int prebuffer_bytes; 205c4e666bcSMatthias Ringwald switch (negotiated_codec){ 206c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 207c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * MSBC_BYTES_PER_FRAME; 208c4e666bcSMatthias Ringwald prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES; 209c4e666bcSMatthias Ringwald break; 210c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 211c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * CVSD_BYTES_PER_FRAME; 212c4e666bcSMatthias Ringwald prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES; 213c4e666bcSMatthias Ringwald break; 214c4e666bcSMatthias Ringwald default: 215c4e666bcSMatthias Ringwald bytes_to_copy = framesPerBuffer * 2; // assume 1 channel / 16 bit audio samples 216c4e666bcSMatthias Ringwald prebuffer_bytes = 0xfffffff; 217c4e666bcSMatthias Ringwald break; 218dbb41bfeSMilanka Ringwald } 219dbb41bfeSMilanka Ringwald 220c4e666bcSMatthias Ringwald // fill with silence while paused 221463c9c89SMatthias Ringwald if (pa_output_paused){ 222463c9c89SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){ 223c4e666bcSMatthias Ringwald memset(outputBuffer, 0, bytes_to_copy); 224c4e666bcSMatthias Ringwald return 0; 225dbb41bfeSMilanka Ringwald } else { 226c4e666bcSMatthias Ringwald // resume playback 227463c9c89SMatthias Ringwald pa_output_paused = 0; 228dbb41bfeSMilanka Ringwald } 229c4e666bcSMatthias Ringwald } 230c4e666bcSMatthias Ringwald 231c4e666bcSMatthias Ringwald // get data from ringbuffer 232c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 233463c9c89SMatthias Ringwald btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read); 234c4e666bcSMatthias Ringwald bytes_to_copy -= bytes_read; 235c4e666bcSMatthias Ringwald 236c4e666bcSMatthias Ringwald // fill with 0 if not enough 237c4e666bcSMatthias Ringwald if (bytes_to_copy){ 238c4e666bcSMatthias Ringwald memset(outputBuffer + bytes_read, 0, bytes_to_copy); 239463c9c89SMatthias Ringwald pa_output_paused = 1; 240c4e666bcSMatthias Ringwald } 2412b89dbfcSMatthias Ringwald // end of output part 2428b29cfc6SMatthias Ringwald 2432b89dbfcSMatthias Ringwald // input part -- just store in ring buffer 2442b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 2452b89dbfcSMatthias Ringwald btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2); 2462b89dbfcSMatthias Ringwald pa_input_counter += framesPerBuffer * 2; 2472b89dbfcSMatthias Ringwald #endif 2482b89dbfcSMatthias Ringwald 2492b89dbfcSMatthias Ringwald return 0; 250c4e666bcSMatthias Ringwald } 251c4e666bcSMatthias Ringwald 252c4e666bcSMatthias Ringwald // return 1 if ok 253c4e666bcSMatthias Ringwald static int portaudio_initialize(int sample_rate){ 254c4e666bcSMatthias Ringwald PaError err; 255c4e666bcSMatthias Ringwald 256c4e666bcSMatthias Ringwald /* -- initialize PortAudio -- */ 257c4e666bcSMatthias Ringwald printf("PortAudio: Initialize\n"); 258c4e666bcSMatthias Ringwald err = Pa_Initialize(); 259c4e666bcSMatthias Ringwald if( err != paNoError ) return 0; 2602b89dbfcSMatthias Ringwald 261c4e666bcSMatthias Ringwald /* -- setup input and output -- */ 2622b89dbfcSMatthias Ringwald const PaDeviceInfo *deviceInfo; 2632b89dbfcSMatthias Ringwald PaStreamParameters * inputParameters = NULL; 2642b89dbfcSMatthias Ringwald PaStreamParameters outputParameters; 265c4e666bcSMatthias Ringwald outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 266c4e666bcSMatthias Ringwald outputParameters.channelCount = NUM_CHANNELS; 267c4e666bcSMatthias Ringwald outputParameters.sampleFormat = paInt16; 268c4e666bcSMatthias Ringwald outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 269c4e666bcSMatthias Ringwald outputParameters.hostApiSpecificStreamInfo = NULL; 2702b89dbfcSMatthias Ringwald deviceInfo = Pa_GetDeviceInfo( outputParameters.device ); 2712b89dbfcSMatthias Ringwald log_info("PortAudio: Output device: %s", deviceInfo->name); 2722b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 2732b89dbfcSMatthias Ringwald PaStreamParameters theInputParameters; 2742b89dbfcSMatthias Ringwald theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ 2752b89dbfcSMatthias Ringwald theInputParameters.channelCount = NUM_CHANNELS; 2762b89dbfcSMatthias Ringwald theInputParameters.sampleFormat = paInt16; 2772b89dbfcSMatthias Ringwald theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighOutputLatency; 2782b89dbfcSMatthias Ringwald theInputParameters.hostApiSpecificStreamInfo = NULL; 2792b89dbfcSMatthias Ringwald inputParameters = &theInputParameters; 2802b89dbfcSMatthias Ringwald deviceInfo = Pa_GetDeviceInfo( inputParameters->device ); 2812b89dbfcSMatthias Ringwald log_info("PortAudio: Input device: %s", deviceInfo->name); 2822b89dbfcSMatthias Ringwald #endif 2832b89dbfcSMatthias Ringwald 2842b89dbfcSMatthias Ringwald /* -- setup output stream -- */ 285c4e666bcSMatthias Ringwald printf("PortAudio: Open stream\n"); 286c4e666bcSMatthias Ringwald err = Pa_OpenStream( 2872b89dbfcSMatthias Ringwald &pa_stream, 2882b89dbfcSMatthias Ringwald inputParameters, 289c4e666bcSMatthias Ringwald &outputParameters, 290c4e666bcSMatthias Ringwald sample_rate, 291c4e666bcSMatthias Ringwald 0, 292c4e666bcSMatthias Ringwald paClipOff, /* we won't output out of range samples so don't bother clipping them */ 293c4e666bcSMatthias Ringwald portaudio_callback, 294c4e666bcSMatthias Ringwald NULL ); 295c4e666bcSMatthias Ringwald if (err != paNoError){ 296c4e666bcSMatthias Ringwald printf("Error opening portaudio stream: \"%s\"\n", Pa_GetErrorText(err)); 297c4e666bcSMatthias Ringwald return 0; 298c4e666bcSMatthias Ringwald } 299463c9c89SMatthias Ringwald memset(pa_output_ring_buffer_storage, 0, sizeof(pa_output_ring_buffer_storage)); 300463c9c89SMatthias Ringwald btstack_ring_buffer_init(&pa_output_ring_buffer, pa_output_ring_buffer_storage, sizeof(pa_output_ring_buffer_storage)); 3012b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 3022b89dbfcSMatthias Ringwald memset(pa_input_ring_buffer_storage, 0, sizeof(pa_input_ring_buffer_storage)); 3032b89dbfcSMatthias Ringwald btstack_ring_buffer_init(&pa_input_ring_buffer, pa_input_ring_buffer_storage, sizeof(pa_input_ring_buffer_storage)); 3042b89dbfcSMatthias Ringwald printf("PortAudio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&pa_input_ring_buffer)); 3052b89dbfcSMatthias Ringwald #endif 3062b89dbfcSMatthias Ringwald 3072b89dbfcSMatthias Ringwald /* -- start stream -- */ 3082b89dbfcSMatthias Ringwald err = Pa_StartStream(pa_stream); 3092b89dbfcSMatthias Ringwald if (err != paNoError){ 3102b89dbfcSMatthias Ringwald printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); 3112b89dbfcSMatthias Ringwald return 0; 3122b89dbfcSMatthias Ringwald } 3132b89dbfcSMatthias Ringwald pa_output_started = 1; 3142b89dbfcSMatthias Ringwald pa_output_paused = 1; 3152b89dbfcSMatthias Ringwald #ifdef USE_PORTAUDIO_INPUT 3162b89dbfcSMatthias Ringwald pa_input_started = 1; 3172b89dbfcSMatthias Ringwald pa_input_paused = 1; 3182b89dbfcSMatthias Ringwald #endif 3192b89dbfcSMatthias Ringwald 320c4e666bcSMatthias Ringwald return 1; 321c4e666bcSMatthias Ringwald } 3222b89dbfcSMatthias Ringwald 3232b89dbfcSMatthias Ringwald static void portaudio_terminate(void){ 3242b89dbfcSMatthias Ringwald if (!pa_stream) return; 3252b89dbfcSMatthias Ringwald 3262b89dbfcSMatthias Ringwald PaError err; 3272b89dbfcSMatthias Ringwald printf("PortAudio: Stop Stream\n"); 3282b89dbfcSMatthias Ringwald err = Pa_StopStream(pa_stream); 3292b89dbfcSMatthias Ringwald if (err != paNoError){ 3302b89dbfcSMatthias Ringwald printf("Error stopping the stream: \"%s\"\n", Pa_GetErrorText(err)); 3312b89dbfcSMatthias Ringwald return; 3322b89dbfcSMatthias Ringwald } 3332b89dbfcSMatthias Ringwald printf("PortAudio: Close Stream\n"); 3342b89dbfcSMatthias Ringwald err = Pa_CloseStream(pa_stream); 3352b89dbfcSMatthias Ringwald if (err != paNoError){ 3362b89dbfcSMatthias Ringwald printf("Error closing the stream: \"%s\"\n", Pa_GetErrorText(err)); 3372b89dbfcSMatthias Ringwald return; 3382b89dbfcSMatthias Ringwald } 3392b89dbfcSMatthias Ringwald pa_stream = NULL; 3402b89dbfcSMatthias Ringwald printf("PortAudio: Terminate\n"); 3412b89dbfcSMatthias Ringwald err = Pa_Terminate(); 3422b89dbfcSMatthias Ringwald if (err != paNoError){ 3432b89dbfcSMatthias Ringwald printf("Error terminating portaudio: \"%s\"\n", Pa_GetErrorText(err)); 3442b89dbfcSMatthias Ringwald return; 3452b89dbfcSMatthias Ringwald } 3462b89dbfcSMatthias Ringwald } 347c4e666bcSMatthias Ringwald #endif 348c4e666bcSMatthias Ringwald 349c4e666bcSMatthias Ringwald 350c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 351c4e666bcSMatthias Ringwald UNUSED(context); 352c4e666bcSMatthias Ringwald UNUSED(sample_rate); 353c4e666bcSMatthias Ringwald 354c4e666bcSMatthias Ringwald // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); 355c4e666bcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 3565303ddeeSMatthias Ringwald // samples in callback in host endianess, ready for PortAudio playback 357463c9c89SMatthias Ringwald btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 3589ec2630cSMatthias Ringwald #else 3599ec2630cSMatthias Ringwald UNUSED(num_channels); 360dbb41bfeSMilanka Ringwald #endif 361dbb41bfeSMilanka Ringwald 362fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 363fcb08cdbSMilanka Ringwald 364fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 365fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 366fcb08cdbSMilanka Ringwald 367fbc7c9f2SMilanka Ringwald wav_writer_write_int16(num_samples, data); 368fcb08cdbSMilanka Ringwald 369fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 370fcb08cdbSMilanka Ringwald sco_demo_close(); 371fcb08cdbSMilanka Ringwald } 372fcb08cdbSMilanka Ringwald } 373fcb08cdbSMilanka Ringwald 374fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 375c4e666bcSMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 376c4e666bcSMatthias Ringwald 377c4e666bcSMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE); 378fbc7c9f2SMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 379fcb08cdbSMilanka Ringwald 380c4e666bcSMatthias Ringwald num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 381220eb563SMilanka Ringwald 382220eb563SMilanka Ringwald hfp_msbc_init(); 3832b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 384b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 3852b89dbfcSMatthias Ringwald #endif 386973d7173SMatthias Ringwald 387d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME 388d5e5f834SMatthias Ringwald msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 389d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 390d5e5f834SMatthias Ringwald #endif 3912b89dbfcSMatthias Ringwald 3927294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 393d5e5f834SMatthias Ringwald msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 394d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 3957294d009SMatthias Ringwald #endif 396dbb41bfeSMilanka Ringwald 397dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 398c4e666bcSMatthias Ringwald portaudio_initialize(MSBC_SAMPLE_RATE); 399dbb41bfeSMilanka Ringwald #endif 400fcb08cdbSMilanka Ringwald } 401fcb08cdbSMilanka Ringwald 402fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 403fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 404d5e5f834SMatthias Ringwald if (msbc_file_in){ 405d5e5f834SMatthias Ringwald // log incoming mSBC data for testing 406d5e5f834SMatthias Ringwald fwrite(packet+3, size-3, 1, msbc_file_in); 407d5e5f834SMatthias Ringwald } 408fcb08cdbSMilanka Ringwald } 409dbb41bfeSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 410fcb08cdbSMilanka Ringwald } 411fcb08cdbSMilanka Ringwald 412fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){ 413c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 414c4e666bcSMatthias Ringwald 415c4e666bcSMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE); 416fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 417c4e666bcSMatthias Ringwald 418c4e666bcSMatthias Ringwald num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 419dbb41bfeSMilanka Ringwald 420dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 421c4e666bcSMatthias Ringwald portaudio_initialize(CVSD_SAMPLE_RATE); 422dbb41bfeSMilanka Ringwald #endif 423fbc7c9f2SMilanka Ringwald } 424fbc7c9f2SMilanka Ringwald 425fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 426dbb41bfeSMilanka Ringwald if (!num_samples_to_write) return; 4275303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 4281f8694ccSMatthias Ringwald 4291f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 4301f8694ccSMatthias Ringwald printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); 4311f8694ccSMatthias Ringwald return; 4321f8694ccSMatthias Ringwald } 433c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 434c4e666bcSMatthias Ringwald const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME; 435fcb08cdbSMilanka Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 436379d044eSMilanka Ringwald 4375303ddeeSMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 4385303ddeeSMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 439fcb08cdbSMilanka Ringwald num_samples_to_write -= samples_to_write; 440fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 441fcb08cdbSMilanka Ringwald sco_demo_close(); 442fcb08cdbSMilanka Ringwald } 4435303ddeeSMatthias Ringwald 4445303ddeeSMatthias Ringwald // convert into host endian 4455303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 4465303ddeeSMatthias Ringwald int i; 4475303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 4485303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 4495303ddeeSMatthias Ringwald } 4505303ddeeSMatthias Ringwald 451*e36764ddSMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out); 4525303ddeeSMatthias Ringwald 453dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 454463c9c89SMatthias Ringwald btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 455dbb41bfeSMilanka Ringwald #endif 456fcb08cdbSMilanka Ringwald } 457fcb08cdbSMilanka Ringwald 458fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 459c4e666bcSMatthias Ringwald printf("SCO demo close\n"); 4602b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 4612b89dbfcSMatthias Ringwald 46226463303SMilanka Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 463fbc7c9f2SMilanka Ringwald wav_writer_close(); 4642b89dbfcSMatthias Ringwald #endif 46526463303SMilanka Ringwald printf("SCO demo statistics: "); 46626463303SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 46726463303SMilanka 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); 46826463303SMilanka Ringwald } else { 46926463303SMilanka 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); 47026463303SMilanka Ringwald } 47126463303SMilanka Ringwald 472dbb41bfeSMilanka Ringwald #ifdef HAVE_PORTAUDIO 4732b89dbfcSMatthias Ringwald portaudio_terminate(); 474dbb41bfeSMilanka Ringwald #endif 475fcb08cdbSMilanka Ringwald 476c4e666bcSMatthias Ringwald #ifdef SCO_WAV_FILENAME 477613518d1SMilanka Ringwald #if 0 478fcb08cdbSMilanka Ringwald printf("SCO Demo: closing wav file\n"); 479220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 4806e046a36SMatthias Ringwald wav_writer_state_t * writer_state = &wav_writer_state; 481fcb08cdbSMilanka Ringwald if (!writer_state->wav_file) return; 482fcb08cdbSMilanka Ringwald rewind(writer_state->wav_file); 4832afeea7fSMilanka 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); 484fcb08cdbSMilanka Ringwald fclose(writer_state->wav_file); 485fcb08cdbSMilanka Ringwald writer_state->wav_file = NULL; 486fcb08cdbSMilanka Ringwald } 487613518d1SMilanka Ringwald #endif 488fcb08cdbSMilanka Ringwald #endif 489c4e666bcSMatthias Ringwald 490c4e666bcSMatthias Ringwald negotiated_codec = -1; 491c4e666bcSMatthias Ringwald 492fcb08cdbSMilanka Ringwald #endif 493fcb08cdbSMilanka Ringwald } 494fcb08cdbSMilanka Ringwald 495fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 496fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 497fcb08cdbSMilanka Ringwald negotiated_codec = codec; 4982b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 49917cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 500220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 501fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 502fcb08cdbSMilanka Ringwald } else { 503fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 504fcb08cdbSMilanka Ringwald } 505fcb08cdbSMilanka Ringwald #endif 506fcb08cdbSMilanka Ringwald #endif 507fcb08cdbSMilanka Ringwald } 508fcb08cdbSMilanka Ringwald 509f7c85330SMatthias Ringwald void sco_demo_init(void){ 510f7c85330SMatthias Ringwald // status 5112b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 5122b89dbfcSMatthias Ringwald printf("SCO Demo: Sending and receiving audio via portaudio.\n"); 5132b89dbfcSMatthias Ringwald #endif 514f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 515f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 516f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 517f7c85330SMatthias Ringwald #else 518f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 519f7c85330SMatthias Ringwald #endif 520f7c85330SMatthias Ringwald #endif 521f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 522f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 523f7c85330SMatthias Ringwald #endif 524f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 525f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 526f7c85330SMatthias Ringwald #endif 527f7c85330SMatthias Ringwald 5282b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 529c4e666bcSMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 530c4e666bcSMatthias Ringwald #else 531f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 5327294d009SMatthias Ringwald #endif 533f7c85330SMatthias Ringwald 534f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 535f7c85330SMatthias Ringwald phase = 'a'; 536f7c85330SMatthias Ringwald #endif 537f7c85330SMatthias Ringwald } 538f7c85330SMatthias Ringwald 5391a919128SMatthias Ringwald void sco_report(void); 5401a919128SMatthias Ringwald void sco_report(void){ 5414a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 5424a96141eSMatthias Ringwald } 543f7c85330SMatthias Ringwald 544f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 545f7c85330SMatthias Ringwald 546f7c85330SMatthias Ringwald if (!sco_handle) return; 547f7c85330SMatthias Ringwald 548c4e666bcSMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 549c4e666bcSMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 550f7c85330SMatthias Ringwald 551f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 552f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 553f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 554220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 555c4e666bcSMatthias Ringwald // overwrite 556c4e666bcSMatthias Ringwald sco_payload_length = 24; 557c4e666bcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 558c4e666bcSMatthias Ringwald 559220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 560220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 561220eb563SMilanka Ringwald } 562220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 563d5e5f834SMatthias Ringwald if (msbc_file_out){ 564d76591efSMatthias Ringwald // log outgoing mSBC data for testing 565d5e5f834SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 566d76591efSMatthias Ringwald } 5677294d009SMatthias Ringwald 568b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 569220eb563SMilanka Ringwald } else { 570c4e666bcSMatthias Ringwald const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME; 57159c97ae1SMatthias Ringwald sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, (int16_t *) (sco_packet+3)); 572220eb563SMilanka Ringwald } 5731a919128SMatthias Ringwald #endif 5742b89dbfcSMatthias Ringwald 5752b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 5762b89dbfcSMatthias Ringwald 5772b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 5782b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 5792b89dbfcSMatthias Ringwald // MSBC 5802b89dbfcSMatthias Ringwald 5812b89dbfcSMatthias Ringwald // overwrite 5822b89dbfcSMatthias Ringwald sco_payload_length = 24; 5832b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 5842b89dbfcSMatthias Ringwald 585b025eb5fSMatthias Ringwald if (pa_input_paused){ 586b025eb5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ 587b025eb5fSMatthias Ringwald // resume sending 588b025eb5fSMatthias Ringwald pa_input_paused = 0; 5892b89dbfcSMatthias Ringwald } 590b025eb5fSMatthias Ringwald } 591b025eb5fSMatthias Ringwald 592b025eb5fSMatthias Ringwald if (!pa_input_paused){ 593b025eb5fSMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 594b025eb5fSMatthias Ringwald if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){ 595b025eb5fSMatthias Ringwald int16_t sample_buffer[num_samples]; 596b025eb5fSMatthias Ringwald uint32_t bytes_read; 597b025eb5fSMatthias Ringwald btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read); 598b025eb5fSMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 599b025eb5fSMatthias Ringwald num_audio_frames++; 600b025eb5fSMatthias Ringwald } 601b025eb5fSMatthias Ringwald } 602b025eb5fSMatthias Ringwald 603b025eb5fSMatthias Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 604b025eb5fSMatthias Ringwald log_error("mSBC stream should not be empty."); 605b025eb5fSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 606b025eb5fSMatthias Ringwald pa_input_paused = 1; 607b025eb5fSMatthias Ringwald } else { 6082b89dbfcSMatthias Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 6092b89dbfcSMatthias Ringwald if (msbc_file_out){ 6102b89dbfcSMatthias Ringwald // log outgoing mSBC data for testing 6112b89dbfcSMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 6122b89dbfcSMatthias Ringwald } 613b025eb5fSMatthias Ringwald } 6142b89dbfcSMatthias Ringwald 6152b89dbfcSMatthias Ringwald } else { 6162b89dbfcSMatthias Ringwald // CVSD 6172b89dbfcSMatthias Ringwald 6182b89dbfcSMatthias 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); 6192b89dbfcSMatthias Ringwald // fill with silence while paused 6202b89dbfcSMatthias Ringwald int bytes_to_copy = sco_payload_length; 6212b89dbfcSMatthias Ringwald if (pa_input_paused){ 6222b89dbfcSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ 6232b89dbfcSMatthias Ringwald // resume sending 6242b89dbfcSMatthias Ringwald pa_input_paused = 0; 6252b89dbfcSMatthias Ringwald } 6262b89dbfcSMatthias Ringwald } 6272b89dbfcSMatthias Ringwald 6282b89dbfcSMatthias Ringwald // get data from ringbuffer 6292b89dbfcSMatthias Ringwald uint16_t pos = 0; 6308fd6902dSMatthias Ringwald uint8_t * sample_data = &sco_packet[3]; 6312b89dbfcSMatthias Ringwald if (!pa_input_paused){ 6322b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 6338fd6902dSMatthias Ringwald btstack_ring_buffer_read(&pa_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read); 6348fd6902dSMatthias Ringwald // flip 16 on big endian systems 6358fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 6368fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 6378fd6902dSMatthias Ringwald int i; 6388fd6902dSMatthias Ringwald for (i=0;i<bytes_read;i+=2){ 6398fd6902dSMatthias Ringwald uint8_t tmp = sample_data[i*2]; 6408fd6902dSMatthias Ringwald sample_data[i*2] = sample_data[i*2+1]; 6418fd6902dSMatthias Ringwald sample_data[i*2+1] = tmp; 6428fd6902dSMatthias Ringwald } 6438fd6902dSMatthias Ringwald } 6442b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 6452b89dbfcSMatthias Ringwald pos += bytes_read; 6462b89dbfcSMatthias Ringwald } 6472b89dbfcSMatthias Ringwald 6482b89dbfcSMatthias Ringwald // fill with 0 if not enough 6492b89dbfcSMatthias Ringwald if (bytes_to_copy){ 6508fd6902dSMatthias Ringwald memset(sample_data + pos, 0, bytes_to_copy); 6512b89dbfcSMatthias Ringwald pa_input_paused = 1; 6522b89dbfcSMatthias Ringwald } 6532b89dbfcSMatthias Ringwald } 6542b89dbfcSMatthias Ringwald #else 6552b89dbfcSMatthias Ringwald // just send '0's 6562b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 6572b89dbfcSMatthias Ringwald sco_payload_length = 24; 6582b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 6592b89dbfcSMatthias Ringwald } 6602b89dbfcSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 6612b89dbfcSMatthias Ringwald #endif 6622b89dbfcSMatthias Ringwald #endif 6632b89dbfcSMatthias Ringwald 664f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 665c4e666bcSMatthias Ringwald memset(&sco_packet[3], phase++, sco_payload_length); 666f7c85330SMatthias Ringwald if (phase > 'z') phase = 'a'; 6671a919128SMatthias Ringwald #endif 6681a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 66938b2eaafSMatthias Ringwald int j; 670c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 67138b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 672f7c85330SMatthias Ringwald } 673f7c85330SMatthias Ringwald #endif 6741a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 6751a919128SMatthias Ringwald int j; 676c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6771a919128SMatthias Ringwald // sco_packet[3+j] = j & 1 ? 0x35 : 0x53; 6781a919128SMatthias Ringwald sco_packet[3+j] = 0x55; 6791a919128SMatthias Ringwald } 6801a919128SMatthias Ringwald #endif 6811a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00 6821a919128SMatthias Ringwald int j; 683c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6841a919128SMatthias Ringwald sco_packet[3+j] = 0x00; 6851a919128SMatthias Ringwald } 6861a919128SMatthias Ringwald // additional hack 6871a919128SMatthias Ringwald // big_endian_store_16(sco_packet, 5, phase++); 6881a919128SMatthias Ringwald (void) phase; 689f7c85330SMatthias Ringwald #endif 690220eb563SMilanka Ringwald 6912b89dbfcSMatthias Ringwald // test silence 6922b89dbfcSMatthias Ringwald // memset(sco_packet+3, 0, sco_payload_length); 6932b89dbfcSMatthias Ringwald 694c4e666bcSMatthias Ringwald // set handle + flags 695c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 696c4e666bcSMatthias Ringwald // set len 697c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 698c4e666bcSMatthias Ringwald // finally send packet 699f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 700f7c85330SMatthias Ringwald 701f7c85330SMatthias Ringwald // request another send event 702f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 703f7c85330SMatthias Ringwald 7044a96141eSMatthias Ringwald count_sent++; 7051a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55 7064a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 7071a919128SMatthias Ringwald #endif 708f7c85330SMatthias Ringwald } 709f7c85330SMatthias Ringwald 710f7c85330SMatthias Ringwald /** 711f7c85330SMatthias Ringwald * @brief Process received data 712f7c85330SMatthias Ringwald */ 7131a919128SMatthias Ringwald #define ANSI_COLOR_RED "\x1b[31m" 7141a919128SMatthias Ringwald #define ANSI_COLOR_GREEN "\x1b[32m" 7151a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW "\x1b[33m" 7161a919128SMatthias Ringwald #define ANSI_COLOR_BLUE "\x1b[34m" 7171a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m" 7181a919128SMatthias Ringwald #define ANSI_COLOR_CYAN "\x1b[36m" 7191a919128SMatthias Ringwald #define ANSI_COLOR_RESET "\x1b[0m" 7201a919128SMatthias Ringwald 721f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 722f7c85330SMatthias Ringwald 723fcb08cdbSMilanka Ringwald dump_data = 1; 7248b29cfc6SMatthias Ringwald 7254a96141eSMatthias Ringwald count_received++; 7261a919128SMatthias Ringwald static uint32_t packets = 0; 7271a919128SMatthias Ringwald static uint32_t crc_errors = 0; 7281a919128SMatthias Ringwald static uint32_t data_received = 0; 7291a919128SMatthias Ringwald static uint32_t byte_errors = 0; 7304a96141eSMatthias Ringwald 7311a919128SMatthias Ringwald data_received += size - 3; 7321a919128SMatthias Ringwald packets++; 7331a919128SMatthias Ringwald if (data_received > 100000){ 7341a919128SMatthias Ringwald printf("Summary: data %07u, packets %04u, packet with crc errors %0u, byte errors %04u\n", data_received, packets, crc_errors, byte_errors); 7351a919128SMatthias Ringwald crc_errors = 0; 7361a919128SMatthias Ringwald byte_errors = 0; 7371a919128SMatthias Ringwald data_received = 0; 7381a919128SMatthias Ringwald packets = 0; 7391a919128SMatthias Ringwald } 7404a96141eSMatthias Ringwald 7412b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 742c4e666bcSMatthias Ringwald switch (negotiated_codec){ 743c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 744fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 745c4e666bcSMatthias Ringwald break; 746c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 747fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 748c4e666bcSMatthias Ringwald break; 749c4e666bcSMatthias Ringwald default: 750c4e666bcSMatthias Ringwald break; 7518b29cfc6SMatthias Ringwald } 752dbb41bfeSMilanka Ringwald dump_data = 0; 7538b29cfc6SMatthias Ringwald #endif 7548b29cfc6SMatthias Ringwald 755b3f76298SMilanka Ringwald if (packet[1] & 0x30){ 7561a919128SMatthias Ringwald crc_errors++; 7571a919128SMatthias Ringwald // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 7581a919128SMatthias Ringwald // printf_hexdump(&packet[3], size-3); 759f7c85330SMatthias Ringwald return; 760f7c85330SMatthias Ringwald } 7618b29cfc6SMatthias Ringwald if (dump_data){ 762f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 7631a919128SMatthias Ringwald printf("data: "); 764f7c85330SMatthias Ringwald int i; 765f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 766f7c85330SMatthias Ringwald printf("%c", packet[i]); 767f7c85330SMatthias Ringwald } 768f7c85330SMatthias Ringwald printf("\n"); 7698b29cfc6SMatthias Ringwald dump_data = 0; 7701a919128SMatthias Ringwald #endif 7711a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 7721a919128SMatthias Ringwald // colored hexdump with expected 7731a919128SMatthias Ringwald static uint8_t expected_byte = 0; 7741a919128SMatthias Ringwald int i; 7751a919128SMatthias Ringwald printf("data: "); 7761a919128SMatthias Ringwald for (i=3;i<size;i++){ 7771a919128SMatthias Ringwald if (packet[i] != expected_byte){ 7781a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7791a919128SMatthias Ringwald } else { 7801a919128SMatthias Ringwald printf("%02x ", packet[i]); 7811a919128SMatthias Ringwald } 7821a919128SMatthias Ringwald expected_byte = packet[i]+1; 7831a919128SMatthias Ringwald } 7841a919128SMatthias Ringwald printf("\n"); 7851a919128SMatthias Ringwald #endif 786a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00 7871a919128SMatthias Ringwald int i; 7881a919128SMatthias Ringwald int contains_error = 0; 7891a919128SMatthias Ringwald for (i=3;i<size;i++){ 7901a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 7911a919128SMatthias Ringwald contains_error = 1; 7921a919128SMatthias Ringwald byte_errors++; 7931a919128SMatthias Ringwald } 7941a919128SMatthias Ringwald } 7951a919128SMatthias Ringwald if (contains_error){ 7961a919128SMatthias Ringwald printf("data: "); 7971a919128SMatthias Ringwald for (i=0;i<3;i++){ 7981a919128SMatthias Ringwald printf("%02x ", packet[i]); 7991a919128SMatthias Ringwald } 8001a919128SMatthias Ringwald for (i=3;i<size;i++){ 8011a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 8021a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 8031a919128SMatthias Ringwald } else { 8041a919128SMatthias Ringwald printf("%02x ", packet[i]); 8051a919128SMatthias Ringwald } 8061a919128SMatthias Ringwald } 8071a919128SMatthias Ringwald printf("\n"); 8081a919128SMatthias Ringwald } 809f7c85330SMatthias Ringwald #endif 8108b29cfc6SMatthias Ringwald } 811f7c85330SMatthias Ringwald } 812