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 */ 37ab2c6ae4SMatthias Ringwald 38ab2c6ae4SMatthias Ringwald #define __BTSTACK_FILE__ "sco_demo_util.c" 39f7c85330SMatthias Ringwald 40f7c85330SMatthias Ringwald /* 41f7c85330SMatthias Ringwald * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo 42f7c85330SMatthias Ringwald */ 43f7c85330SMatthias Ringwald 442ec72fbbSMilanka Ringwald #include <stdio.h> 452ec72fbbSMilanka Ringwald 46f7c85330SMatthias Ringwald #include "sco_demo_util.h" 47379c5f5fSMatthias Ringwald 48379c5f5fSMatthias Ringwald #include "btstack_audio.h" 49fcb08cdbSMilanka Ringwald #include "btstack_debug.h" 50379c5f5fSMatthias Ringwald #include "btstack_ring_buffer.h" 5135fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h" 52379c5f5fSMatthias Ringwald #include "classic/btstack_sbc.h" 5335fd3fb9SMatthias Ringwald #include "classic/hfp.h" 54379c5f5fSMatthias Ringwald #include "classic/hfp_msbc.h" 55fcb08cdbSMilanka Ringwald 5635fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 57fbc7c9f2SMilanka Ringwald #include "wav_util.h" 5835fd3fb9SMatthias Ringwald #endif 59fbc7c9f2SMilanka Ringwald 60c4e666bcSMatthias Ringwald // test modes 61f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE 0 62f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII 1 63f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER 2 641a919128SMatthias Ringwald #define SCO_DEMO_MODE_55 3 651a919128SMatthias Ringwald #define SCO_DEMO_MODE_00 4 66463c9c89SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 5 67f7c85330SMatthias Ringwald 68f7c85330SMatthias Ringwald // SCO demo configuration 69d365bb51SMatthias Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_MICROPHONE 70c4e666bcSMatthias Ringwald 71c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console 72f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 73f7c85330SMatthias Ringwald 74*f55ac442SMatthias Ringwald // #define ENABLE_SCO_STEREO_PLAYBACK 75*f55ac442SMatthias Ringwald 76d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 772c7ae6e1SMatthias Ringwald // length and name of wav file on disk 78c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15 798b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 80d4f907a6SMatthias Ringwald #endif 81c4e666bcSMatthias Ringwald 82c4e666bcSMatthias Ringwald // name of sbc test files 83d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 842308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME "sco_input.msbc" 85220eb563SMilanka Ringwald 86c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency 87c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS 50 88c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS 50 898b29cfc6SMatthias Ringwald 90c4e666bcSMatthias Ringwald // constants 91c4e666bcSMatthias Ringwald #define NUM_CHANNELS 1 92c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE 8000 93c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE 16000 94379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME 2 95f7c85330SMatthias Ringwald 96379c5f5fSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME) 97379c5f5fSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME) 98f7c85330SMatthias Ringwald 992b89dbfcSMatthias Ringwald // output 100379c5f5fSMatthias Ringwald 101d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 102d861f4bfSMatthias Ringwald static int audio_output_paused = 0; 103379c5f5fSMatthias Ringwald static uint8_t audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES]; 104379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer; 105d861f4bfSMatthias Ringwald #endif 106d861f4bfSMatthias Ringwald 1072b89dbfcSMatthias Ringwald 1082b89dbfcSMatthias Ringwald // input 1092b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 110379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT 111379c5f5fSMatthias Ringwald static int audio_input_paused = 0; 112379c5f5fSMatthias Ringwald static uint8_t audio_input_ring_buffer_storage[2*8000]; // full second input buffer 113379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer; 114f7c85330SMatthias Ringwald #endif 115f7c85330SMatthias Ringwald 116fcb08cdbSMilanka Ringwald static int dump_data = 1; 117fcb08cdbSMilanka Ringwald static int count_sent = 0; 118fcb08cdbSMilanka Ringwald static int count_received = 0; 119c4e666bcSMatthias Ringwald static int negotiated_codec = -1; 120c4e666bcSMatthias Ringwald 1211bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 122379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state; 1231bbecc2bSMatthias Ringwald #endif 1241bbecc2bSMatthias Ringwald 125379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state; 126379c5f5fSMatthias Ringwald 127379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8) 128fcb08cdbSMilanka Ringwald 1291bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 130d5e5f834SMatthias Ringwald FILE * msbc_file_in; 131d5e5f834SMatthias Ringwald FILE * msbc_file_out; 1321bbecc2bSMatthias Ringwald #endif 1337294d009SMatthias Ringwald 1342b89dbfcSMatthias Ringwald int num_samples_to_write; 1352b89dbfcSMatthias Ringwald int num_audio_frames; 136249d94cfSMatthias Ringwald unsigned int phase; 1372b89dbfcSMatthias Ringwald 138f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 139d6a06398SMatthias Ringwald 1407556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz 141c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 1427556ab9fSMatthias Ringwald 0, 3135, 6237, 9270, 12202, 14999, 17633, 20073, 22294, 24270, 1437556ab9fSMatthias Ringwald 25980, 27406, 28531, 29344, 29835, 30000, 29835, 29344, 28531, 27406, 1447556ab9fSMatthias Ringwald 25980, 24270, 22294, 20073, 17633, 14999, 12202, 9270, 6237, 3135, 1457556ab9fSMatthias Ringwald 0, -3135, -6237, -9270, -12202, -14999, -17633, -20073, -22294, -24270, 1467556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406, 1477556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202, -9270, -6237, -3135, 14835fd3fb9SMatthias Ringwald }; 14935fd3fb9SMatthias Ringwald 15059c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian 151adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){ 152249d94cfSMatthias Ringwald unsigned int i; 15359c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 15459c97ae1SMatthias Ringwald int16_t sample = sine_int16_at_16000hz[phase]; 155adaba9f3SMatthias Ringwald little_endian_store_16(data, i * 2, sample); 15659c97ae1SMatthias Ringwald // ony use every second sample from 16khz table to get 8khz 15759c97ae1SMatthias Ringwald phase += 2; 158c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 15935fd3fb9SMatthias Ringwald phase = 0; 16035fd3fb9SMatthias Ringwald } 16135fd3fb9SMatthias Ringwald } 16235fd3fb9SMatthias Ringwald } 16335fd3fb9SMatthias Ringwald 1641bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess 1651bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 166249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){ 167249d94cfSMatthias Ringwald unsigned int i; 1681bbecc2bSMatthias Ringwald for (i=0; i < num_samples; i++){ 1691bbecc2bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase++]; 1701bbecc2bSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 1711bbecc2bSMatthias Ringwald phase = 0; 1721bbecc2bSMatthias Ringwald } 1731bbecc2bSMatthias Ringwald } 1741bbecc2bSMatthias Ringwald } 1751bbecc2bSMatthias Ringwald 176b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){ 17735fd3fb9SMatthias Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 17835fd3fb9SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 179379c5f5fSMatthias Ringwald if (num_samples > MAX_NUM_MSBC_SAMPLES) return; 180379c5f5fSMatthias Ringwald int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES]; 18159c97ae1SMatthias Ringwald sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer); 18235fd3fb9SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 18335fd3fb9SMatthias Ringwald num_audio_frames++; 18435fd3fb9SMatthias Ringwald } 1852b89dbfcSMatthias Ringwald #endif 1861bbecc2bSMatthias Ringwald #endif 187dbb41bfeSMilanka Ringwald 188d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 189d861f4bfSMatthias Ringwald 190379c5f5fSMatthias Ringwald static void playback_callback(int16_t * buffer, uint16_t num_samples){ 1912b89dbfcSMatthias Ringwald 192be030f50SMilanka Ringwald uint32_t prebuffer_bytes; 193c4e666bcSMatthias Ringwald switch (negotiated_codec){ 194c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 195c4e666bcSMatthias Ringwald prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES; 196c4e666bcSMatthias Ringwald break; 197c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 198c4e666bcSMatthias Ringwald default: 199379c5f5fSMatthias Ringwald prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES; 200c4e666bcSMatthias Ringwald break; 201dbb41bfeSMilanka Ringwald } 202dbb41bfeSMilanka Ringwald 203c4e666bcSMatthias Ringwald // fill with silence while paused 204379c5f5fSMatthias Ringwald if (audio_output_paused){ 205379c5f5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){ 206*f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK 207*f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME * 2); 208*f55ac442SMatthias Ringwald #else 209*f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 210*f55ac442SMatthias Ringwald #endif 211379c5f5fSMatthias Ringwald return; 212dbb41bfeSMilanka Ringwald } else { 213c4e666bcSMatthias Ringwald // resume playback 214379c5f5fSMatthias Ringwald audio_output_paused = 0; 215dbb41bfeSMilanka Ringwald } 216c4e666bcSMatthias Ringwald } 217c4e666bcSMatthias Ringwald 218c4e666bcSMatthias Ringwald // get data from ringbuffer 219c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 220*f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK 221*f55ac442SMatthias Ringwald while (num_samples){ 222*f55ac442SMatthias Ringwald int16_t temp[16]; 223*f55ac442SMatthias Ringwald unsigned int bytes_to_read = btstack_min(num_samples * BYTES_PER_FRAME, sizeof(temp)); 224*f55ac442SMatthias Ringwald btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) &temp[0], bytes_to_read, &bytes_read); 225*f55ac442SMatthias Ringwald if (bytes_read == 0) break; 226*f55ac442SMatthias Ringwald unsigned int i; 227*f55ac442SMatthias Ringwald for (i=0;i<bytes_read / BYTES_PER_FRAME;i++){ 228*f55ac442SMatthias Ringwald *buffer++ = temp[i]; 229*f55ac442SMatthias Ringwald *buffer++ = temp[i]; 230*f55ac442SMatthias Ringwald num_samples--; 231*f55ac442SMatthias Ringwald } 232*f55ac442SMatthias Ringwald } 233*f55ac442SMatthias Ringwald #else 234*f55ac442SMatthias Ringwald btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 235*f55ac442SMatthias Ringwald num_samples -= bytes_read / BYTES_PER_FRAME; 236*f55ac442SMatthias Ringwald buffer += bytes_read / BYTES_PER_FRAME; 237*f55ac442SMatthias Ringwald #endif 238c4e666bcSMatthias Ringwald 239c4e666bcSMatthias Ringwald // fill with 0 if not enough 240*f55ac442SMatthias Ringwald if (num_samples){ 241*f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK 242*f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME * 2); 243*f55ac442SMatthias Ringwald #else 244*f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 245*f55ac442SMatthias Ringwald #endif 246379c5f5fSMatthias Ringwald audio_output_paused = 1; 247c4e666bcSMatthias Ringwald } 248379c5f5fSMatthias Ringwald } 2498b29cfc6SMatthias Ringwald 250379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 251379c5f5fSMatthias Ringwald static void recording_callback(const int16_t * buffer, uint16_t num_samples){ 252379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2); 253c4e666bcSMatthias Ringwald } 254379c5f5fSMatthias Ringwald #endif 255c4e666bcSMatthias Ringwald 256c4e666bcSMatthias Ringwald // return 1 if ok 257379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){ 258c4e666bcSMatthias Ringwald 259d365bb51SMatthias Ringwald // -- output -- // 260d365bb51SMatthias Ringwald 261379c5f5fSMatthias Ringwald // init buffers 262379c5f5fSMatthias Ringwald memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage)); 263379c5f5fSMatthias Ringwald btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage)); 2642b89dbfcSMatthias Ringwald 265d365bb51SMatthias Ringwald // config and setup audio playback 266d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 267d365bb51SMatthias Ringwald if (!audio_sink) return 0; 2682b89dbfcSMatthias Ringwald 269*f55ac442SMatthias Ringwald #ifdef ENABLE_SCO_STEREO_PLAYBACK 270*f55ac442SMatthias Ringwald audio_sink->init(2, sample_rate, &playback_callback); 271*f55ac442SMatthias Ringwald #else 272d365bb51SMatthias Ringwald audio_sink->init(1, sample_rate, &playback_callback); 273*f55ac442SMatthias Ringwald #endif 274d365bb51SMatthias Ringwald audio_sink->start_stream(); 275379c5f5fSMatthias Ringwald 276379c5f5fSMatthias Ringwald audio_output_paused = 1; 277d365bb51SMatthias Ringwald 278d365bb51SMatthias Ringwald // -- input -- // 279d365bb51SMatthias Ringwald 280379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 281d365bb51SMatthias Ringwald // init buffers 282d365bb51SMatthias Ringwald memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage)); 283d365bb51SMatthias Ringwald btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage)); 284d365bb51SMatthias Ringwald 285d365bb51SMatthias Ringwald // config and setup audio recording 286d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance(); 287d365bb51SMatthias Ringwald if (!audio_source) return 0; 288d365bb51SMatthias Ringwald 289d365bb51SMatthias Ringwald audio_source->init(1, sample_rate, &recording_callback); 290d365bb51SMatthias Ringwald audio_source->start_stream(); 291d365bb51SMatthias Ringwald 292379c5f5fSMatthias Ringwald audio_input_paused = 1; 2932b89dbfcSMatthias Ringwald #endif 2942b89dbfcSMatthias Ringwald 295c4e666bcSMatthias Ringwald return 1; 296c4e666bcSMatthias Ringwald } 2972b89dbfcSMatthias Ringwald 298379c5f5fSMatthias Ringwald static void audio_terminate(void){ 299d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 300d365bb51SMatthias Ringwald if (!audio_sink) return; 301d365bb51SMatthias Ringwald audio_sink->close(); 302d365bb51SMatthias Ringwald 303d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT 304d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance(); 305d365bb51SMatthias Ringwald if (!audio_source) return; 306d365bb51SMatthias Ringwald audio_source->close(); 307d365bb51SMatthias Ringwald #endif 3082b89dbfcSMatthias Ringwald } 309c4e666bcSMatthias Ringwald 3101bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 311d861f4bfSMatthias Ringwald 312c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 313c4e666bcSMatthias Ringwald UNUSED(context); 314c4e666bcSMatthias Ringwald UNUSED(sample_rate); 3152c7ae6e1SMatthias Ringwald UNUSED(data); 3162c7ae6e1SMatthias Ringwald UNUSED(num_samples); 3172c7ae6e1SMatthias Ringwald UNUSED(num_channels); 3182c7ae6e1SMatthias Ringwald 3192c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 320c4e666bcSMatthias Ringwald 321c4e666bcSMatthias Ringwald // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); 322379c5f5fSMatthias Ringwald 323379c5f5fSMatthias Ringwald // samples in callback in host endianess, ready for playback 324379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 325dbb41bfeSMilanka Ringwald 3262c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 327fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 328fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 329fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 330fbc7c9f2SMilanka Ringwald wav_writer_write_int16(num_samples, data); 331fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 3322c7ae6e1SMatthias Ringwald wav_writer_close(); 333fcb08cdbSMilanka Ringwald } 3341bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 3352c7ae6e1SMatthias Ringwald 3361bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */ 337fcb08cdbSMilanka Ringwald } 3381bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 3391bbecc2bSMatthias Ringwald 3401bbecc2bSMatthias Ringwald 3411bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 342fcb08cdbSMilanka Ringwald 343fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 344c4e666bcSMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 345c4e666bcSMatthias Ringwald 346fbc7c9f2SMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 347220eb563SMilanka Ringwald hfp_msbc_init(); 3482c7ae6e1SMatthias Ringwald 3492c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3502c7ae6e1SMatthias Ringwald num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 3512c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE); 3522c7ae6e1SMatthias Ringwald #endif 3532c7ae6e1SMatthias Ringwald 3542b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 355b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 3562b89dbfcSMatthias Ringwald #endif 357973d7173SMatthias Ringwald 358d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME 359d5e5f834SMatthias Ringwald msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 360d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 361d5e5f834SMatthias Ringwald #endif 3622b89dbfcSMatthias Ringwald 3637294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 364d5e5f834SMatthias Ringwald msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 365d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 3667294d009SMatthias Ringwald #endif 367dbb41bfeSMilanka Ringwald 368379c5f5fSMatthias Ringwald audio_initialize(MSBC_SAMPLE_RATE); 369fcb08cdbSMilanka Ringwald } 370fcb08cdbSMilanka Ringwald 371fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 372fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 373d5e5f834SMatthias Ringwald if (msbc_file_in){ 374d5e5f834SMatthias Ringwald // log incoming mSBC data for testing 375d5e5f834SMatthias Ringwald fwrite(packet+3, size-3, 1, msbc_file_in); 376d5e5f834SMatthias Ringwald } 377fcb08cdbSMilanka Ringwald } 378dbb41bfeSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 379fcb08cdbSMilanka Ringwald } 3801bbecc2bSMatthias Ringwald #endif 381fcb08cdbSMilanka Ringwald 382fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){ 383c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 384c4e666bcSMatthias Ringwald 385fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 386c4e666bcSMatthias Ringwald 3872c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 388c4e666bcSMatthias Ringwald num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 3892c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE); 3902c7ae6e1SMatthias Ringwald #endif 391dbb41bfeSMilanka Ringwald 392379c5f5fSMatthias Ringwald audio_initialize(CVSD_SAMPLE_RATE); 393fbc7c9f2SMilanka Ringwald } 394fbc7c9f2SMilanka Ringwald 395fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 396dbb41bfeSMilanka Ringwald if (!num_samples_to_write) return; 3972c7ae6e1SMatthias Ringwald 3985303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 3991f8694ccSMatthias Ringwald 4001f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 4011f8694ccSMatthias Ringwald printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); 4021f8694ccSMatthias Ringwald return; 4031f8694ccSMatthias Ringwald } 4042c7ae6e1SMatthias Ringwald 405c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 406379c5f5fSMatthias Ringwald const int num_samples = audio_bytes_read / BYTES_PER_FRAME; 4075303ddeeSMatthias Ringwald 4085303ddeeSMatthias Ringwald // convert into host endian 4095303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 4105303ddeeSMatthias Ringwald int i; 4115303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 4125303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 4135303ddeeSMatthias Ringwald } 4145303ddeeSMatthias Ringwald 415e36764ddSMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out); 4165303ddeeSMatthias Ringwald 4172c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 4182c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 4192c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 4202c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 4212c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 4222c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 4232c7ae6e1SMatthias Ringwald wav_writer_close(); 4242c7ae6e1SMatthias Ringwald } 4252c7ae6e1SMatthias Ringwald #endif 4262c7ae6e1SMatthias Ringwald 427379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 428fcb08cdbSMilanka Ringwald } 429fcb08cdbSMilanka Ringwald 4302c7ae6e1SMatthias Ringwald #endif 4312c7ae6e1SMatthias Ringwald 4322c7ae6e1SMatthias Ringwald 433fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 434c4e666bcSMatthias Ringwald printf("SCO demo close\n"); 4352b89dbfcSMatthias Ringwald 43626463303SMilanka Ringwald printf("SCO demo statistics: "); 4371bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 43826463303SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 4392c7ae6e1SMatthias Ringwald printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.\n", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr); 4401bbecc2bSMatthias Ringwald } else 4411bbecc2bSMatthias Ringwald #endif 4421bbecc2bSMatthias Ringwald { 4432c7ae6e1SMatthias Ringwald printf("Used CVSD with PLC, number of proccesed frames: \n - %d good frames, \n - %d bad frames.\n", cvsd_plc_state.good_frames_nr, cvsd_plc_state.bad_frames_nr); 44426463303SMilanka Ringwald } 44526463303SMilanka Ringwald 4462c7ae6e1SMatthias Ringwald negotiated_codec = -1; 4472c7ae6e1SMatthias Ringwald 4482c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 4492c7ae6e1SMatthias Ringwald 4502c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 4512c7ae6e1SMatthias Ringwald wav_writer_close(); 4522c7ae6e1SMatthias Ringwald #endif 4532c7ae6e1SMatthias Ringwald 454379c5f5fSMatthias Ringwald audio_terminate(); 455fcb08cdbSMilanka Ringwald 456fcb08cdbSMilanka Ringwald #endif 457fcb08cdbSMilanka Ringwald } 458fcb08cdbSMilanka Ringwald 459fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 460fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 461fcb08cdbSMilanka Ringwald negotiated_codec = codec; 4622c7ae6e1SMatthias Ringwald 4632b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 464220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 4651bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 466fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 4671bbecc2bSMatthias Ringwald #endif 468fcb08cdbSMilanka Ringwald } else { 469fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 470fcb08cdbSMilanka Ringwald } 471fcb08cdbSMilanka Ringwald #endif 472fcb08cdbSMilanka Ringwald } 473fcb08cdbSMilanka Ringwald 474f7c85330SMatthias Ringwald void sco_demo_init(void){ 475f7c85330SMatthias Ringwald // status 4762b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 477379c5f5fSMatthias Ringwald printf("SCO Demo: Sending and receiving audio via btstack_audio.\n"); 4782b89dbfcSMatthias Ringwald #endif 479f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 480f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 481379c5f5fSMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n"); 482f7c85330SMatthias Ringwald #else 483f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 484f7c85330SMatthias Ringwald #endif 485f7c85330SMatthias Ringwald #endif 486f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 487f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 488f7c85330SMatthias Ringwald #endif 489f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 490f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 491f7c85330SMatthias Ringwald #endif 492f7c85330SMatthias Ringwald 4932b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 494c4e666bcSMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 495c4e666bcSMatthias Ringwald #else 496f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 4977294d009SMatthias Ringwald #endif 498f7c85330SMatthias Ringwald } 499f7c85330SMatthias Ringwald 5001a919128SMatthias Ringwald void sco_report(void); 5011a919128SMatthias Ringwald void sco_report(void){ 5024a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 5034a96141eSMatthias Ringwald } 504f7c85330SMatthias Ringwald 505f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 506f7c85330SMatthias Ringwald 507e1de95beSMatthias Ringwald if (sco_handle == HCI_CON_HANDLE_INVALID) return; 508f7c85330SMatthias Ringwald 509c4e666bcSMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 510c4e666bcSMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 511f7c85330SMatthias Ringwald 512f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 513f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 514f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 5151bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 516220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 51701b2daf8SMatthias Ringwald 518220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 519220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 520220eb563SMilanka Ringwald } 521220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 522d5e5f834SMatthias Ringwald if (msbc_file_out){ 523d76591efSMatthias Ringwald // log outgoing mSBC data for testing 524d5e5f834SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 525d76591efSMatthias Ringwald } 5267294d009SMatthias Ringwald 527b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 5281bbecc2bSMatthias Ringwald } else 5291bbecc2bSMatthias Ringwald #endif 5301bbecc2bSMatthias Ringwald { 531379c5f5fSMatthias Ringwald const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME; 532adaba9f3SMatthias Ringwald sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]); 533220eb563SMilanka Ringwald } 5341a919128SMatthias Ringwald #endif 5352b89dbfcSMatthias Ringwald 5362b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 5372b89dbfcSMatthias Ringwald 5382b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 5392b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 5402b89dbfcSMatthias Ringwald // MSBC 5412b89dbfcSMatthias Ringwald 542379c5f5fSMatthias Ringwald if (audio_input_paused){ 543379c5f5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ 544b025eb5fSMatthias Ringwald // resume sending 545379c5f5fSMatthias Ringwald audio_input_paused = 0; 5462b89dbfcSMatthias Ringwald } 547b025eb5fSMatthias Ringwald } 548b025eb5fSMatthias Ringwald 549379c5f5fSMatthias Ringwald if (!audio_input_paused){ 550b025eb5fSMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 551379c5f5fSMatthias Ringwald if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert 552379c5f5fSMatthias Ringwald if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= (unsigned int)(num_samples * BYTES_PER_FRAME)){ 553379c5f5fSMatthias Ringwald int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES]; 554b025eb5fSMatthias Ringwald uint32_t bytes_read; 555379c5f5fSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 556b025eb5fSMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 557b025eb5fSMatthias Ringwald num_audio_frames++; 558b025eb5fSMatthias Ringwald } 559b025eb5fSMatthias Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 560b025eb5fSMatthias Ringwald log_error("mSBC stream should not be empty."); 561379c5f5fSMatthias Ringwald } 562379c5f5fSMatthias Ringwald } 563379c5f5fSMatthias Ringwald 564379c5f5fSMatthias Ringwald if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 565b025eb5fSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 566379c5f5fSMatthias Ringwald audio_input_paused = 1; 567b025eb5fSMatthias Ringwald } else { 5682b89dbfcSMatthias Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 5692b89dbfcSMatthias Ringwald if (msbc_file_out){ 5702b89dbfcSMatthias Ringwald // log outgoing mSBC data for testing 5712b89dbfcSMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 5722b89dbfcSMatthias Ringwald } 573b025eb5fSMatthias Ringwald } 5742b89dbfcSMatthias Ringwald 5752b89dbfcSMatthias Ringwald } else { 5762b89dbfcSMatthias Ringwald // CVSD 5772b89dbfcSMatthias Ringwald 578379c5f5fSMatthias Ringwald log_info("send: bytes avail %u, free %u", btstack_ring_buffer_bytes_available(&audio_input_ring_buffer), btstack_ring_buffer_bytes_free(&audio_input_ring_buffer)); 5792b89dbfcSMatthias Ringwald // fill with silence while paused 5802b89dbfcSMatthias Ringwald int bytes_to_copy = sco_payload_length; 581379c5f5fSMatthias Ringwald if (audio_input_paused){ 582379c5f5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ 5832b89dbfcSMatthias Ringwald // resume sending 584379c5f5fSMatthias Ringwald audio_input_paused = 0; 5852b89dbfcSMatthias Ringwald } 5862b89dbfcSMatthias Ringwald } 5872b89dbfcSMatthias Ringwald 5882b89dbfcSMatthias Ringwald // get data from ringbuffer 5892b89dbfcSMatthias Ringwald uint16_t pos = 0; 5908fd6902dSMatthias Ringwald uint8_t * sample_data = &sco_packet[3]; 591379c5f5fSMatthias Ringwald if (!audio_input_paused){ 5922b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 593379c5f5fSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read); 5948fd6902dSMatthias Ringwald // flip 16 on big endian systems 5958fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 5968fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 5978d3be402SMatthias Ringwald unsigned int i; 5988fd6902dSMatthias Ringwald for (i=0;i<bytes_read;i+=2){ 5998fd6902dSMatthias Ringwald uint8_t tmp = sample_data[i*2]; 6008fd6902dSMatthias Ringwald sample_data[i*2] = sample_data[i*2+1]; 6018fd6902dSMatthias Ringwald sample_data[i*2+1] = tmp; 6028fd6902dSMatthias Ringwald } 6038fd6902dSMatthias Ringwald } 6042b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 6052b89dbfcSMatthias Ringwald pos += bytes_read; 6062b89dbfcSMatthias Ringwald } 6072b89dbfcSMatthias Ringwald 6082b89dbfcSMatthias Ringwald // fill with 0 if not enough 6092b89dbfcSMatthias Ringwald if (bytes_to_copy){ 6108fd6902dSMatthias Ringwald memset(sample_data + pos, 0, bytes_to_copy); 611379c5f5fSMatthias Ringwald audio_input_paused = 1; 6122b89dbfcSMatthias Ringwald } 6132b89dbfcSMatthias Ringwald } 6142b89dbfcSMatthias Ringwald #else 6152b89dbfcSMatthias Ringwald // just send '0's 6162b89dbfcSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 6172b89dbfcSMatthias Ringwald #endif 6182b89dbfcSMatthias Ringwald #endif 6192b89dbfcSMatthias Ringwald 620f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 62101b2daf8SMatthias Ringwald // store packet counter-xxxx 62201b2daf8SMatthias Ringwald snprintf((char *)&sco_packet[3], 5, "%04u", phase++); 62301b2daf8SMatthias Ringwald uint8_t ascii = (phase & 0x0f) + 'a'; 62401b2daf8SMatthias Ringwald sco_packet[3+4] = '-'; 62501b2daf8SMatthias Ringwald memset(&sco_packet[3+5], ascii, sco_payload_length-5); 6261a919128SMatthias Ringwald #endif 6271a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 62838b2eaafSMatthias Ringwald int j; 629c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 63038b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 631f7c85330SMatthias Ringwald } 632f7c85330SMatthias Ringwald #endif 6331a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 6341a919128SMatthias Ringwald int j; 635c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6361a919128SMatthias Ringwald // sco_packet[3+j] = j & 1 ? 0x35 : 0x53; 6371a919128SMatthias Ringwald sco_packet[3+j] = 0x55; 6381a919128SMatthias Ringwald } 6391a919128SMatthias Ringwald #endif 6401a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00 6411a919128SMatthias Ringwald int j; 642c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6431a919128SMatthias Ringwald sco_packet[3+j] = 0x00; 6441a919128SMatthias Ringwald } 6451a919128SMatthias Ringwald // additional hack 6461a919128SMatthias Ringwald // big_endian_store_16(sco_packet, 5, phase++); 6471a919128SMatthias Ringwald (void) phase; 648f7c85330SMatthias Ringwald #endif 649220eb563SMilanka Ringwald 6502b89dbfcSMatthias Ringwald // test silence 6512b89dbfcSMatthias Ringwald // memset(sco_packet+3, 0, sco_payload_length); 6522b89dbfcSMatthias Ringwald 653c4e666bcSMatthias Ringwald // set handle + flags 654c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 655c4e666bcSMatthias Ringwald // set len 656c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 657c4e666bcSMatthias Ringwald // finally send packet 658f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 659f7c85330SMatthias Ringwald 660f7c85330SMatthias Ringwald // request another send event 661f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 662f7c85330SMatthias Ringwald 6634a96141eSMatthias Ringwald count_sent++; 6641a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55 6654a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 6661a919128SMatthias Ringwald #endif 667f7c85330SMatthias Ringwald } 668f7c85330SMatthias Ringwald 669f7c85330SMatthias Ringwald /** 670f7c85330SMatthias Ringwald * @brief Process received data 671f7c85330SMatthias Ringwald */ 6721a919128SMatthias Ringwald #define ANSI_COLOR_RED "\x1b[31m" 6731a919128SMatthias Ringwald #define ANSI_COLOR_GREEN "\x1b[32m" 6741a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW "\x1b[33m" 6751a919128SMatthias Ringwald #define ANSI_COLOR_BLUE "\x1b[34m" 6761a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m" 6771a919128SMatthias Ringwald #define ANSI_COLOR_CYAN "\x1b[36m" 6781a919128SMatthias Ringwald #define ANSI_COLOR_RESET "\x1b[0m" 6791a919128SMatthias Ringwald 680f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 681f7c85330SMatthias Ringwald 682fcb08cdbSMilanka Ringwald dump_data = 1; 6838b29cfc6SMatthias Ringwald 6844a96141eSMatthias Ringwald count_received++; 6851a919128SMatthias Ringwald static uint32_t packets = 0; 6861a919128SMatthias Ringwald static uint32_t crc_errors = 0; 6871a919128SMatthias Ringwald static uint32_t data_received = 0; 6881a919128SMatthias Ringwald static uint32_t byte_errors = 0; 6894a96141eSMatthias Ringwald 6901a919128SMatthias Ringwald data_received += size - 3; 6911a919128SMatthias Ringwald packets++; 6921a919128SMatthias Ringwald if (data_received > 100000){ 693d4f907a6SMatthias Ringwald printf("Summary: data %07u, packets %04u, packet with crc errors %0u, byte errors %04u\n", (unsigned int) data_received, (unsigned int) packets, (unsigned int) crc_errors, (unsigned int) byte_errors); 6941a919128SMatthias Ringwald crc_errors = 0; 6951a919128SMatthias Ringwald byte_errors = 0; 6961a919128SMatthias Ringwald data_received = 0; 6971a919128SMatthias Ringwald packets = 0; 6981a919128SMatthias Ringwald } 6994a96141eSMatthias Ringwald 7002b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 701c4e666bcSMatthias Ringwald switch (negotiated_codec){ 7021bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 703c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 704fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 705c4e666bcSMatthias Ringwald break; 7061bbecc2bSMatthias Ringwald #endif 707c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 708fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 709c4e666bcSMatthias Ringwald break; 710c4e666bcSMatthias Ringwald default: 711c4e666bcSMatthias Ringwald break; 7128b29cfc6SMatthias Ringwald } 713dbb41bfeSMilanka Ringwald dump_data = 0; 7148b29cfc6SMatthias Ringwald #endif 7158b29cfc6SMatthias Ringwald 71601b2daf8SMatthias Ringwald #if 0 717b3f76298SMilanka Ringwald if (packet[1] & 0x30){ 7181a919128SMatthias Ringwald crc_errors++; 71901b2daf8SMatthias Ringwald printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 72001b2daf8SMatthias Ringwald printf_hexdump(&packet[3], size-3); 721f7c85330SMatthias Ringwald return; 722f7c85330SMatthias Ringwald } 72301b2daf8SMatthias Ringwald #endif 72401b2daf8SMatthias Ringwald 7258b29cfc6SMatthias Ringwald if (dump_data){ 726f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 7271a919128SMatthias Ringwald printf("data: "); 728f7c85330SMatthias Ringwald int i; 729f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 730f7c85330SMatthias Ringwald printf("%c", packet[i]); 731f7c85330SMatthias Ringwald } 732f7c85330SMatthias Ringwald printf("\n"); 7338b29cfc6SMatthias Ringwald dump_data = 0; 7341a919128SMatthias Ringwald #endif 7351a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 7361a919128SMatthias Ringwald // colored hexdump with expected 7371a919128SMatthias Ringwald static uint8_t expected_byte = 0; 7381a919128SMatthias Ringwald int i; 7391a919128SMatthias Ringwald printf("data: "); 7401a919128SMatthias Ringwald for (i=3;i<size;i++){ 7411a919128SMatthias Ringwald if (packet[i] != expected_byte){ 7421a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7431a919128SMatthias Ringwald } else { 7441a919128SMatthias Ringwald printf("%02x ", packet[i]); 7451a919128SMatthias Ringwald } 7461a919128SMatthias Ringwald expected_byte = packet[i]+1; 7471a919128SMatthias Ringwald } 7481a919128SMatthias Ringwald printf("\n"); 7491a919128SMatthias Ringwald #endif 750a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00 7511a919128SMatthias Ringwald int i; 7521a919128SMatthias Ringwald int contains_error = 0; 7531a919128SMatthias Ringwald for (i=3;i<size;i++){ 7541a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 7551a919128SMatthias Ringwald contains_error = 1; 7561a919128SMatthias Ringwald byte_errors++; 7571a919128SMatthias Ringwald } 7581a919128SMatthias Ringwald } 7591a919128SMatthias Ringwald if (contains_error){ 7601a919128SMatthias Ringwald printf("data: "); 7611a919128SMatthias Ringwald for (i=0;i<3;i++){ 7621a919128SMatthias Ringwald printf("%02x ", packet[i]); 7631a919128SMatthias Ringwald } 7641a919128SMatthias Ringwald for (i=3;i<size;i++){ 7651a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 7661a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7671a919128SMatthias Ringwald } else { 7681a919128SMatthias Ringwald printf("%02x ", packet[i]); 7691a919128SMatthias Ringwald } 7701a919128SMatthias Ringwald } 7711a919128SMatthias Ringwald printf("\n"); 7721a919128SMatthias Ringwald } 773f7c85330SMatthias Ringwald #endif 7748b29cfc6SMatthias Ringwald } 775f7c85330SMatthias Ringwald } 776