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" 47*35fd3fb9SMatthias Ringwald #include "classic/btstack_sbc.h" 48*35fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h" 49*35fd3fb9SMatthias Ringwald #include "classic/hfp_msbc.h" 50*35fd3fb9SMatthias Ringwald #include "classic/hfp.h" 51fcb08cdbSMilanka Ringwald 52*35fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 53fbc7c9f2SMilanka Ringwald #include "wav_util.h" 54*35fd3fb9SMatthias 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" 69d5e5f834SMatthias Ringwald #define SCO_MSBC_IN_FILENAME "sco_input.mscb" 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 120*35fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, at 8000 kz 121*35fd3fb9SMatthias Ringwald static const uint8_t sine_uint8[] = { 122*35fd3fb9SMatthias Ringwald 0, 15, 31, 46, 61, 74, 86, 97, 107, 114, 123*35fd3fb9SMatthias Ringwald 120, 124, 126, 126, 124, 120, 114, 107, 97, 86, 124*35fd3fb9SMatthias Ringwald 74, 61, 46, 31, 15, 0, 241, 225, 210, 195, 125*35fd3fb9SMatthias Ringwald 182, 170, 159, 149, 142, 136, 132, 130, 130, 132, 126*35fd3fb9SMatthias Ringwald 136, 142, 149, 159, 170, 182, 195, 210, 225, 241, 127*35fd3fb9SMatthias Ringwald }; 128*35fd3fb9SMatthias Ringwald 129*35fd3fb9SMatthias Ringwald 130*35fd3fb9SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz 131*35fd3fb9SMatthias Ringwald static const int16_t sine_int16[] = { 132*35fd3fb9SMatthias Ringwald 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 133*35fd3fb9SMatthias Ringwald 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 134*35fd3fb9SMatthias Ringwald 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 135*35fd3fb9SMatthias Ringwald 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 136*35fd3fb9SMatthias Ringwald 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 137*35fd3fb9SMatthias Ringwald 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 138*35fd3fb9SMatthias Ringwald -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 139*35fd3fb9SMatthias Ringwald -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 140*35fd3fb9SMatthias Ringwald -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 141*35fd3fb9SMatthias Ringwald -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 142*35fd3fb9SMatthias Ringwald }; 143*35fd3fb9SMatthias Ringwald 144*35fd3fb9SMatthias Ringwald static int phase = 0; 145*35fd3fb9SMatthias Ringwald static void sco_demo_sine_wave_int8(int num_samples, int8_t * data){ 146*35fd3fb9SMatthias Ringwald int i; 147*35fd3fb9SMatthias Ringwald for (i=0; i<num_samples; i++){ 148*35fd3fb9SMatthias Ringwald data[i] = (int8_t)sine_uint8[phase]; 149*35fd3fb9SMatthias Ringwald phase++; 150*35fd3fb9SMatthias Ringwald if (phase >= sizeof(sine_uint8)) phase = 0; 151*35fd3fb9SMatthias Ringwald } 152*35fd3fb9SMatthias Ringwald } 153*35fd3fb9SMatthias Ringwald 154*35fd3fb9SMatthias Ringwald static void sco_demo_sine_wave_int16(int num_samples, int16_t * data){ 155*35fd3fb9SMatthias Ringwald int i; 156*35fd3fb9SMatthias Ringwald for (i=0; i < num_samples; i++){ 157*35fd3fb9SMatthias Ringwald data[i] = sine_int16[phase++]; 158*35fd3fb9SMatthias Ringwald if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){ 159*35fd3fb9SMatthias Ringwald phase = 0; 160*35fd3fb9SMatthias Ringwald } 161*35fd3fb9SMatthias Ringwald } 162*35fd3fb9SMatthias Ringwald } 163*35fd3fb9SMatthias Ringwald 164*35fd3fb9SMatthias Ringwald static void sco_demo_fill_audio_frame(void){ 165*35fd3fb9SMatthias Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 166*35fd3fb9SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 167*35fd3fb9SMatthias Ringwald int16_t sample_buffer[num_samples]; 168*35fd3fb9SMatthias Ringwald sco_demo_sine_wave_int16(num_samples, sample_buffer); 169*35fd3fb9SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 170*35fd3fb9SMatthias Ringwald num_audio_frames++; 171*35fd3fb9SMatthias 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 { 495*35fd3fb9SMatthias 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