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 69fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE 70c4e666bcSMatthias Ringwald 71c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console 72f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 73f7c85330SMatthias Ringwald 74d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 752c7ae6e1SMatthias Ringwald // length and name of wav file on disk 76c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15 778b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 78d4f907a6SMatthias Ringwald #endif 79c4e666bcSMatthias Ringwald 80c4e666bcSMatthias Ringwald // name of sbc test files 81d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 822308e108SMilanka Ringwald #define SCO_MSBC_IN_FILENAME "sco_input.msbc" 83220eb563SMilanka Ringwald 84c4e666bcSMatthias Ringwald // pre-buffer for CVSD and mSBC - also defines latency 85c4e666bcSMatthias Ringwald #define SCO_CVSD_PA_PREBUFFER_MS 50 86c4e666bcSMatthias Ringwald #define SCO_MSBC_PA_PREBUFFER_MS 50 878b29cfc6SMatthias Ringwald 88c4e666bcSMatthias Ringwald // constants 89c4e666bcSMatthias Ringwald #define NUM_CHANNELS 1 90c4e666bcSMatthias Ringwald #define CVSD_SAMPLE_RATE 8000 91c4e666bcSMatthias Ringwald #define MSBC_SAMPLE_RATE 16000 92379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME 2 93f7c85330SMatthias Ringwald 94379c5f5fSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE || SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 95379c5f5fSMatthias Ringwald #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME) 96379c5f5fSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME) 97f7c85330SMatthias Ringwald #endif 98f7c85330SMatthias Ringwald 992b89dbfcSMatthias Ringwald // output 100379c5f5fSMatthias Ringwald static int audio_output_paused = 0; 101379c5f5fSMatthias Ringwald 102379c5f5fSMatthias Ringwald static uint8_t audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES]; 103379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer; 1042b89dbfcSMatthias Ringwald 1052b89dbfcSMatthias Ringwald // input 1062b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 107379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT 108379c5f5fSMatthias Ringwald static int audio_input_paused = 0; 109379c5f5fSMatthias Ringwald static uint8_t audio_input_ring_buffer_storage[2*8000]; // full second input buffer 110379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer; 111f7c85330SMatthias Ringwald #endif 112f7c85330SMatthias Ringwald 113fcb08cdbSMilanka Ringwald static int dump_data = 1; 114fcb08cdbSMilanka Ringwald static int count_sent = 0; 115fcb08cdbSMilanka Ringwald static int count_received = 0; 116c4e666bcSMatthias Ringwald static int negotiated_codec = -1; 117c4e666bcSMatthias Ringwald 1181bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 119379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state; 1201bbecc2bSMatthias Ringwald #endif 1211bbecc2bSMatthias Ringwald 122379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state; 123379c5f5fSMatthias Ringwald 124379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8) 125fcb08cdbSMilanka Ringwald 1261bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 127d5e5f834SMatthias Ringwald FILE * msbc_file_in; 128d5e5f834SMatthias Ringwald FILE * msbc_file_out; 1291bbecc2bSMatthias Ringwald #endif 1307294d009SMatthias Ringwald 1312b89dbfcSMatthias Ringwald int num_samples_to_write; 1322b89dbfcSMatthias Ringwald int num_audio_frames; 133249d94cfSMatthias Ringwald unsigned int phase; 1342b89dbfcSMatthias Ringwald 135f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 136d6a06398SMatthias Ringwald 1377556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz 138c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 1397556ab9fSMatthias Ringwald 0, 3135, 6237, 9270, 12202, 14999, 17633, 20073, 22294, 24270, 1407556ab9fSMatthias Ringwald 25980, 27406, 28531, 29344, 29835, 30000, 29835, 29344, 28531, 27406, 1417556ab9fSMatthias Ringwald 25980, 24270, 22294, 20073, 17633, 14999, 12202, 9270, 6237, 3135, 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, 14535fd3fb9SMatthias Ringwald }; 14635fd3fb9SMatthias Ringwald 14759c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian 148adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){ 149249d94cfSMatthias Ringwald unsigned int i; 15059c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 15159c97ae1SMatthias Ringwald int16_t sample = sine_int16_at_16000hz[phase]; 152adaba9f3SMatthias Ringwald little_endian_store_16(data, i * 2, sample); 15359c97ae1SMatthias Ringwald // ony use every second sample from 16khz table to get 8khz 15459c97ae1SMatthias Ringwald phase += 2; 155c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 15635fd3fb9SMatthias Ringwald phase = 0; 15735fd3fb9SMatthias Ringwald } 15835fd3fb9SMatthias Ringwald } 15935fd3fb9SMatthias Ringwald } 16035fd3fb9SMatthias Ringwald 1611bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess 1621bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 163249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){ 164249d94cfSMatthias Ringwald unsigned int i; 1651bbecc2bSMatthias Ringwald for (i=0; i < num_samples; i++){ 1661bbecc2bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase++]; 1671bbecc2bSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 1681bbecc2bSMatthias Ringwald phase = 0; 1691bbecc2bSMatthias Ringwald } 1701bbecc2bSMatthias Ringwald } 1711bbecc2bSMatthias Ringwald } 1721bbecc2bSMatthias Ringwald 173b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){ 17435fd3fb9SMatthias Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 17535fd3fb9SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 176379c5f5fSMatthias Ringwald if (num_samples > MAX_NUM_MSBC_SAMPLES) return; 177379c5f5fSMatthias Ringwald int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES]; 17859c97ae1SMatthias Ringwald sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer); 17935fd3fb9SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 18035fd3fb9SMatthias Ringwald num_audio_frames++; 18135fd3fb9SMatthias Ringwald } 1822b89dbfcSMatthias Ringwald #endif 1831bbecc2bSMatthias Ringwald #endif 184dbb41bfeSMilanka Ringwald 185379c5f5fSMatthias Ringwald static void playback_callback(int16_t * buffer, uint16_t num_samples){ 1862b89dbfcSMatthias Ringwald 187c4e666bcSMatthias Ringwald // config based on codec 188379c5f5fSMatthias Ringwald int bytes_to_copy = num_samples * BYTES_PER_FRAME; 189be030f50SMilanka Ringwald uint32_t prebuffer_bytes; 190c4e666bcSMatthias Ringwald switch (negotiated_codec){ 191c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 192c4e666bcSMatthias Ringwald prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES; 193c4e666bcSMatthias Ringwald break; 194c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 195c4e666bcSMatthias Ringwald default: 196379c5f5fSMatthias Ringwald prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES; 197c4e666bcSMatthias Ringwald break; 198dbb41bfeSMilanka Ringwald } 199dbb41bfeSMilanka Ringwald 200c4e666bcSMatthias Ringwald // fill with silence while paused 201379c5f5fSMatthias Ringwald if (audio_output_paused){ 202379c5f5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){ 203379c5f5fSMatthias Ringwald memset(buffer, 0, bytes_to_copy); 204379c5f5fSMatthias Ringwald return; 205dbb41bfeSMilanka Ringwald } else { 206c4e666bcSMatthias Ringwald // resume playback 207379c5f5fSMatthias Ringwald audio_output_paused = 0; 208dbb41bfeSMilanka Ringwald } 209c4e666bcSMatthias Ringwald } 210c4e666bcSMatthias Ringwald 211c4e666bcSMatthias Ringwald // get data from ringbuffer 212c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 213379c5f5fSMatthias Ringwald btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, bytes_to_copy, &bytes_read); 214c4e666bcSMatthias Ringwald bytes_to_copy -= bytes_read; 215c4e666bcSMatthias Ringwald 216c4e666bcSMatthias Ringwald // fill with 0 if not enough 217c4e666bcSMatthias Ringwald if (bytes_to_copy){ 218379c5f5fSMatthias Ringwald memset(buffer + bytes_read, 0, bytes_to_copy); 219379c5f5fSMatthias Ringwald audio_output_paused = 1; 220c4e666bcSMatthias Ringwald } 221379c5f5fSMatthias Ringwald } 2228b29cfc6SMatthias Ringwald 223379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 224379c5f5fSMatthias Ringwald static void recording_callback(const int16_t * buffer, uint16_t num_samples){ 225379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2); 226c4e666bcSMatthias Ringwald } 227379c5f5fSMatthias Ringwald #endif 228c4e666bcSMatthias Ringwald 229c4e666bcSMatthias Ringwald // return 1 if ok 230379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){ 231c4e666bcSMatthias Ringwald 232379c5f5fSMatthias Ringwald // init buffers 233379c5f5fSMatthias Ringwald memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage)); 234379c5f5fSMatthias Ringwald btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage)); 235379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 236379c5f5fSMatthias Ringwald memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage)); 237379c5f5fSMatthias Ringwald btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage)); 238379c5f5fSMatthias Ringwald printf("Audio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&audio_input_ring_buffer)); 2392b89dbfcSMatthias Ringwald #endif 2402b89dbfcSMatthias Ringwald 241379c5f5fSMatthias Ringwald // config and setup audio playback/recording 242379c5f5fSMatthias Ringwald const btstack_audio_t * audio = btstack_audio_get_instance(); 243379c5f5fSMatthias Ringwald if (!audio) return 0; 2442b89dbfcSMatthias Ringwald 245379c5f5fSMatthias Ringwald void (*recording)(const int16_t * buffer, uint16_t num_samples) = NULL; 246379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 247379c5f5fSMatthias Ringwald recording = &recording_callback; 248379c5f5fSMatthias Ringwald #endif 249379c5f5fSMatthias Ringwald audio->init(1, sample_rate, &playback_callback, recording); 250379c5f5fSMatthias Ringwald audio->start_stream(); 251379c5f5fSMatthias Ringwald 252379c5f5fSMatthias Ringwald audio_output_paused = 1; 253379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 254379c5f5fSMatthias Ringwald audio_input_paused = 1; 2552b89dbfcSMatthias Ringwald #endif 2562b89dbfcSMatthias Ringwald 257c4e666bcSMatthias Ringwald return 1; 258c4e666bcSMatthias Ringwald } 2592b89dbfcSMatthias Ringwald 260379c5f5fSMatthias Ringwald static void audio_terminate(void){ 261379c5f5fSMatthias Ringwald const btstack_audio_t * audio = btstack_audio_get_instance(); 262379c5f5fSMatthias Ringwald if (!audio) return; 263379c5f5fSMatthias Ringwald audio->close(); 2642b89dbfcSMatthias Ringwald } 265c4e666bcSMatthias Ringwald 2662c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 267c4e666bcSMatthias Ringwald 2681bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 269c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 270c4e666bcSMatthias Ringwald UNUSED(context); 271c4e666bcSMatthias Ringwald UNUSED(sample_rate); 2722c7ae6e1SMatthias Ringwald UNUSED(data); 2732c7ae6e1SMatthias Ringwald UNUSED(num_samples); 2742c7ae6e1SMatthias Ringwald UNUSED(num_channels); 2752c7ae6e1SMatthias Ringwald 2762c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 277c4e666bcSMatthias Ringwald 278c4e666bcSMatthias Ringwald // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); 279379c5f5fSMatthias Ringwald 280379c5f5fSMatthias Ringwald // samples in callback in host endianess, ready for playback 281379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 282dbb41bfeSMilanka Ringwald 2832c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 284fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 285fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 286fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 287fbc7c9f2SMilanka Ringwald wav_writer_write_int16(num_samples, data); 288fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 2892c7ae6e1SMatthias Ringwald wav_writer_close(); 290fcb08cdbSMilanka Ringwald } 2911bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 2922c7ae6e1SMatthias Ringwald 2931bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */ 294fcb08cdbSMilanka Ringwald } 2951bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 2961bbecc2bSMatthias Ringwald 2971bbecc2bSMatthias Ringwald 2981bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 299fcb08cdbSMilanka Ringwald 300fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 301c4e666bcSMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 302c4e666bcSMatthias Ringwald 303fbc7c9f2SMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 304220eb563SMilanka Ringwald hfp_msbc_init(); 3052c7ae6e1SMatthias Ringwald 3062c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3072c7ae6e1SMatthias Ringwald num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 3082c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE); 3092c7ae6e1SMatthias Ringwald #endif 3102c7ae6e1SMatthias Ringwald 3112b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 312b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 3132b89dbfcSMatthias Ringwald #endif 314973d7173SMatthias Ringwald 315d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME 316d5e5f834SMatthias Ringwald msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 317d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 318d5e5f834SMatthias Ringwald #endif 3192b89dbfcSMatthias Ringwald 3207294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 321d5e5f834SMatthias Ringwald msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 322d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 3237294d009SMatthias Ringwald #endif 324dbb41bfeSMilanka Ringwald 325379c5f5fSMatthias Ringwald audio_initialize(MSBC_SAMPLE_RATE); 326fcb08cdbSMilanka Ringwald } 327fcb08cdbSMilanka Ringwald 328fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 329fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 330d5e5f834SMatthias Ringwald if (msbc_file_in){ 331d5e5f834SMatthias Ringwald // log incoming mSBC data for testing 332d5e5f834SMatthias Ringwald fwrite(packet+3, size-3, 1, msbc_file_in); 333d5e5f834SMatthias Ringwald } 334fcb08cdbSMilanka Ringwald } 335dbb41bfeSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 336fcb08cdbSMilanka Ringwald } 3371bbecc2bSMatthias Ringwald #endif 338fcb08cdbSMilanka Ringwald 339fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){ 340c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 341c4e666bcSMatthias Ringwald 342fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 343c4e666bcSMatthias Ringwald 3442c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 345c4e666bcSMatthias Ringwald num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 3462c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE); 3472c7ae6e1SMatthias Ringwald #endif 348dbb41bfeSMilanka Ringwald 349379c5f5fSMatthias Ringwald audio_initialize(CVSD_SAMPLE_RATE); 350fbc7c9f2SMilanka Ringwald } 351fbc7c9f2SMilanka Ringwald 352fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 353dbb41bfeSMilanka Ringwald if (!num_samples_to_write) return; 3542c7ae6e1SMatthias Ringwald 3555303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 3561f8694ccSMatthias Ringwald 3571f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 3581f8694ccSMatthias Ringwald printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); 3591f8694ccSMatthias Ringwald return; 3601f8694ccSMatthias Ringwald } 3612c7ae6e1SMatthias Ringwald 362c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 363379c5f5fSMatthias Ringwald const int num_samples = audio_bytes_read / BYTES_PER_FRAME; 3645303ddeeSMatthias Ringwald 3655303ddeeSMatthias Ringwald // convert into host endian 3665303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 3675303ddeeSMatthias Ringwald int i; 3685303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 3695303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 3705303ddeeSMatthias Ringwald } 3715303ddeeSMatthias Ringwald 372e36764ddSMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out); 3735303ddeeSMatthias Ringwald 3742c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3752c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 3762c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 3772c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 3782c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 3792c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 3802c7ae6e1SMatthias Ringwald wav_writer_close(); 3812c7ae6e1SMatthias Ringwald } 3822c7ae6e1SMatthias Ringwald #endif 3832c7ae6e1SMatthias Ringwald 384379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 385fcb08cdbSMilanka Ringwald } 386fcb08cdbSMilanka Ringwald 3872c7ae6e1SMatthias Ringwald #endif 3882c7ae6e1SMatthias Ringwald 3892c7ae6e1SMatthias Ringwald 390fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 391c4e666bcSMatthias Ringwald printf("SCO demo close\n"); 3922b89dbfcSMatthias Ringwald 39326463303SMilanka Ringwald printf("SCO demo statistics: "); 3941bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 39526463303SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 3962c7ae6e1SMatthias 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); 3971bbecc2bSMatthias Ringwald } else 3981bbecc2bSMatthias Ringwald #endif 3991bbecc2bSMatthias Ringwald { 4002c7ae6e1SMatthias 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); 40126463303SMilanka Ringwald } 40226463303SMilanka Ringwald 4032c7ae6e1SMatthias Ringwald negotiated_codec = -1; 4042c7ae6e1SMatthias Ringwald 4052c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 4062c7ae6e1SMatthias Ringwald 4072c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 4082c7ae6e1SMatthias Ringwald wav_writer_close(); 4092c7ae6e1SMatthias Ringwald #endif 4102c7ae6e1SMatthias Ringwald 411379c5f5fSMatthias Ringwald audio_terminate(); 412fcb08cdbSMilanka Ringwald 413fcb08cdbSMilanka Ringwald #endif 414fcb08cdbSMilanka Ringwald } 415fcb08cdbSMilanka Ringwald 416fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 417fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 418fcb08cdbSMilanka Ringwald negotiated_codec = codec; 4192c7ae6e1SMatthias Ringwald 4202b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 421220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 4221bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 423fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 4241bbecc2bSMatthias Ringwald #endif 425fcb08cdbSMilanka Ringwald } else { 426fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 427fcb08cdbSMilanka Ringwald } 428fcb08cdbSMilanka Ringwald #endif 429fcb08cdbSMilanka Ringwald } 430fcb08cdbSMilanka Ringwald 431f7c85330SMatthias Ringwald void sco_demo_init(void){ 432f7c85330SMatthias Ringwald // status 4332b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 434379c5f5fSMatthias Ringwald printf("SCO Demo: Sending and receiving audio via btstack_audio.\n"); 4352b89dbfcSMatthias Ringwald #endif 436f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 437f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 438379c5f5fSMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n"); 439f7c85330SMatthias Ringwald #else 440f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 441f7c85330SMatthias Ringwald #endif 442f7c85330SMatthias Ringwald #endif 443f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 444f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 445f7c85330SMatthias Ringwald #endif 446f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 447f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 448f7c85330SMatthias Ringwald #endif 449f7c85330SMatthias Ringwald 4502b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 451c4e666bcSMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 452c4e666bcSMatthias Ringwald #else 453f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 4547294d009SMatthias Ringwald #endif 455f7c85330SMatthias Ringwald 456f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 457f7c85330SMatthias Ringwald phase = 'a'; 458f7c85330SMatthias Ringwald #endif 459f7c85330SMatthias Ringwald } 460f7c85330SMatthias Ringwald 4611a919128SMatthias Ringwald void sco_report(void); 4621a919128SMatthias Ringwald 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 468*e1de95beSMatthias Ringwald if (sco_handle == HCI_CON_HANDLE_INVALID) return; 469f7c85330SMatthias Ringwald 470c4e666bcSMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 471c4e666bcSMatthias Ringwald 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 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 4761bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 477220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 478c4e666bcSMatthias Ringwald // overwrite 479c4e666bcSMatthias Ringwald sco_payload_length = 24; 480c4e666bcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 481c4e666bcSMatthias Ringwald 482220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 483220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 484220eb563SMilanka Ringwald } 485220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 486d5e5f834SMatthias Ringwald if (msbc_file_out){ 487d76591efSMatthias Ringwald // log outgoing mSBC data for testing 488d5e5f834SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 489d76591efSMatthias Ringwald } 4907294d009SMatthias Ringwald 491b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 4921bbecc2bSMatthias Ringwald } else 4931bbecc2bSMatthias Ringwald #endif 4941bbecc2bSMatthias Ringwald { 495379c5f5fSMatthias Ringwald const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME; 496adaba9f3SMatthias Ringwald sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]); 497220eb563SMilanka Ringwald } 4981a919128SMatthias Ringwald #endif 4992b89dbfcSMatthias Ringwald 5002b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 5012b89dbfcSMatthias Ringwald 5022b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 5032b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 5042b89dbfcSMatthias Ringwald // MSBC 5052b89dbfcSMatthias Ringwald 5062b89dbfcSMatthias Ringwald // overwrite 5072b89dbfcSMatthias Ringwald sco_payload_length = 24; 5082b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 5092b89dbfcSMatthias Ringwald 510379c5f5fSMatthias Ringwald if (audio_input_paused){ 511379c5f5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ 512b025eb5fSMatthias Ringwald // resume sending 513379c5f5fSMatthias Ringwald audio_input_paused = 0; 5142b89dbfcSMatthias Ringwald } 515b025eb5fSMatthias Ringwald } 516b025eb5fSMatthias Ringwald 517379c5f5fSMatthias Ringwald if (!audio_input_paused){ 518b025eb5fSMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 519379c5f5fSMatthias Ringwald if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert 520379c5f5fSMatthias 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)){ 521379c5f5fSMatthias Ringwald int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES]; 522b025eb5fSMatthias Ringwald uint32_t bytes_read; 523379c5f5fSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 524b025eb5fSMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 525b025eb5fSMatthias Ringwald num_audio_frames++; 526b025eb5fSMatthias Ringwald } 527b025eb5fSMatthias Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 528b025eb5fSMatthias Ringwald log_error("mSBC stream should not be empty."); 529379c5f5fSMatthias Ringwald } 530379c5f5fSMatthias Ringwald } 531379c5f5fSMatthias Ringwald 532379c5f5fSMatthias Ringwald if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 533b025eb5fSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 534379c5f5fSMatthias Ringwald audio_input_paused = 1; 535b025eb5fSMatthias Ringwald } else { 5362b89dbfcSMatthias Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 5372b89dbfcSMatthias Ringwald if (msbc_file_out){ 5382b89dbfcSMatthias Ringwald // log outgoing mSBC data for testing 5392b89dbfcSMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 5402b89dbfcSMatthias Ringwald } 541b025eb5fSMatthias Ringwald } 5422b89dbfcSMatthias Ringwald 5432b89dbfcSMatthias Ringwald } else { 5442b89dbfcSMatthias Ringwald // CVSD 5452b89dbfcSMatthias Ringwald 546379c5f5fSMatthias 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)); 5472b89dbfcSMatthias Ringwald // fill with silence while paused 5482b89dbfcSMatthias Ringwald int bytes_to_copy = sco_payload_length; 549379c5f5fSMatthias Ringwald if (audio_input_paused){ 550379c5f5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ 5512b89dbfcSMatthias Ringwald // resume sending 552379c5f5fSMatthias Ringwald audio_input_paused = 0; 5532b89dbfcSMatthias Ringwald } 5542b89dbfcSMatthias Ringwald } 5552b89dbfcSMatthias Ringwald 5562b89dbfcSMatthias Ringwald // get data from ringbuffer 5572b89dbfcSMatthias Ringwald uint16_t pos = 0; 5588fd6902dSMatthias Ringwald uint8_t * sample_data = &sco_packet[3]; 559379c5f5fSMatthias Ringwald if (!audio_input_paused){ 5602b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 561379c5f5fSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read); 5628fd6902dSMatthias Ringwald // flip 16 on big endian systems 5638fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 5648fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 5658d3be402SMatthias Ringwald unsigned int i; 5668fd6902dSMatthias Ringwald for (i=0;i<bytes_read;i+=2){ 5678fd6902dSMatthias Ringwald uint8_t tmp = sample_data[i*2]; 5688fd6902dSMatthias Ringwald sample_data[i*2] = sample_data[i*2+1]; 5698fd6902dSMatthias Ringwald sample_data[i*2+1] = tmp; 5708fd6902dSMatthias Ringwald } 5718fd6902dSMatthias Ringwald } 5722b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 5732b89dbfcSMatthias Ringwald pos += bytes_read; 5742b89dbfcSMatthias Ringwald } 5752b89dbfcSMatthias Ringwald 5762b89dbfcSMatthias Ringwald // fill with 0 if not enough 5772b89dbfcSMatthias Ringwald if (bytes_to_copy){ 5788fd6902dSMatthias Ringwald memset(sample_data + pos, 0, bytes_to_copy); 579379c5f5fSMatthias Ringwald audio_input_paused = 1; 5802b89dbfcSMatthias Ringwald } 5812b89dbfcSMatthias Ringwald } 5822b89dbfcSMatthias Ringwald #else 5832b89dbfcSMatthias Ringwald // just send '0's 5842b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 5852b89dbfcSMatthias Ringwald sco_payload_length = 24; 5862b89dbfcSMatthias Ringwald sco_packet_length = sco_payload_length + 3; 5872b89dbfcSMatthias Ringwald } 5882b89dbfcSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 5892b89dbfcSMatthias Ringwald #endif 5902b89dbfcSMatthias Ringwald #endif 5912b89dbfcSMatthias Ringwald 592f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 593c4e666bcSMatthias Ringwald memset(&sco_packet[3], phase++, sco_payload_length); 594f7c85330SMatthias Ringwald if (phase > 'z') phase = 'a'; 5951a919128SMatthias Ringwald #endif 5961a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 59738b2eaafSMatthias Ringwald int j; 598c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 59938b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 600f7c85330SMatthias Ringwald } 601f7c85330SMatthias Ringwald #endif 6021a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 6031a919128SMatthias Ringwald int j; 604c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6051a919128SMatthias Ringwald // sco_packet[3+j] = j & 1 ? 0x35 : 0x53; 6061a919128SMatthias Ringwald sco_packet[3+j] = 0x55; 6071a919128SMatthias Ringwald } 6081a919128SMatthias Ringwald #endif 6091a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00 6101a919128SMatthias Ringwald int j; 611c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6121a919128SMatthias Ringwald sco_packet[3+j] = 0x00; 6131a919128SMatthias Ringwald } 6141a919128SMatthias Ringwald // additional hack 6151a919128SMatthias Ringwald // big_endian_store_16(sco_packet, 5, phase++); 6161a919128SMatthias Ringwald (void) phase; 617f7c85330SMatthias Ringwald #endif 618220eb563SMilanka Ringwald 6192b89dbfcSMatthias Ringwald // test silence 6202b89dbfcSMatthias Ringwald // memset(sco_packet+3, 0, sco_payload_length); 6212b89dbfcSMatthias Ringwald 622c4e666bcSMatthias Ringwald // set handle + flags 623c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 624c4e666bcSMatthias Ringwald // set len 625c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 626c4e666bcSMatthias Ringwald // finally send packet 627f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 628f7c85330SMatthias Ringwald 629f7c85330SMatthias Ringwald // request another send event 630f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 631f7c85330SMatthias Ringwald 6324a96141eSMatthias Ringwald count_sent++; 6331a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55 6344a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 6351a919128SMatthias Ringwald #endif 636f7c85330SMatthias Ringwald } 637f7c85330SMatthias Ringwald 638f7c85330SMatthias Ringwald /** 639f7c85330SMatthias Ringwald * @brief Process received data 640f7c85330SMatthias Ringwald */ 6411a919128SMatthias Ringwald #define ANSI_COLOR_RED "\x1b[31m" 6421a919128SMatthias Ringwald #define ANSI_COLOR_GREEN "\x1b[32m" 6431a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW "\x1b[33m" 6441a919128SMatthias Ringwald #define ANSI_COLOR_BLUE "\x1b[34m" 6451a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m" 6461a919128SMatthias Ringwald #define ANSI_COLOR_CYAN "\x1b[36m" 6471a919128SMatthias Ringwald #define ANSI_COLOR_RESET "\x1b[0m" 6481a919128SMatthias Ringwald 649f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 650f7c85330SMatthias Ringwald 651fcb08cdbSMilanka Ringwald dump_data = 1; 6528b29cfc6SMatthias Ringwald 6534a96141eSMatthias Ringwald count_received++; 6541a919128SMatthias Ringwald static uint32_t packets = 0; 6551a919128SMatthias Ringwald static uint32_t crc_errors = 0; 6561a919128SMatthias Ringwald static uint32_t data_received = 0; 6571a919128SMatthias Ringwald static uint32_t byte_errors = 0; 6584a96141eSMatthias Ringwald 6591a919128SMatthias Ringwald data_received += size - 3; 6601a919128SMatthias Ringwald packets++; 6611a919128SMatthias Ringwald if (data_received > 100000){ 662d4f907a6SMatthias 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); 6631a919128SMatthias Ringwald crc_errors = 0; 6641a919128SMatthias Ringwald byte_errors = 0; 6651a919128SMatthias Ringwald data_received = 0; 6661a919128SMatthias Ringwald packets = 0; 6671a919128SMatthias Ringwald } 6684a96141eSMatthias Ringwald 6692b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 670c4e666bcSMatthias Ringwald switch (negotiated_codec){ 6711bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 672c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 673fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 674c4e666bcSMatthias Ringwald break; 6751bbecc2bSMatthias Ringwald #endif 676c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 677fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 678c4e666bcSMatthias Ringwald break; 679c4e666bcSMatthias Ringwald default: 680c4e666bcSMatthias Ringwald break; 6818b29cfc6SMatthias Ringwald } 682dbb41bfeSMilanka Ringwald dump_data = 0; 6838b29cfc6SMatthias Ringwald #endif 6848b29cfc6SMatthias Ringwald 685b3f76298SMilanka Ringwald if (packet[1] & 0x30){ 6861a919128SMatthias Ringwald crc_errors++; 6871a919128SMatthias Ringwald // printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 6881a919128SMatthias Ringwald // printf_hexdump(&packet[3], size-3); 689f7c85330SMatthias Ringwald return; 690f7c85330SMatthias Ringwald } 6918b29cfc6SMatthias Ringwald if (dump_data){ 692f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 6931a919128SMatthias Ringwald printf("data: "); 694f7c85330SMatthias Ringwald int i; 695f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 696f7c85330SMatthias Ringwald printf("%c", packet[i]); 697f7c85330SMatthias Ringwald } 698f7c85330SMatthias Ringwald printf("\n"); 6998b29cfc6SMatthias Ringwald dump_data = 0; 7001a919128SMatthias Ringwald #endif 7011a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 7021a919128SMatthias Ringwald // colored hexdump with expected 7031a919128SMatthias Ringwald static uint8_t expected_byte = 0; 7041a919128SMatthias Ringwald int i; 7051a919128SMatthias Ringwald printf("data: "); 7061a919128SMatthias Ringwald for (i=3;i<size;i++){ 7071a919128SMatthias Ringwald if (packet[i] != expected_byte){ 7081a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7091a919128SMatthias Ringwald } else { 7101a919128SMatthias Ringwald printf("%02x ", packet[i]); 7111a919128SMatthias Ringwald } 7121a919128SMatthias Ringwald expected_byte = packet[i]+1; 7131a919128SMatthias Ringwald } 7141a919128SMatthias Ringwald printf("\n"); 7151a919128SMatthias Ringwald #endif 716a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00 7171a919128SMatthias Ringwald int i; 7181a919128SMatthias Ringwald int contains_error = 0; 7191a919128SMatthias Ringwald for (i=3;i<size;i++){ 7201a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 7211a919128SMatthias Ringwald contains_error = 1; 7221a919128SMatthias Ringwald byte_errors++; 7231a919128SMatthias Ringwald } 7241a919128SMatthias Ringwald } 7251a919128SMatthias Ringwald if (contains_error){ 7261a919128SMatthias Ringwald printf("data: "); 7271a919128SMatthias Ringwald for (i=0;i<3;i++){ 7281a919128SMatthias Ringwald printf("%02x ", packet[i]); 7291a919128SMatthias Ringwald } 7301a919128SMatthias Ringwald for (i=3;i<size;i++){ 7311a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 7321a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7331a919128SMatthias Ringwald } else { 7341a919128SMatthias Ringwald printf("%02x ", packet[i]); 7351a919128SMatthias Ringwald } 7361a919128SMatthias Ringwald } 7371a919128SMatthias Ringwald printf("\n"); 7381a919128SMatthias Ringwald } 739f7c85330SMatthias Ringwald #endif 7408b29cfc6SMatthias Ringwald } 741f7c85330SMatthias Ringwald } 742