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 69*d365bb51SMatthias 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 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 #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME) 95379c5f5fSMatthias Ringwald #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME) 96f7c85330SMatthias Ringwald 972b89dbfcSMatthias Ringwald // output 98379c5f5fSMatthias Ringwald 99d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 100d861f4bfSMatthias Ringwald static int audio_output_paused = 0; 101379c5f5fSMatthias Ringwald static uint8_t audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES]; 102379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer; 103d861f4bfSMatthias Ringwald #endif 104d861f4bfSMatthias Ringwald 1052b89dbfcSMatthias Ringwald 1062b89dbfcSMatthias Ringwald // input 1072b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 108379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT 109379c5f5fSMatthias Ringwald static int audio_input_paused = 0; 110379c5f5fSMatthias Ringwald static uint8_t audio_input_ring_buffer_storage[2*8000]; // full second input buffer 111379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer; 112f7c85330SMatthias Ringwald #endif 113f7c85330SMatthias Ringwald 114fcb08cdbSMilanka Ringwald static int dump_data = 1; 115fcb08cdbSMilanka Ringwald static int count_sent = 0; 116fcb08cdbSMilanka Ringwald static int count_received = 0; 117c4e666bcSMatthias Ringwald static int negotiated_codec = -1; 118c4e666bcSMatthias Ringwald 1191bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 120379c5f5fSMatthias Ringwald static btstack_sbc_decoder_state_t decoder_state; 1211bbecc2bSMatthias Ringwald #endif 1221bbecc2bSMatthias Ringwald 123379c5f5fSMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state; 124379c5f5fSMatthias Ringwald 125379c5f5fSMatthias Ringwald #define MAX_NUM_MSBC_SAMPLES (16*8) 126fcb08cdbSMilanka Ringwald 1271bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 128d5e5f834SMatthias Ringwald FILE * msbc_file_in; 129d5e5f834SMatthias Ringwald FILE * msbc_file_out; 1301bbecc2bSMatthias Ringwald #endif 1317294d009SMatthias Ringwald 1322b89dbfcSMatthias Ringwald int num_samples_to_write; 1332b89dbfcSMatthias Ringwald int num_audio_frames; 134249d94cfSMatthias Ringwald unsigned int phase; 1352b89dbfcSMatthias Ringwald 136f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 137d6a06398SMatthias Ringwald 1387556ab9fSMatthias Ringwald // input signal: pre-computed sine wave, 266 Hz at 16000 kHz 139c4e666bcSMatthias Ringwald static const int16_t sine_int16_at_16000hz[] = { 1407556ab9fSMatthias Ringwald 0, 3135, 6237, 9270, 12202, 14999, 17633, 20073, 22294, 24270, 1417556ab9fSMatthias Ringwald 25980, 27406, 28531, 29344, 29835, 30000, 29835, 29344, 28531, 27406, 1427556ab9fSMatthias Ringwald 25980, 24270, 22294, 20073, 17633, 14999, 12202, 9270, 6237, 3135, 1437556ab9fSMatthias Ringwald 0, -3135, -6237, -9270, -12202, -14999, -17633, -20073, -22294, -24270, 1447556ab9fSMatthias Ringwald -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406, 1457556ab9fSMatthias Ringwald -25980, -24270, -22294, -20073, -17633, -14999, -12202, -9270, -6237, -3135, 14635fd3fb9SMatthias Ringwald }; 14735fd3fb9SMatthias Ringwald 14859c97ae1SMatthias Ringwald // 8 kHz samples for CVSD/SCO packets in little endian 149adaba9f3SMatthias Ringwald static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){ 150249d94cfSMatthias Ringwald unsigned int i; 15159c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 15259c97ae1SMatthias Ringwald int16_t sample = sine_int16_at_16000hz[phase]; 153adaba9f3SMatthias Ringwald little_endian_store_16(data, i * 2, sample); 15459c97ae1SMatthias Ringwald // ony use every second sample from 16khz table to get 8khz 15559c97ae1SMatthias Ringwald phase += 2; 156c4e666bcSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 15735fd3fb9SMatthias Ringwald phase = 0; 15835fd3fb9SMatthias Ringwald } 15935fd3fb9SMatthias Ringwald } 16035fd3fb9SMatthias Ringwald } 16135fd3fb9SMatthias Ringwald 1621bbecc2bSMatthias Ringwald // 16 kHz samples for mSBC encoder in host endianess 1631bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 164249d94cfSMatthias Ringwald static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(unsigned int num_samples, int16_t * data){ 165249d94cfSMatthias Ringwald unsigned int i; 1661bbecc2bSMatthias Ringwald for (i=0; i < num_samples; i++){ 1671bbecc2bSMatthias Ringwald data[i] = sine_int16_at_16000hz[phase++]; 1681bbecc2bSMatthias Ringwald if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 1691bbecc2bSMatthias Ringwald phase = 0; 1701bbecc2bSMatthias Ringwald } 1711bbecc2bSMatthias Ringwald } 1721bbecc2bSMatthias Ringwald } 1731bbecc2bSMatthias Ringwald 174b025eb5fSMatthias Ringwald static void sco_demo_msbc_fill_sine_audio_frame(void){ 17535fd3fb9SMatthias Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 17635fd3fb9SMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 177379c5f5fSMatthias Ringwald if (num_samples > MAX_NUM_MSBC_SAMPLES) return; 178379c5f5fSMatthias Ringwald int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES]; 17959c97ae1SMatthias Ringwald sco_demo_sine_wave_int16_at_16000_hz_host_endian(num_samples, sample_buffer); 18035fd3fb9SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 18135fd3fb9SMatthias Ringwald num_audio_frames++; 18235fd3fb9SMatthias Ringwald } 1832b89dbfcSMatthias Ringwald #endif 1841bbecc2bSMatthias Ringwald #endif 185dbb41bfeSMilanka Ringwald 186d861f4bfSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 187d861f4bfSMatthias Ringwald 188379c5f5fSMatthias Ringwald static void playback_callback(int16_t * buffer, uint16_t num_samples){ 1892b89dbfcSMatthias Ringwald 190c4e666bcSMatthias Ringwald // config based on codec 191379c5f5fSMatthias Ringwald int bytes_to_copy = num_samples * BYTES_PER_FRAME; 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){ 206379c5f5fSMatthias Ringwald memset(buffer, 0, bytes_to_copy); 207379c5f5fSMatthias Ringwald return; 208dbb41bfeSMilanka Ringwald } else { 209c4e666bcSMatthias Ringwald // resume playback 210379c5f5fSMatthias Ringwald audio_output_paused = 0; 211dbb41bfeSMilanka Ringwald } 212c4e666bcSMatthias Ringwald } 213c4e666bcSMatthias Ringwald 214c4e666bcSMatthias Ringwald // get data from ringbuffer 215c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 216379c5f5fSMatthias Ringwald btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, bytes_to_copy, &bytes_read); 217c4e666bcSMatthias Ringwald bytes_to_copy -= bytes_read; 218c4e666bcSMatthias Ringwald 219c4e666bcSMatthias Ringwald // fill with 0 if not enough 220c4e666bcSMatthias Ringwald if (bytes_to_copy){ 221379c5f5fSMatthias Ringwald memset(buffer + bytes_read, 0, bytes_to_copy); 222379c5f5fSMatthias Ringwald audio_output_paused = 1; 223c4e666bcSMatthias Ringwald } 224379c5f5fSMatthias Ringwald } 2258b29cfc6SMatthias Ringwald 226379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 227379c5f5fSMatthias Ringwald static void recording_callback(const int16_t * buffer, uint16_t num_samples){ 228379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2); 229c4e666bcSMatthias Ringwald } 230379c5f5fSMatthias Ringwald #endif 231c4e666bcSMatthias Ringwald 232c4e666bcSMatthias Ringwald // return 1 if ok 233379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){ 234c4e666bcSMatthias Ringwald 235*d365bb51SMatthias Ringwald // -- output -- // 236*d365bb51SMatthias Ringwald 237379c5f5fSMatthias Ringwald // init buffers 238379c5f5fSMatthias Ringwald memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage)); 239379c5f5fSMatthias Ringwald btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage)); 2402b89dbfcSMatthias Ringwald 241*d365bb51SMatthias Ringwald // config and setup audio playback 242*d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 243*d365bb51SMatthias Ringwald if (!audio_sink) return 0; 2442b89dbfcSMatthias Ringwald 245*d365bb51SMatthias Ringwald audio_sink->init(1, sample_rate, &playback_callback); 246*d365bb51SMatthias Ringwald audio_sink->start_stream(); 247379c5f5fSMatthias Ringwald 248379c5f5fSMatthias Ringwald audio_output_paused = 1; 249*d365bb51SMatthias Ringwald 250*d365bb51SMatthias Ringwald // -- input -- // 251*d365bb51SMatthias Ringwald 252379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 253*d365bb51SMatthias Ringwald // init buffers 254*d365bb51SMatthias Ringwald memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage)); 255*d365bb51SMatthias Ringwald btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage)); 256*d365bb51SMatthias Ringwald 257*d365bb51SMatthias Ringwald // config and setup audio recording 258*d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance(); 259*d365bb51SMatthias Ringwald if (!audio_source) return 0; 260*d365bb51SMatthias Ringwald 261*d365bb51SMatthias Ringwald audio_source->init(1, sample_rate, &recording_callback); 262*d365bb51SMatthias Ringwald audio_source->start_stream(); 263*d365bb51SMatthias Ringwald 264379c5f5fSMatthias Ringwald audio_input_paused = 1; 2652b89dbfcSMatthias Ringwald #endif 2662b89dbfcSMatthias Ringwald 267c4e666bcSMatthias Ringwald return 1; 268c4e666bcSMatthias Ringwald } 2692b89dbfcSMatthias Ringwald 270379c5f5fSMatthias Ringwald static void audio_terminate(void){ 271*d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 272*d365bb51SMatthias Ringwald if (!audio_sink) return; 273*d365bb51SMatthias Ringwald audio_sink->close(); 274*d365bb51SMatthias Ringwald 275*d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT 276*d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance(); 277*d365bb51SMatthias Ringwald if (!audio_source) return; 278*d365bb51SMatthias Ringwald audio_source->close(); 279*d365bb51SMatthias Ringwald #endif 2802b89dbfcSMatthias Ringwald } 281c4e666bcSMatthias Ringwald 2821bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 283d861f4bfSMatthias Ringwald 284c4e666bcSMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 285c4e666bcSMatthias Ringwald UNUSED(context); 286c4e666bcSMatthias Ringwald UNUSED(sample_rate); 2872c7ae6e1SMatthias Ringwald UNUSED(data); 2882c7ae6e1SMatthias Ringwald UNUSED(num_samples); 2892c7ae6e1SMatthias Ringwald UNUSED(num_channels); 2902c7ae6e1SMatthias Ringwald 2912c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 292c4e666bcSMatthias Ringwald 293c4e666bcSMatthias Ringwald // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); 294379c5f5fSMatthias Ringwald 295379c5f5fSMatthias Ringwald // samples in callback in host endianess, ready for playback 296379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 297dbb41bfeSMilanka Ringwald 2982c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 299fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 300fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 301fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 302fbc7c9f2SMilanka Ringwald wav_writer_write_int16(num_samples, data); 303fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 3042c7ae6e1SMatthias Ringwald wav_writer_close(); 305fcb08cdbSMilanka Ringwald } 3061bbecc2bSMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 3072c7ae6e1SMatthias Ringwald 3081bbecc2bSMatthias Ringwald #endif /* Demo mode sine or microphone */ 309fcb08cdbSMilanka Ringwald } 3101bbecc2bSMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 3111bbecc2bSMatthias Ringwald 3121bbecc2bSMatthias Ringwald 3131bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 314fcb08cdbSMilanka Ringwald 315fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 316c4e666bcSMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 317c4e666bcSMatthias Ringwald 318fbc7c9f2SMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 319220eb563SMilanka Ringwald hfp_msbc_init(); 3202c7ae6e1SMatthias Ringwald 3212c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3222c7ae6e1SMatthias Ringwald num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 3232c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE); 3242c7ae6e1SMatthias Ringwald #endif 3252c7ae6e1SMatthias Ringwald 3262b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 327b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 3282b89dbfcSMatthias Ringwald #endif 329973d7173SMatthias Ringwald 330d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME 331d5e5f834SMatthias Ringwald msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 332d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 333d5e5f834SMatthias Ringwald #endif 3342b89dbfcSMatthias Ringwald 3357294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 336d5e5f834SMatthias Ringwald msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 337d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 3387294d009SMatthias Ringwald #endif 339dbb41bfeSMilanka Ringwald 340379c5f5fSMatthias Ringwald audio_initialize(MSBC_SAMPLE_RATE); 341fcb08cdbSMilanka Ringwald } 342fcb08cdbSMilanka Ringwald 343fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 344fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 345d5e5f834SMatthias Ringwald if (msbc_file_in){ 346d5e5f834SMatthias Ringwald // log incoming mSBC data for testing 347d5e5f834SMatthias Ringwald fwrite(packet+3, size-3, 1, msbc_file_in); 348d5e5f834SMatthias Ringwald } 349fcb08cdbSMilanka Ringwald } 350dbb41bfeSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 351fcb08cdbSMilanka Ringwald } 3521bbecc2bSMatthias Ringwald #endif 353fcb08cdbSMilanka Ringwald 354fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){ 355c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 356c4e666bcSMatthias Ringwald 357fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 358c4e666bcSMatthias Ringwald 3592c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 360c4e666bcSMatthias Ringwald num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 3612c7ae6e1SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE); 3622c7ae6e1SMatthias Ringwald #endif 363dbb41bfeSMilanka Ringwald 364379c5f5fSMatthias Ringwald audio_initialize(CVSD_SAMPLE_RATE); 365fbc7c9f2SMilanka Ringwald } 366fbc7c9f2SMilanka Ringwald 367fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 368dbb41bfeSMilanka Ringwald if (!num_samples_to_write) return; 3692c7ae6e1SMatthias Ringwald 3705303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 3711f8694ccSMatthias Ringwald 3721f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 3731f8694ccSMatthias Ringwald printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); 3741f8694ccSMatthias Ringwald return; 3751f8694ccSMatthias Ringwald } 3762c7ae6e1SMatthias Ringwald 377c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 378379c5f5fSMatthias Ringwald const int num_samples = audio_bytes_read / BYTES_PER_FRAME; 3795303ddeeSMatthias Ringwald 3805303ddeeSMatthias Ringwald // convert into host endian 3815303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 3825303ddeeSMatthias Ringwald int i; 3835303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 3845303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 3855303ddeeSMatthias Ringwald } 3865303ddeeSMatthias Ringwald 387e36764ddSMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out); 3885303ddeeSMatthias Ringwald 3892c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3902c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 3912c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 3922c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 3932c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 3942c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 3952c7ae6e1SMatthias Ringwald wav_writer_close(); 3962c7ae6e1SMatthias Ringwald } 3972c7ae6e1SMatthias Ringwald #endif 3982c7ae6e1SMatthias Ringwald 399379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 400fcb08cdbSMilanka Ringwald } 401fcb08cdbSMilanka Ringwald 4022c7ae6e1SMatthias Ringwald #endif 4032c7ae6e1SMatthias Ringwald 4042c7ae6e1SMatthias Ringwald 405fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 406c4e666bcSMatthias Ringwald printf("SCO demo close\n"); 4072b89dbfcSMatthias Ringwald 40826463303SMilanka Ringwald printf("SCO demo statistics: "); 4091bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 41026463303SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 4112c7ae6e1SMatthias 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); 4121bbecc2bSMatthias Ringwald } else 4131bbecc2bSMatthias Ringwald #endif 4141bbecc2bSMatthias Ringwald { 4152c7ae6e1SMatthias 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); 41626463303SMilanka Ringwald } 41726463303SMilanka Ringwald 4182c7ae6e1SMatthias Ringwald negotiated_codec = -1; 4192c7ae6e1SMatthias Ringwald 4202c7ae6e1SMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 4212c7ae6e1SMatthias Ringwald 4222c7ae6e1SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 4232c7ae6e1SMatthias Ringwald wav_writer_close(); 4242c7ae6e1SMatthias Ringwald #endif 4252c7ae6e1SMatthias Ringwald 426379c5f5fSMatthias Ringwald audio_terminate(); 427fcb08cdbSMilanka Ringwald 428fcb08cdbSMilanka Ringwald #endif 429fcb08cdbSMilanka Ringwald } 430fcb08cdbSMilanka Ringwald 431fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 432fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 433fcb08cdbSMilanka Ringwald negotiated_codec = codec; 4342c7ae6e1SMatthias Ringwald 4352b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 436220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 4371bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 438fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 4391bbecc2bSMatthias Ringwald #endif 440fcb08cdbSMilanka Ringwald } else { 441fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 442fcb08cdbSMilanka Ringwald } 443fcb08cdbSMilanka Ringwald #endif 444fcb08cdbSMilanka Ringwald } 445fcb08cdbSMilanka Ringwald 446f7c85330SMatthias Ringwald void sco_demo_init(void){ 447f7c85330SMatthias Ringwald // status 4482b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 449379c5f5fSMatthias Ringwald printf("SCO Demo: Sending and receiving audio via btstack_audio.\n"); 4502b89dbfcSMatthias Ringwald #endif 451f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 452f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 453379c5f5fSMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n"); 454f7c85330SMatthias Ringwald #else 455f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 456f7c85330SMatthias Ringwald #endif 457f7c85330SMatthias Ringwald #endif 458f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 459f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 460f7c85330SMatthias Ringwald #endif 461f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 462f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 463f7c85330SMatthias Ringwald #endif 464f7c85330SMatthias Ringwald 4652b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 466c4e666bcSMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 467c4e666bcSMatthias Ringwald #else 468f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 4697294d009SMatthias Ringwald #endif 470f7c85330SMatthias Ringwald } 471f7c85330SMatthias Ringwald 4721a919128SMatthias Ringwald void sco_report(void); 4731a919128SMatthias Ringwald void sco_report(void){ 4744a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 4754a96141eSMatthias Ringwald } 476f7c85330SMatthias Ringwald 477f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 478f7c85330SMatthias Ringwald 479e1de95beSMatthias Ringwald if (sco_handle == HCI_CON_HANDLE_INVALID) return; 480f7c85330SMatthias Ringwald 481c4e666bcSMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length(); 482c4e666bcSMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 483f7c85330SMatthias Ringwald 484f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 485f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 486f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 4871bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 488220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 48901b2daf8SMatthias Ringwald 490220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 491220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 492220eb563SMilanka Ringwald } 493220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 494d5e5f834SMatthias Ringwald if (msbc_file_out){ 495d76591efSMatthias Ringwald // log outgoing mSBC data for testing 496d5e5f834SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 497d76591efSMatthias Ringwald } 4987294d009SMatthias Ringwald 499b025eb5fSMatthias Ringwald sco_demo_msbc_fill_sine_audio_frame(); 5001bbecc2bSMatthias Ringwald } else 5011bbecc2bSMatthias Ringwald #endif 5021bbecc2bSMatthias Ringwald { 503379c5f5fSMatthias Ringwald const int audio_samples_per_packet = sco_payload_length / BYTES_PER_FRAME; 504adaba9f3SMatthias Ringwald sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]); 505220eb563SMilanka Ringwald } 5061a919128SMatthias Ringwald #endif 5072b89dbfcSMatthias Ringwald 5082b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 5092b89dbfcSMatthias Ringwald 5102b89dbfcSMatthias Ringwald #ifdef HAVE_PORTAUDIO 5112b89dbfcSMatthias Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 5122b89dbfcSMatthias Ringwald // MSBC 5132b89dbfcSMatthias Ringwald 514379c5f5fSMatthias Ringwald if (audio_input_paused){ 515379c5f5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ 516b025eb5fSMatthias Ringwald // resume sending 517379c5f5fSMatthias Ringwald audio_input_paused = 0; 5182b89dbfcSMatthias Ringwald } 519b025eb5fSMatthias Ringwald } 520b025eb5fSMatthias Ringwald 521379c5f5fSMatthias Ringwald if (!audio_input_paused){ 522b025eb5fSMatthias Ringwald int num_samples = hfp_msbc_num_audio_samples_per_frame(); 523379c5f5fSMatthias Ringwald if (num_samples > MAX_NUM_MSBC_SAMPLES) return; // assert 524379c5f5fSMatthias 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)){ 525379c5f5fSMatthias Ringwald int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES]; 526b025eb5fSMatthias Ringwald uint32_t bytes_read; 527379c5f5fSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 528b025eb5fSMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 529b025eb5fSMatthias Ringwald num_audio_frames++; 530b025eb5fSMatthias Ringwald } 531b025eb5fSMatthias Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 532b025eb5fSMatthias Ringwald log_error("mSBC stream should not be empty."); 533379c5f5fSMatthias Ringwald } 534379c5f5fSMatthias Ringwald } 535379c5f5fSMatthias Ringwald 536379c5f5fSMatthias Ringwald if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 537b025eb5fSMatthias Ringwald memset(sco_packet + 3, 0, sco_payload_length); 538379c5f5fSMatthias Ringwald audio_input_paused = 1; 539b025eb5fSMatthias Ringwald } else { 5402b89dbfcSMatthias Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 5412b89dbfcSMatthias Ringwald if (msbc_file_out){ 5422b89dbfcSMatthias Ringwald // log outgoing mSBC data for testing 5432b89dbfcSMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 5442b89dbfcSMatthias Ringwald } 545b025eb5fSMatthias Ringwald } 5462b89dbfcSMatthias Ringwald 5472b89dbfcSMatthias Ringwald } else { 5482b89dbfcSMatthias Ringwald // CVSD 5492b89dbfcSMatthias Ringwald 550379c5f5fSMatthias 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)); 5512b89dbfcSMatthias Ringwald // fill with silence while paused 5522b89dbfcSMatthias Ringwald int bytes_to_copy = sco_payload_length; 553379c5f5fSMatthias Ringwald if (audio_input_paused){ 554379c5f5fSMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ 5552b89dbfcSMatthias Ringwald // resume sending 556379c5f5fSMatthias Ringwald audio_input_paused = 0; 5572b89dbfcSMatthias Ringwald } 5582b89dbfcSMatthias Ringwald } 5592b89dbfcSMatthias Ringwald 5602b89dbfcSMatthias Ringwald // get data from ringbuffer 5612b89dbfcSMatthias Ringwald uint16_t pos = 0; 5628fd6902dSMatthias Ringwald uint8_t * sample_data = &sco_packet[3]; 563379c5f5fSMatthias Ringwald if (!audio_input_paused){ 5642b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 565379c5f5fSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read); 5668fd6902dSMatthias Ringwald // flip 16 on big endian systems 5678fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 5688fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 5698d3be402SMatthias Ringwald unsigned int i; 5708fd6902dSMatthias Ringwald for (i=0;i<bytes_read;i+=2){ 5718fd6902dSMatthias Ringwald uint8_t tmp = sample_data[i*2]; 5728fd6902dSMatthias Ringwald sample_data[i*2] = sample_data[i*2+1]; 5738fd6902dSMatthias Ringwald sample_data[i*2+1] = tmp; 5748fd6902dSMatthias Ringwald } 5758fd6902dSMatthias Ringwald } 5762b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 5772b89dbfcSMatthias Ringwald pos += bytes_read; 5782b89dbfcSMatthias Ringwald } 5792b89dbfcSMatthias Ringwald 5802b89dbfcSMatthias Ringwald // fill with 0 if not enough 5812b89dbfcSMatthias Ringwald if (bytes_to_copy){ 5828fd6902dSMatthias Ringwald memset(sample_data + pos, 0, bytes_to_copy); 583379c5f5fSMatthias Ringwald audio_input_paused = 1; 5842b89dbfcSMatthias Ringwald } 5852b89dbfcSMatthias Ringwald } 5862b89dbfcSMatthias Ringwald #else 5872b89dbfcSMatthias Ringwald // just send '0's 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 59301b2daf8SMatthias Ringwald // store packet counter-xxxx 59401b2daf8SMatthias Ringwald snprintf((char *)&sco_packet[3], 5, "%04u", phase++); 59501b2daf8SMatthias Ringwald uint8_t ascii = (phase & 0x0f) + 'a'; 59601b2daf8SMatthias Ringwald sco_packet[3+4] = '-'; 59701b2daf8SMatthias Ringwald memset(&sco_packet[3+5], ascii, sco_payload_length-5); 5981a919128SMatthias Ringwald #endif 5991a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 60038b2eaafSMatthias Ringwald int j; 601c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 60238b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 603f7c85330SMatthias Ringwald } 604f7c85330SMatthias Ringwald #endif 6051a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 6061a919128SMatthias Ringwald int j; 607c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6081a919128SMatthias Ringwald // sco_packet[3+j] = j & 1 ? 0x35 : 0x53; 6091a919128SMatthias Ringwald sco_packet[3+j] = 0x55; 6101a919128SMatthias Ringwald } 6111a919128SMatthias Ringwald #endif 6121a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_00 6131a919128SMatthias Ringwald int j; 614c4e666bcSMatthias Ringwald for (j=0;j<sco_payload_length;j++){ 6151a919128SMatthias Ringwald sco_packet[3+j] = 0x00; 6161a919128SMatthias Ringwald } 6171a919128SMatthias Ringwald // additional hack 6181a919128SMatthias Ringwald // big_endian_store_16(sco_packet, 5, phase++); 6191a919128SMatthias Ringwald (void) phase; 620f7c85330SMatthias Ringwald #endif 621220eb563SMilanka Ringwald 6222b89dbfcSMatthias Ringwald // test silence 6232b89dbfcSMatthias Ringwald // memset(sco_packet+3, 0, sco_payload_length); 6242b89dbfcSMatthias Ringwald 625c4e666bcSMatthias Ringwald // set handle + flags 626c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 627c4e666bcSMatthias Ringwald // set len 628c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 629c4e666bcSMatthias Ringwald // finally send packet 630f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 631f7c85330SMatthias Ringwald 632f7c85330SMatthias Ringwald // request another send event 633f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 634f7c85330SMatthias Ringwald 6354a96141eSMatthias Ringwald count_sent++; 6361a919128SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_55 6374a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 6381a919128SMatthias Ringwald #endif 639f7c85330SMatthias Ringwald } 640f7c85330SMatthias Ringwald 641f7c85330SMatthias Ringwald /** 642f7c85330SMatthias Ringwald * @brief Process received data 643f7c85330SMatthias Ringwald */ 6441a919128SMatthias Ringwald #define ANSI_COLOR_RED "\x1b[31m" 6451a919128SMatthias Ringwald #define ANSI_COLOR_GREEN "\x1b[32m" 6461a919128SMatthias Ringwald #define ANSI_COLOR_YELLOW "\x1b[33m" 6471a919128SMatthias Ringwald #define ANSI_COLOR_BLUE "\x1b[34m" 6481a919128SMatthias Ringwald #define ANSI_COLOR_MAGENTA "\x1b[35m" 6491a919128SMatthias Ringwald #define ANSI_COLOR_CYAN "\x1b[36m" 6501a919128SMatthias Ringwald #define ANSI_COLOR_RESET "\x1b[0m" 6511a919128SMatthias Ringwald 652f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 653f7c85330SMatthias Ringwald 654fcb08cdbSMilanka Ringwald dump_data = 1; 6558b29cfc6SMatthias Ringwald 6564a96141eSMatthias Ringwald count_received++; 6571a919128SMatthias Ringwald static uint32_t packets = 0; 6581a919128SMatthias Ringwald static uint32_t crc_errors = 0; 6591a919128SMatthias Ringwald static uint32_t data_received = 0; 6601a919128SMatthias Ringwald static uint32_t byte_errors = 0; 6614a96141eSMatthias Ringwald 6621a919128SMatthias Ringwald data_received += size - 3; 6631a919128SMatthias Ringwald packets++; 6641a919128SMatthias Ringwald if (data_received > 100000){ 665d4f907a6SMatthias 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); 6661a919128SMatthias Ringwald crc_errors = 0; 6671a919128SMatthias Ringwald byte_errors = 0; 6681a919128SMatthias Ringwald data_received = 0; 6691a919128SMatthias Ringwald packets = 0; 6701a919128SMatthias Ringwald } 6714a96141eSMatthias Ringwald 6722b89dbfcSMatthias Ringwald #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) 673c4e666bcSMatthias Ringwald switch (negotiated_codec){ 6741bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 675c4e666bcSMatthias Ringwald case HFP_CODEC_MSBC: 676fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 677c4e666bcSMatthias Ringwald break; 6781bbecc2bSMatthias Ringwald #endif 679c4e666bcSMatthias Ringwald case HFP_CODEC_CVSD: 680fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 681c4e666bcSMatthias Ringwald break; 682c4e666bcSMatthias Ringwald default: 683c4e666bcSMatthias Ringwald break; 6848b29cfc6SMatthias Ringwald } 685dbb41bfeSMilanka Ringwald dump_data = 0; 6868b29cfc6SMatthias Ringwald #endif 6878b29cfc6SMatthias Ringwald 68801b2daf8SMatthias Ringwald #if 0 689b3f76298SMilanka Ringwald if (packet[1] & 0x30){ 6901a919128SMatthias Ringwald crc_errors++; 69101b2daf8SMatthias Ringwald printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 69201b2daf8SMatthias Ringwald printf_hexdump(&packet[3], size-3); 693f7c85330SMatthias Ringwald return; 694f7c85330SMatthias Ringwald } 69501b2daf8SMatthias Ringwald #endif 69601b2daf8SMatthias Ringwald 6978b29cfc6SMatthias Ringwald if (dump_data){ 698f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 6991a919128SMatthias Ringwald printf("data: "); 700f7c85330SMatthias Ringwald int i; 701f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 702f7c85330SMatthias Ringwald printf("%c", packet[i]); 703f7c85330SMatthias Ringwald } 704f7c85330SMatthias Ringwald printf("\n"); 7058b29cfc6SMatthias Ringwald dump_data = 0; 7061a919128SMatthias Ringwald #endif 7071a919128SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 7081a919128SMatthias Ringwald // colored hexdump with expected 7091a919128SMatthias Ringwald static uint8_t expected_byte = 0; 7101a919128SMatthias Ringwald int i; 7111a919128SMatthias Ringwald printf("data: "); 7121a919128SMatthias Ringwald for (i=3;i<size;i++){ 7131a919128SMatthias Ringwald if (packet[i] != expected_byte){ 7141a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7151a919128SMatthias Ringwald } else { 7161a919128SMatthias Ringwald printf("%02x ", packet[i]); 7171a919128SMatthias Ringwald } 7181a919128SMatthias Ringwald expected_byte = packet[i]+1; 7191a919128SMatthias Ringwald } 7201a919128SMatthias Ringwald printf("\n"); 7211a919128SMatthias Ringwald #endif 722a11bf416SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 || SCO_DEMO_MODE == SCO_DEMO_MODE_00 7231a919128SMatthias Ringwald int i; 7241a919128SMatthias Ringwald int contains_error = 0; 7251a919128SMatthias Ringwald for (i=3;i<size;i++){ 7261a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 7271a919128SMatthias Ringwald contains_error = 1; 7281a919128SMatthias Ringwald byte_errors++; 7291a919128SMatthias Ringwald } 7301a919128SMatthias Ringwald } 7311a919128SMatthias Ringwald if (contains_error){ 7321a919128SMatthias Ringwald printf("data: "); 7331a919128SMatthias Ringwald for (i=0;i<3;i++){ 7341a919128SMatthias Ringwald printf("%02x ", packet[i]); 7351a919128SMatthias Ringwald } 7361a919128SMatthias Ringwald for (i=3;i<size;i++){ 7371a919128SMatthias Ringwald if (packet[i] != 0x00 && packet[i] != 0x35 && packet[i] != 0x53 && packet[i] != 0x55){ 7381a919128SMatthias Ringwald printf(ANSI_COLOR_RED "%02x " ANSI_COLOR_RESET, packet[i]); 7391a919128SMatthias Ringwald } else { 7401a919128SMatthias Ringwald printf("%02x ", packet[i]); 7411a919128SMatthias Ringwald } 7421a919128SMatthias Ringwald } 7431a919128SMatthias Ringwald printf("\n"); 7441a919128SMatthias Ringwald } 745f7c85330SMatthias Ringwald #endif 7468b29cfc6SMatthias Ringwald } 747f7c85330SMatthias Ringwald } 748