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 432ec72fbbSMilanka Ringwald #include <stdio.h> 442ec72fbbSMilanka Ringwald 45f7c85330SMatthias Ringwald #include "sco_demo_util.h" 46fcb08cdbSMilanka Ringwald #include "btstack_debug.h" 4735fd3fb9SMatthias Ringwald #include "classic/btstack_sbc.h" 4835fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h" 4935fd3fb9SMatthias Ringwald #include "classic/hfp_msbc.h" 5035fd3fb9SMatthias Ringwald #include "classic/hfp.h" 51fcb08cdbSMilanka Ringwald 5235fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 53fbc7c9f2SMilanka Ringwald #include "wav_util.h" 5435fd3fb9SMatthias Ringwald #endif 55fbc7c9f2SMilanka Ringwald 56f7c85330SMatthias Ringwald // configure test mode 57f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE 0 58f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII 1 59f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER 2 60f7c85330SMatthias Ringwald 618b29cfc6SMatthias Ringwald 62f7c85330SMatthias Ringwald // SCO demo configuration 63fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE 64f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 65f7c85330SMatthias Ringwald 668b29cfc6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 678b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 68d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 69*2308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME "sco_input.msbc" 70220eb563SMilanka Ringwald 71202da317SMilanka Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15 728b29cfc6SMatthias Ringwald #endif 738b29cfc6SMatthias Ringwald 74f7c85330SMatthias Ringwald 75f7c85330SMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) 76f7c85330SMatthias Ringwald #define USE_PORTAUDIO 77f7c85330SMatthias Ringwald #endif 78f7c85330SMatthias Ringwald 79f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 80f7c85330SMatthias Ringwald #include <portaudio.h> 81dbb41bfeSMilanka Ringwald #include "btstack_ring_buffer.h" 82dbb41bfeSMilanka Ringwald 838b29cfc6SMatthias Ringwald // portaudio config 848b29cfc6SMatthias Ringwald #define NUM_CHANNELS 1 85dbb41bfeSMilanka Ringwald 86dbb41bfeSMilanka Ringwald #define CVSD_SAMPLE_RATE 8000 87dbb41bfeSMilanka Ringwald #define CVSD_FRAMES_PER_BUFFER 24 88dbb41bfeSMilanka Ringwald #define CVSD_PA_SAMPLE_TYPE paInt8 89dbb41bfeSMilanka Ringwald #define CVSD_BYTES_PER_FRAME (1*NUM_CHANNELS) 90dbb41bfeSMilanka Ringwald #define CVSD_PREBUFFER_MS 5 91dbb41bfeSMilanka Ringwald #define CVSD_PREBUFFER_BYTES (CVSD_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME) 92dbb41bfeSMilanka Ringwald 93dbb41bfeSMilanka Ringwald #define MSBC_SAMPLE_RATE 16000 94dbb41bfeSMilanka Ringwald #define MSBC_FRAMES_PER_BUFFER 120 95dbb41bfeSMilanka Ringwald #define MSBC_PA_SAMPLE_TYPE paInt16 96dbb41bfeSMilanka Ringwald #define MSBC_BYTES_PER_FRAME (2*NUM_CHANNELS) 97dbb41bfeSMilanka Ringwald #define MSBC_PREBUFFER_MS 50 98dbb41bfeSMilanka Ringwald #define MSBC_PREBUFFER_BYTES (MSBC_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME) 99dbb41bfeSMilanka Ringwald 100f7c85330SMatthias Ringwald // portaudio globals 101f7c85330SMatthias Ringwald static PaStream * stream; 102dbb41bfeSMilanka Ringwald static uint8_t pa_stream_started = 0; 103dbb41bfeSMilanka Ringwald 104dbb41bfeSMilanka Ringwald static uint8_t ring_buffer_storage[2*MSBC_PREBUFFER_BYTES]; 105dbb41bfeSMilanka Ringwald static btstack_ring_buffer_t ring_buffer; 106f7c85330SMatthias Ringwald #endif 107f7c85330SMatthias Ringwald 108fcb08cdbSMilanka Ringwald 109fcb08cdbSMilanka Ringwald static int dump_data = 1; 110fcb08cdbSMilanka Ringwald static int count_sent = 0; 111fcb08cdbSMilanka Ringwald static int count_received = 0; 112d76591efSMatthias Ringwald static uint8_t negotiated_codec = 0; 113220eb563SMilanka Ringwald static int num_audio_frames = 0; 114fcb08cdbSMilanka Ringwald 115d5e5f834SMatthias Ringwald FILE * msbc_file_in; 116d5e5f834SMatthias Ringwald FILE * msbc_file_out; 1177294d009SMatthias Ringwald 118f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 119d6a06398SMatthias Ringwald 12035fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, at 8000 kz 12135fd3fb9SMatthias Ringwald static const uint8_t sine_uint8[] = { 12235fd3fb9SMatthias Ringwald 0, 15, 31, 46, 61, 74, 86, 97, 107, 114, 12335fd3fb9SMatthias Ringwald 120, 124, 126, 126, 124, 120, 114, 107, 97, 86, 12435fd3fb9SMatthias Ringwald 74, 61, 46, 31, 15, 0, 241, 225, 210, 195, 12535fd3fb9SMatthias Ringwald 182, 170, 159, 149, 142, 136, 132, 130, 130, 132, 12635fd3fb9SMatthias Ringwald 136, 142, 149, 159, 170, 182, 195, 210, 225, 241, 12735fd3fb9SMatthias Ringwald }; 12835fd3fb9SMatthias Ringwald 12935fd3fb9SMatthias Ringwald 13035fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz 13135fd3fb9SMatthias Ringwald static const int16_t sine_int16[] = { 13235fd3fb9SMatthias Ringwald 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 13335fd3fb9SMatthias Ringwald 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 13435fd3fb9SMatthias Ringwald 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 13535fd3fb9SMatthias Ringwald 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 13635fd3fb9SMatthias Ringwald 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 13735fd3fb9SMatthias Ringwald 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 13835fd3fb9SMatthias Ringwald -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 13935fd3fb9SMatthias Ringwald -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 14035fd3fb9SMatthias Ringwald -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 14135fd3fb9SMatthias Ringwald -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 14235fd3fb9SMatthias Ringwald }; 14335fd3fb9SMatthias Ringwald 14435fd3fb9SMatthias Ringwald static int phase = 0; 14535fd3fb9SMatthias Ringwald static void sco_demo_sine_wave_int8(int num_samples, int8_t * data){ 14635fd3fb9SMatthias Ringwald int i; 14735fd3fb9SMatthias Ringwald for (i=0; i<num_samples; i++){ 14835fd3fb9SMatthias Ringwald data[i] = (int8_t)sine_uint8[phase]; 14935fd3fb9SMatthias Ringwald phase++; 15035fd3fb9SMatthias Ringwald if (phase >= sizeof(sine_uint8)) phase = 0; 15135fd3fb9SMatthias Ringwald } 15235fd3fb9SMatthias Ringwald } 15335fd3fb9SMatthias Ringwald 15435fd3fb9SMatthias Ringwald static void sco_demo_sine_wave_int16(int num_samples, int16_t * data){ 15535fd3fb9SMatthias Ringwald int i; 15635fd3fb9SMatthias Ringwald for (i=0; i < num_samples; i++){ 15735fd3fb9SMatthias Ringwald data[i] = sine_int16[phase++]; 15835fd3fb9SMatthias Ringwald if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){ 15935fd3fb9SMatthias Ringwald phase = 0; 16035fd3fb9SMatthias Ringwald } 16135fd3fb9SMatthias Ringwald } 16235fd3fb9SMatthias Ringwald } 16335fd3fb9SMatthias Ringwald 16435fd3fb9SMatthias Ringwald static void sco_demo_fill_audio_frame(void){ 16535fd3fb9SMatthias Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 16635fd3fb9SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 16735fd3fb9SMatthias Ringwald int16_t sample_buffer[num_samples]; 16835fd3fb9SMatthias Ringwald sco_demo_sine_wave_int16(num_samples, sample_buffer); 16935fd3fb9SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 17035fd3fb9SMatthias Ringwald num_audio_frames++; 17135fd3fb9SMatthias Ringwald } 172f7c85330SMatthias Ringwald 1738b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME 1742afeea7fSMilanka Ringwald static btstack_sbc_decoder_state_t decoder_state; 17582e01da0SMilanka Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state; 176dbb41bfeSMilanka Ringwald static int num_samples_to_write; 177dbb41bfeSMilanka Ringwald 178dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 179dbb41bfeSMilanka Ringwald static int patestCallback( const void *inputBuffer, void *outputBuffer, 180dbb41bfeSMilanka Ringwald unsigned long framesPerBuffer, 181dbb41bfeSMilanka Ringwald const PaStreamCallbackTimeInfo* timeInfo, 182dbb41bfeSMilanka Ringwald PaStreamCallbackFlags statusFlags, 183dbb41bfeSMilanka Ringwald void *userData ) { 184dbb41bfeSMilanka Ringwald (void) timeInfo; /* Prevent unused variable warnings. */ 185dbb41bfeSMilanka Ringwald (void) statusFlags; 186dbb41bfeSMilanka Ringwald (void) inputBuffer; 187dbb41bfeSMilanka Ringwald 188dbb41bfeSMilanka Ringwald uint32_t bytes_read = 0; 189dbb41bfeSMilanka Ringwald int bytes_per_buffer = framesPerBuffer; 190dbb41bfeSMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 191dbb41bfeSMilanka Ringwald bytes_per_buffer *= MSBC_BYTES_PER_FRAME; 192dbb41bfeSMilanka Ringwald } else { 193dbb41bfeSMilanka Ringwald bytes_per_buffer *= CVSD_BYTES_PER_FRAME; 194dbb41bfeSMilanka Ringwald } 195dbb41bfeSMilanka Ringwald 196dbb41bfeSMilanka Ringwald if (btstack_ring_buffer_bytes_available(&ring_buffer) >= bytes_per_buffer){ 197dbb41bfeSMilanka Ringwald btstack_ring_buffer_read(&ring_buffer, outputBuffer, bytes_per_buffer, &bytes_read); 198dbb41bfeSMilanka Ringwald } else { 199dbb41bfeSMilanka Ringwald printf("NOT ENOUGH DATA!\n"); 200dbb41bfeSMilanka Ringwald memset(outputBuffer, 0, bytes_per_buffer); 201dbb41bfeSMilanka Ringwald } 202dbb41bfeSMilanka Ringwald // printf("bytes avail after read: %d\n", btstack_ring_buffer_bytes_available(&ring_buffer)); 203dbb41bfeSMilanka Ringwald return 0; 204dbb41bfeSMilanka Ringwald } 205dbb41bfeSMilanka Ringwald #endif 2068b29cfc6SMatthias Ringwald 207fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 208dbb41bfeSMilanka Ringwald // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); 209dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 210dbb41bfeSMilanka Ringwald if (!pa_stream_started && btstack_ring_buffer_bytes_available(&ring_buffer) >= MSBC_PREBUFFER_BYTES){ 211dbb41bfeSMilanka Ringwald /* -- start stream -- */ 212dbb41bfeSMilanka Ringwald PaError err = Pa_StartStream(stream); 213dbb41bfeSMilanka Ringwald if (err != paNoError){ 214dbb41bfeSMilanka Ringwald printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); 215dbb41bfeSMilanka Ringwald return; 216dbb41bfeSMilanka Ringwald } 217dbb41bfeSMilanka Ringwald pa_stream_started = 1; 218dbb41bfeSMilanka Ringwald } 219dbb41bfeSMilanka Ringwald btstack_ring_buffer_write(&ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 220dbb41bfeSMilanka Ringwald // printf("bytes avail after write: %d\n", btstack_ring_buffer_bytes_available(&ring_buffer)); 221dbb41bfeSMilanka Ringwald #endif 222dbb41bfeSMilanka Ringwald 223fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 224fcb08cdbSMilanka Ringwald 225fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 226fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 227fcb08cdbSMilanka Ringwald 228fbc7c9f2SMilanka Ringwald wav_writer_write_int16(num_samples, data); 229fcb08cdbSMilanka Ringwald 230fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 231fcb08cdbSMilanka Ringwald sco_demo_close(); 232fcb08cdbSMilanka Ringwald } 233fcb08cdbSMilanka Ringwald } 234fcb08cdbSMilanka Ringwald 235fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 236fbc7c9f2SMilanka Ringwald int sample_rate = 16000; 237fbc7c9f2SMilanka Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, sample_rate); 238fbc7c9f2SMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 239fcb08cdbSMilanka Ringwald 240fbc7c9f2SMilanka Ringwald num_samples_to_write = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 241220eb563SMilanka Ringwald 242220eb563SMilanka Ringwald hfp_msbc_init(); 243220eb563SMilanka Ringwald sco_demo_fill_audio_frame(); 244973d7173SMatthias Ringwald 245d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME 246d5e5f834SMatthias Ringwald msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 247d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 248d5e5f834SMatthias Ringwald #endif 2497294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 250d5e5f834SMatthias Ringwald msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 251d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 2527294d009SMatthias Ringwald #endif 253dbb41bfeSMilanka Ringwald 254dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 255dbb41bfeSMilanka Ringwald PaError err; 256dbb41bfeSMilanka Ringwald PaStreamParameters outputParameters; 257dbb41bfeSMilanka Ringwald 258dbb41bfeSMilanka Ringwald /* -- initialize PortAudio -- */ 259dbb41bfeSMilanka Ringwald err = Pa_Initialize(); 260dbb41bfeSMilanka Ringwald if( err != paNoError ) return; 261dbb41bfeSMilanka Ringwald /* -- setup input and output -- */ 262dbb41bfeSMilanka Ringwald outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 263dbb41bfeSMilanka Ringwald outputParameters.channelCount = NUM_CHANNELS; 264dbb41bfeSMilanka Ringwald outputParameters.sampleFormat = MSBC_PA_SAMPLE_TYPE; 265dbb41bfeSMilanka Ringwald outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 266dbb41bfeSMilanka Ringwald outputParameters.hostApiSpecificStreamInfo = NULL; 267dbb41bfeSMilanka Ringwald /* -- setup stream -- */ 268dbb41bfeSMilanka Ringwald err = Pa_OpenStream( 269dbb41bfeSMilanka Ringwald &stream, 270dbb41bfeSMilanka Ringwald NULL, // &inputParameters, 271dbb41bfeSMilanka Ringwald &outputParameters, 272dbb41bfeSMilanka Ringwald MSBC_SAMPLE_RATE, 273dbb41bfeSMilanka Ringwald MSBC_FRAMES_PER_BUFFER, 274dbb41bfeSMilanka Ringwald paClipOff, /* we won't output out of range samples so don't bother clipping them */ 275dbb41bfeSMilanka Ringwald patestCallback, /* no callback, use blocking API */ 276dbb41bfeSMilanka Ringwald NULL ); /* no callback, so no callback userData */ 277dbb41bfeSMilanka Ringwald if (err != paNoError){ 278dbb41bfeSMilanka Ringwald printf("Error initializing portaudio: \"%s\"\n", Pa_GetErrorText(err)); 279dbb41bfeSMilanka Ringwald return; 280dbb41bfeSMilanka Ringwald } 281dbb41bfeSMilanka Ringwald memset(ring_buffer_storage, 0, sizeof(ring_buffer_storage)); 282dbb41bfeSMilanka Ringwald btstack_ring_buffer_init(&ring_buffer, ring_buffer_storage, sizeof(ring_buffer_storage)); 283dbb41bfeSMilanka Ringwald pa_stream_started = 0; 284dbb41bfeSMilanka Ringwald #endif 285fcb08cdbSMilanka Ringwald } 286fcb08cdbSMilanka Ringwald 287fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 288fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 289d5e5f834SMatthias Ringwald if (msbc_file_in){ 290d5e5f834SMatthias Ringwald // log incoming mSBC data for testing 291d5e5f834SMatthias Ringwald fwrite(packet+3, size-3, 1, msbc_file_in); 292d5e5f834SMatthias Ringwald } 293fcb08cdbSMilanka Ringwald } 294dbb41bfeSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 295fcb08cdbSMilanka Ringwald } 296fcb08cdbSMilanka Ringwald 297fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){ 298fbc7c9f2SMilanka Ringwald int sample_rate = 8000; 299fbc7c9f2SMilanka Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, sample_rate); 300fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 301fbc7c9f2SMilanka Ringwald num_samples_to_write = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 302dbb41bfeSMilanka Ringwald 303dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 304dbb41bfeSMilanka Ringwald PaError err; 305dbb41bfeSMilanka Ringwald PaStreamParameters outputParameters; 306dbb41bfeSMilanka Ringwald 307dbb41bfeSMilanka Ringwald /* -- initialize PortAudio -- */ 308dbb41bfeSMilanka Ringwald err = Pa_Initialize(); 309dbb41bfeSMilanka Ringwald if( err != paNoError ) return; 310dbb41bfeSMilanka Ringwald /* -- setup input and output -- */ 311dbb41bfeSMilanka Ringwald outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 312dbb41bfeSMilanka Ringwald outputParameters.channelCount = NUM_CHANNELS; 313dbb41bfeSMilanka Ringwald outputParameters.sampleFormat = CVSD_PA_SAMPLE_TYPE; 314dbb41bfeSMilanka Ringwald outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 315dbb41bfeSMilanka Ringwald outputParameters.hostApiSpecificStreamInfo = NULL; 316dbb41bfeSMilanka Ringwald /* -- setup stream -- */ 317dbb41bfeSMilanka Ringwald err = Pa_OpenStream( 318dbb41bfeSMilanka Ringwald &stream, 319dbb41bfeSMilanka Ringwald NULL, // &inputParameters, 320dbb41bfeSMilanka Ringwald &outputParameters, 321dbb41bfeSMilanka Ringwald CVSD_SAMPLE_RATE, 322dbb41bfeSMilanka Ringwald CVSD_FRAMES_PER_BUFFER, 323dbb41bfeSMilanka Ringwald paClipOff, /* we won't output out of range samples so don't bother clipping them */ 324dbb41bfeSMilanka Ringwald patestCallback, /* no callback, use blocking API */ 325dbb41bfeSMilanka Ringwald NULL ); /* no callback, so no callback userData */ 326dbb41bfeSMilanka Ringwald if (err != paNoError){ 327dbb41bfeSMilanka Ringwald printf("Error initializing portaudio: \"%s\"\n", Pa_GetErrorText(err)); 328dbb41bfeSMilanka Ringwald return; 329dbb41bfeSMilanka Ringwald } 330dbb41bfeSMilanka Ringwald memset(ring_buffer_storage, 0, sizeof(ring_buffer_storage)); 331dbb41bfeSMilanka Ringwald btstack_ring_buffer_init(&ring_buffer, ring_buffer_storage, sizeof(ring_buffer_storage)); 332dbb41bfeSMilanka Ringwald pa_stream_started = 0; 333dbb41bfeSMilanka Ringwald #endif 334fbc7c9f2SMilanka Ringwald } 335fbc7c9f2SMilanka Ringwald 336fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 337dbb41bfeSMilanka Ringwald if (!num_samples_to_write) return; 338dbb41bfeSMilanka Ringwald 339fcb08cdbSMilanka Ringwald const int num_samples = size - 3; 340fcb08cdbSMilanka Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 34182e01da0SMilanka Ringwald int8_t audio_frame_out[24]; 342379d044eSMilanka Ringwald 343dbb41bfeSMilanka Ringwald 344fbc7c9f2SMilanka Ringwald // memcpy(audio_frame_out, (int8_t*)(packet+3), 24); 345fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, (int8_t *)(packet+3), num_samples, audio_frame_out); 346379d044eSMilanka Ringwald 347fbc7c9f2SMilanka Ringwald wav_writer_write_int8(samples_to_write, audio_frame_out); 348fcb08cdbSMilanka Ringwald num_samples_to_write -= samples_to_write; 349fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 350fcb08cdbSMilanka Ringwald sco_demo_close(); 351fcb08cdbSMilanka Ringwald } 352dbb41bfeSMilanka Ringwald #ifdef USE_PORTAUDIO 353dbb41bfeSMilanka Ringwald if (!pa_stream_started && btstack_ring_buffer_bytes_available(&ring_buffer) >= CVSD_PREBUFFER_BYTES){ 354dbb41bfeSMilanka Ringwald /* -- start stream -- */ 355dbb41bfeSMilanka Ringwald PaError err = Pa_StartStream(stream); 356dbb41bfeSMilanka Ringwald if (err != paNoError){ 357dbb41bfeSMilanka Ringwald printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); 358dbb41bfeSMilanka Ringwald return; 359fcb08cdbSMilanka Ringwald } 360dbb41bfeSMilanka Ringwald pa_stream_started = 1; 361dbb41bfeSMilanka Ringwald } 362dbb41bfeSMilanka Ringwald btstack_ring_buffer_write(&ring_buffer, (uint8_t *)audio_frame_out, samples_to_write); 363dbb41bfeSMilanka Ringwald #endif 364fcb08cdbSMilanka Ringwald } 365fcb08cdbSMilanka Ringwald 3668b29cfc6SMatthias Ringwald #endif 3674a96141eSMatthias Ringwald #endif 3688b29cfc6SMatthias Ringwald 369fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 370fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 37126463303SMilanka Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 372fbc7c9f2SMilanka Ringwald wav_writer_close(); 37326463303SMilanka Ringwald printf("SCO demo statistics: "); 37426463303SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 37526463303SMilanka 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); 37626463303SMilanka Ringwald } else { 37726463303SMilanka 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); 37826463303SMilanka Ringwald } 37926463303SMilanka Ringwald #endif 38026463303SMilanka Ringwald #endif 38126463303SMilanka Ringwald 382dbb41bfeSMilanka Ringwald #ifdef HAVE_PORTAUDIO 383dbb41bfeSMilanka Ringwald if (pa_stream_started){ 384dbb41bfeSMilanka Ringwald PaError err = Pa_StopStream(stream); 385dbb41bfeSMilanka Ringwald if (err != paNoError){ 386dbb41bfeSMilanka Ringwald printf("Error stopping the stream: \"%s\"\n", Pa_GetErrorText(err)); 387dbb41bfeSMilanka Ringwald return; 388dbb41bfeSMilanka Ringwald } 389dbb41bfeSMilanka Ringwald pa_stream_started = 0; 390dbb41bfeSMilanka Ringwald err = Pa_CloseStream(stream); 391dbb41bfeSMilanka Ringwald if (err != paNoError){ 392dbb41bfeSMilanka Ringwald printf("Error closing the stream: \"%s\"\n", Pa_GetErrorText(err)); 393dbb41bfeSMilanka Ringwald return; 394dbb41bfeSMilanka Ringwald } 395dbb41bfeSMilanka Ringwald 396dbb41bfeSMilanka Ringwald err = Pa_Terminate(); 397dbb41bfeSMilanka Ringwald if (err != paNoError){ 398dbb41bfeSMilanka Ringwald printf("Error terminating portaudio: \"%s\"\n", Pa_GetErrorText(err)); 399dbb41bfeSMilanka Ringwald return; 400dbb41bfeSMilanka Ringwald } 401dbb41bfeSMilanka Ringwald } 402dbb41bfeSMilanka Ringwald #endif 403dbb41bfeSMilanka Ringwald 40426463303SMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 405fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME 406fcb08cdbSMilanka Ringwald 407613518d1SMilanka Ringwald #if 0 408fcb08cdbSMilanka Ringwald printf("SCO Demo: closing wav file\n"); 409220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 4106e046a36SMatthias Ringwald wav_writer_state_t * writer_state = &wav_writer_state; 411fcb08cdbSMilanka Ringwald if (!writer_state->wav_file) return; 412fcb08cdbSMilanka Ringwald rewind(writer_state->wav_file); 4132afeea7fSMilanka 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); 414fcb08cdbSMilanka Ringwald fclose(writer_state->wav_file); 415fcb08cdbSMilanka Ringwald writer_state->wav_file = NULL; 416fcb08cdbSMilanka Ringwald } 417613518d1SMilanka Ringwald #endif 418fcb08cdbSMilanka Ringwald #endif 419fcb08cdbSMilanka Ringwald #endif 420fcb08cdbSMilanka Ringwald } 421fcb08cdbSMilanka Ringwald 422fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 423fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 424fcb08cdbSMilanka Ringwald negotiated_codec = codec; 425fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 42617cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 427220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 428fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 429fcb08cdbSMilanka Ringwald } else { 430fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 431fcb08cdbSMilanka Ringwald } 432fcb08cdbSMilanka Ringwald #endif 433fcb08cdbSMilanka Ringwald #endif 434fcb08cdbSMilanka Ringwald } 435fcb08cdbSMilanka Ringwald 436f7c85330SMatthias Ringwald void sco_demo_init(void){ 437f7c85330SMatthias Ringwald 438f7c85330SMatthias Ringwald // status 439f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 440f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 441f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 442f7c85330SMatthias Ringwald #else 443f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 444f7c85330SMatthias Ringwald #endif 445f7c85330SMatthias Ringwald #endif 446f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 447f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 448f7c85330SMatthias Ringwald #endif 449f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 450f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 451f7c85330SMatthias Ringwald #endif 452f7c85330SMatthias Ringwald 4537294d009SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE 454f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 4557294d009SMatthias Ringwald #endif 456f7c85330SMatthias Ringwald 457f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 458f7c85330SMatthias Ringwald phase = 'a'; 459f7c85330SMatthias Ringwald #endif 460f7c85330SMatthias Ringwald } 461f7c85330SMatthias Ringwald 4624a96141eSMatthias Ringwald static void sco_report(void){ 4634a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 4644a96141eSMatthias Ringwald } 465f7c85330SMatthias Ringwald 466f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 467f7c85330SMatthias Ringwald 468f7c85330SMatthias Ringwald if (!sco_handle) return; 469f7c85330SMatthias Ringwald 470f7c85330SMatthias Ringwald const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length(); 471f7c85330SMatthias Ringwald const int sco_payload_length = sco_packet_length - 3; 472f7c85330SMatthias Ringwald 473f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 474f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 475f7c85330SMatthias Ringwald // set handle + flags 476f7c85330SMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 477f7c85330SMatthias Ringwald // set len 478f7c85330SMatthias Ringwald sco_packet[2] = sco_payload_length; 479220eb563SMilanka Ringwald const int audio_samples_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2 480f7c85330SMatthias Ringwald 481f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 482220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 483220eb563SMilanka Ringwald 484220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 485220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 486220eb563SMilanka Ringwald } 487220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 488d5e5f834SMatthias Ringwald if (msbc_file_out){ 489d76591efSMatthias Ringwald // log outgoing mSBC data for testing 490d5e5f834SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 491d76591efSMatthias Ringwald } 4927294d009SMatthias Ringwald 493220eb563SMilanka Ringwald sco_demo_fill_audio_frame(); 494220eb563SMilanka Ringwald } else { 49535fd3fb9SMatthias Ringwald sco_demo_sine_wave_int8(audio_samples_per_packet, (int8_t *) (sco_packet+3)); 496220eb563SMilanka Ringwald } 497f7c85330SMatthias Ringwald #else 498f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 499220eb563SMilanka Ringwald memset(&sco_packet[3], phase++, audio_samples_per_packet); 500f7c85330SMatthias Ringwald if (phase > 'z') phase = 'a'; 501f7c85330SMatthias Ringwald #else 50238b2eaafSMatthias Ringwald int j; 503220eb563SMilanka Ringwald for (j=0;j<audio_samples_per_packet;j++){ 50438b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 505f7c85330SMatthias Ringwald } 506f7c85330SMatthias Ringwald #endif 507f7c85330SMatthias Ringwald #endif 508220eb563SMilanka Ringwald 509f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 510f7c85330SMatthias Ringwald 511f7c85330SMatthias Ringwald // request another send event 512f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 513f7c85330SMatthias Ringwald 5144a96141eSMatthias Ringwald count_sent++; 5154a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 516f7c85330SMatthias Ringwald } 517f7c85330SMatthias Ringwald 518f7c85330SMatthias Ringwald /** 519f7c85330SMatthias Ringwald * @brief Process received data 520f7c85330SMatthias Ringwald */ 521f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 522f7c85330SMatthias Ringwald 523fcb08cdbSMilanka Ringwald dump_data = 1; 5248b29cfc6SMatthias Ringwald 5254a96141eSMatthias Ringwald count_received++; 5264a96141eSMatthias Ringwald // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report(); 5274a96141eSMatthias Ringwald 5284a96141eSMatthias Ringwald 5294a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 5308b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME 531220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 532fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 533fcb08cdbSMilanka Ringwald } else { 534fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 5358b29cfc6SMatthias Ringwald } 536dbb41bfeSMilanka Ringwald dump_data = 0; 5378b29cfc6SMatthias Ringwald #endif 5384a96141eSMatthias Ringwald #endif 5398b29cfc6SMatthias Ringwald 540b3f76298SMilanka Ringwald if (packet[1] & 0x30){ 541b3f76298SMilanka Ringwald printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 542b3f76298SMilanka Ringwald log_info("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 543f7c85330SMatthias Ringwald printf_hexdump(&packet[3], size-3); 544b3f76298SMilanka Ringwald 545f7c85330SMatthias Ringwald return; 546f7c85330SMatthias Ringwald } 5478b29cfc6SMatthias Ringwald if (dump_data){ 548f7c85330SMatthias Ringwald printf("data: "); 549f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 550f7c85330SMatthias Ringwald int i; 551f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 552f7c85330SMatthias Ringwald printf("%c", packet[i]); 553f7c85330SMatthias Ringwald } 554f7c85330SMatthias Ringwald printf("\n"); 5558b29cfc6SMatthias Ringwald dump_data = 0; 5568b29cfc6SMatthias Ringwald #else 557f7c85330SMatthias Ringwald printf_hexdump(&packet[3], size-3); 558f7c85330SMatthias Ringwald #endif 5598b29cfc6SMatthias Ringwald } 560f7c85330SMatthias Ringwald } 561