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 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH 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 38e501bae0SMatthias 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" 51*37abe280SMatthias Ringwald #include "classic/btstack_sbc_bluedroid.h" 5235fd3fb9SMatthias Ringwald #include "classic/btstack_cvsd_plc.h" 53379c5f5fSMatthias Ringwald #include "classic/btstack_sbc.h" 5435fd3fb9SMatthias Ringwald #include "classic/hfp.h" 55f0d95bdcSMatthias Ringwald #include "classic/hfp_codec.h" 56fcb08cdbSMilanka Ringwald 57681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 58681cb550SMatthias Ringwald #include "btstack_lc3.h" 59681cb550SMatthias Ringwald #include "btstack_lc3_google.h" 60681cb550SMatthias Ringwald #endif 61681cb550SMatthias Ringwald 62681cb550SMatthias Ringwald 63f89e874bSMatthias Ringwald #ifdef _MSC_VER 64f89e874bSMatthias Ringwald // ignore deprecated warning for fopen 65f89e874bSMatthias Ringwald #pragma warning(disable : 4996) 66f89e874bSMatthias Ringwald #endif 67f89e874bSMatthias Ringwald 6835fd3fb9SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 69fbc7c9f2SMilanka Ringwald #include "wav_util.h" 7035fd3fb9SMatthias Ringwald #endif 71fbc7c9f2SMilanka Ringwald 72c4e666bcSMatthias Ringwald // test modes 73f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE 0 7494381a69SMatthias Ringwald #define SCO_DEMO_MODE_MICROPHONE 1 751762039cSMatthias Ringwald #define SCO_DEMO_MODE_MODPLAYER 2 76f7c85330SMatthias Ringwald 77f7c85330SMatthias Ringwald // SCO demo configuration 78d365bb51SMatthias Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_MICROPHONE 79c4e666bcSMatthias Ringwald 80c4e666bcSMatthias Ringwald // number of sco packets until 'report' on console 81f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 82f7c85330SMatthias Ringwald 83f55ac442SMatthias Ringwald 84d4f907a6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 852c7ae6e1SMatthias Ringwald // length and name of wav file on disk 86c4e666bcSMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15 878b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 88859f2bc5SMatthias Ringwald #endif 89859f2bc5SMatthias Ringwald 90c4e666bcSMatthias Ringwald // constants 91c4e666bcSMatthias Ringwald #define NUM_CHANNELS 1 92b150a479SMatthias Ringwald #define SAMPLE_RATE_8KHZ 8000 93b150a479SMatthias Ringwald #define SAMPLE_RATE_16KHZ 16000 94681cb550SMatthias Ringwald #define SAMPLE_RATE_32KHZ 32000 95379c5f5fSMatthias Ringwald #define BYTES_PER_FRAME 2 96f7c85330SMatthias Ringwald 97681cb550SMatthias Ringwald // audio pre-buffer - also defines latency 98b150a479SMatthias Ringwald #define SCO_PREBUFFER_MS 50 99b150a479SMatthias Ringwald #define PREBUFFER_BYTES_8KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_8KHZ/1000 * BYTES_PER_FRAME) 100b150a479SMatthias Ringwald #define PREBUFFER_BYTES_16KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_16KHZ/1000 * BYTES_PER_FRAME) 101681cb550SMatthias Ringwald #define PREBUFFER_BYTES_32KHZ (SCO_PREBUFFER_MS * SAMPLE_RATE_32KHZ/1000 * BYTES_PER_FRAME) 102f7c85330SMatthias Ringwald 103681cb550SMatthias Ringwald #if defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH) 104681cb550SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_32KHZ 105681cb550SMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 240 106681cb550SMatthias Ringwald #elif defined(ENABLE_HFP_WIDE_BAND_SPEECH) 1079582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_16KHZ 108f0d95bdcSMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 120 1099582ae64SMatthias Ringwald #else 1109582ae64SMatthias Ringwald #define PREBUFFER_BYTES_MAX PREBUFFER_BYTES_8KHZ 111f0d95bdcSMatthias Ringwald #define SAMPLES_PER_FRAME_MAX 60 1129582ae64SMatthias Ringwald #endif 1139582ae64SMatthias Ringwald 114bf958e42SMatthias Ringwald static uint16_t audio_prebuffer_bytes; 115bf958e42SMatthias Ringwald 1162b89dbfcSMatthias Ringwald // output 117d861f4bfSMatthias Ringwald static int audio_output_paused = 0; 1189582ae64SMatthias Ringwald static uint8_t audio_output_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX]; 119379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_output_ring_buffer; 1202b89dbfcSMatthias Ringwald 1212b89dbfcSMatthias Ringwald // input 1222b89dbfcSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 123379c5f5fSMatthias Ringwald #define USE_AUDIO_INPUT 1243cf06407SMatthias Ringwald #else 1253cf06407SMatthias Ringwald #define USE_ADUIO_GENERATOR 1263cf06407SMatthias Ringwald static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data); 1276fb1424bSMatthias Ringwald #endif 128681cb550SMatthias Ringwald 129379c5f5fSMatthias Ringwald static int audio_input_paused = 0; 1309582ae64SMatthias Ringwald static uint8_t audio_input_ring_buffer_storage[2 * PREBUFFER_BYTES_MAX]; 131379c5f5fSMatthias Ringwald static btstack_ring_buffer_t audio_input_ring_buffer; 132f7c85330SMatthias Ringwald 1331762039cSMatthias Ringwald // mod player 1341762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER 1351762039cSMatthias Ringwald #include "hxcmod.h" 1361762039cSMatthias Ringwald #include "mods/mod.h" 1371762039cSMatthias Ringwald static modcontext mod_context; 1381762039cSMatthias Ringwald #endif 1391762039cSMatthias Ringwald 140fcb08cdbSMilanka Ringwald static int count_sent = 0; 141fcb08cdbSMilanka Ringwald static int count_received = 0; 142c4e666bcSMatthias Ringwald 143681cb550SMatthias Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state; 144681cb550SMatthias Ringwald 1451bbecc2bSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 1460a4f399aSMatthias Ringwald static btstack_sbc_encoder_state_t msbc_encoder_state; 147*37abe280SMatthias Ringwald static const btstack_sbc_decoder_t * sbc_decoder_instance; 148*37abe280SMatthias Ringwald static btstack_sbc_decoder_bluedroid_t sbc_decoder_context; 1491bbecc2bSMatthias Ringwald #endif 1501bbecc2bSMatthias Ringwald 151681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 152681cb550SMatthias Ringwald static const btstack_lc3_decoder_t * lc3_decoder; 153681cb550SMatthias Ringwald static btstack_lc3_decoder_google_t lc3_decoder_context; 154aeb2ea11SMatthias Ringwald static btstack_lc3_encoder_google_t lc3_encoder_context; 155681cb550SMatthias Ringwald static hfp_h2_sync_t hfp_h2_sync; 156681cb550SMatthias Ringwald #endif 157379c5f5fSMatthias Ringwald 1582b89dbfcSMatthias Ringwald int num_samples_to_write; 1592b89dbfcSMatthias Ringwald int num_audio_frames; 1602b89dbfcSMatthias Ringwald 161bf958e42SMatthias Ringwald // generic codec support 162bf958e42SMatthias Ringwald typedef struct { 163bf958e42SMatthias Ringwald void (*init)(void); 164bf958e42SMatthias Ringwald void(*receive)(const uint8_t * packet, uint16_t size); 165bf958e42SMatthias Ringwald void (*fill_payload)(uint8_t * payload_buffer, uint16_t sco_payload_length); 166bf958e42SMatthias Ringwald void (*close)(void); 16779cc780fSMatthias Ringwald // 16879cc780fSMatthias Ringwald uint16_t sample_rate; 169bf958e42SMatthias Ringwald } codec_support_t; 17079cc780fSMatthias Ringwald 17179cc780fSMatthias Ringwald // current configuration 172bf958e42SMatthias Ringwald static const codec_support_t * codec_current = NULL; 173bf958e42SMatthias Ringwald 174f0d95bdcSMatthias Ringwald // hfp_codec 1757555fa8bSMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH) || defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH) 176f0d95bdcSMatthias Ringwald static hfp_codec_t hfp_codec; 1777555fa8bSMatthias Ringwald #endif 178d6a06398SMatthias Ringwald 1799ad691b0SMatthias Ringwald // Sine Wave 1809ad691b0SMatthias Ringwald 1819ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 1829ad691b0SMatthias Ringwald static uint16_t sine_wave_phase; 1839ad691b0SMatthias Ringwald static uint16_t sine_wave_steps_per_sample; 184681cb550SMatthias Ringwald #define SINE_WAVE_SAMPLE_RATE SAMPLE_RATE_32KHZ 18594381a69SMatthias Ringwald 186681cb550SMatthias Ringwald // input signal: pre-computed int16 sine wave, 32000 Hz at 266 Hz 187681cb550SMatthias Ringwald static const int16_t sine_int16[] = { 188681cb550SMatthias Ringwald 0, 1715, 3425, 5126, 6813, 8481, 10126, 11743, 13328, 14876, 189681cb550SMatthias Ringwald 16383, 17846, 19260, 20621, 21925, 23170, 24351, 25465, 26509, 27481, 190681cb550SMatthias Ringwald 28377, 29196, 29934, 30591, 31163, 31650, 32051, 32364, 32587, 32722, 191681cb550SMatthias Ringwald 32767, 32722, 32587, 32364, 32051, 31650, 31163, 30591, 29934, 29196, 192681cb550SMatthias Ringwald 28377, 27481, 26509, 25465, 24351, 23170, 21925, 20621, 19260, 17846, 193681cb550SMatthias Ringwald 16383, 14876, 13328, 11743, 10126, 8481, 6813, 5126, 3425, 1715, 194681cb550SMatthias Ringwald 0, -1715, -3425, -5126, -6813, -8481, -10126, -11743, -13328, -14876, 195681cb550SMatthias Ringwald -16384, -17846, -19260, -20621, -21925, -23170, -24351, -25465, -26509, -27481, 196681cb550SMatthias Ringwald -28377, -29196, -29934, -30591, -31163, -31650, -32051, -32364, -32587, -32722, 197681cb550SMatthias Ringwald -32767, -32722, -32587, -32364, -32051, -31650, -31163, -30591, -29934, -29196, 198681cb550SMatthias Ringwald -28377, -27481, -26509, -25465, -24351, -23170, -21925, -20621, -19260, -17846, 199681cb550SMatthias Ringwald -16384, -14876, -13328, -11743, -10126, -8481, -6813, -5126, -3425, -1715, 20035fd3fb9SMatthias Ringwald }; 20135fd3fb9SMatthias Ringwald 2029ad691b0SMatthias Ringwald static void sco_demo_sine_wave_host_endian(uint16_t num_samples, int16_t * data){ 203249d94cfSMatthias Ringwald unsigned int i; 20459c97ae1SMatthias Ringwald for (i=0; i < num_samples; i++){ 205681cb550SMatthias Ringwald data[i] = sine_int16[sine_wave_phase]; 2069ad691b0SMatthias Ringwald sine_wave_phase += sine_wave_steps_per_sample; 207681cb550SMatthias Ringwald if (sine_wave_phase >= (sizeof(sine_int16) / sizeof(int16_t))){ 2089ad691b0SMatthias Ringwald sine_wave_phase = 0; 20935fd3fb9SMatthias Ringwald } 21035fd3fb9SMatthias Ringwald } 21135fd3fb9SMatthias Ringwald } 2121bbecc2bSMatthias Ringwald #endif 213dbb41bfeSMilanka Ringwald 2141762039cSMatthias Ringwald // Mod Player 2151762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER 2161762039cSMatthias Ringwald #define NUM_SAMPLES_GENERATOR_BUFFER 30 2171762039cSMatthias Ringwald static void sco_demo_modplayer(uint16_t num_samples, int16_t * data){ 2181762039cSMatthias Ringwald // mix down stereo 2191762039cSMatthias Ringwald signed short samples[NUM_SAMPLES_GENERATOR_BUFFER * 2]; 2201762039cSMatthias Ringwald while (num_samples > 0){ 2211762039cSMatthias Ringwald uint16_t next_samples = btstack_min(num_samples, NUM_SAMPLES_GENERATOR_BUFFER); 2221762039cSMatthias Ringwald hxcmod_fillbuffer(&mod_context, (unsigned short *) samples, next_samples, NULL); 2231762039cSMatthias Ringwald num_samples -= next_samples; 2241762039cSMatthias Ringwald uint16_t i; 2251762039cSMatthias Ringwald for (i=0;i<next_samples;i++){ 2261762039cSMatthias Ringwald int32_t left = samples[2*i + 0]; 2271762039cSMatthias Ringwald int32_t right = samples[2*i + 1]; 2281762039cSMatthias Ringwald data[i] = (int16_t)((left + right) / 2); 2291762039cSMatthias Ringwald } 2301762039cSMatthias Ringwald } 2311762039cSMatthias Ringwald } 2321762039cSMatthias Ringwald #endif 2331762039cSMatthias Ringwald 23494381a69SMatthias Ringwald // Audio Playback / Recording 235d861f4bfSMatthias Ringwald 23694381a69SMatthias Ringwald static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){ 2372b89dbfcSMatthias Ringwald 238c4e666bcSMatthias Ringwald // fill with silence while paused 239379c5f5fSMatthias Ringwald if (audio_output_paused){ 240bf958e42SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < audio_prebuffer_bytes){ 241f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 242379c5f5fSMatthias Ringwald return; 243dbb41bfeSMilanka Ringwald } else { 244c4e666bcSMatthias Ringwald // resume playback 245379c5f5fSMatthias Ringwald audio_output_paused = 0; 246dbb41bfeSMilanka Ringwald } 247c4e666bcSMatthias Ringwald } 248c4e666bcSMatthias Ringwald 249c4e666bcSMatthias Ringwald // get data from ringbuffer 250c4e666bcSMatthias Ringwald uint32_t bytes_read = 0; 251f55ac442SMatthias Ringwald btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 252f55ac442SMatthias Ringwald num_samples -= bytes_read / BYTES_PER_FRAME; 253f55ac442SMatthias Ringwald buffer += bytes_read / BYTES_PER_FRAME; 254c4e666bcSMatthias Ringwald 255c4e666bcSMatthias Ringwald // fill with 0 if not enough 256f55ac442SMatthias Ringwald if (num_samples){ 257f55ac442SMatthias Ringwald memset(buffer, 0, num_samples * BYTES_PER_FRAME); 258379c5f5fSMatthias Ringwald audio_output_paused = 1; 259c4e666bcSMatthias Ringwald } 260379c5f5fSMatthias Ringwald } 2618b29cfc6SMatthias Ringwald 262379c5f5fSMatthias Ringwald #ifdef USE_AUDIO_INPUT 26394381a69SMatthias Ringwald static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){ 264379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2); 265c4e666bcSMatthias Ringwald } 266379c5f5fSMatthias Ringwald #endif 267c4e666bcSMatthias Ringwald 268c4e666bcSMatthias Ringwald // return 1 if ok 269379c5f5fSMatthias Ringwald static int audio_initialize(int sample_rate){ 270c4e666bcSMatthias Ringwald 271d365bb51SMatthias Ringwald // -- output -- // 272d365bb51SMatthias Ringwald 273379c5f5fSMatthias Ringwald // init buffers 274379c5f5fSMatthias Ringwald memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage)); 275379c5f5fSMatthias Ringwald btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage)); 2762b89dbfcSMatthias Ringwald 277d365bb51SMatthias Ringwald // config and setup audio playback 278d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 279e0c8f71bSMatthias Ringwald if (audio_sink != NULL){ 28094381a69SMatthias Ringwald audio_sink->init(1, sample_rate, &audio_playback_callback); 281d365bb51SMatthias Ringwald audio_sink->start_stream(); 282379c5f5fSMatthias Ringwald 283379c5f5fSMatthias Ringwald audio_output_paused = 1; 284e0c8f71bSMatthias Ringwald } 285d365bb51SMatthias Ringwald 286d365bb51SMatthias Ringwald // -- input -- // 287d365bb51SMatthias Ringwald 288d365bb51SMatthias Ringwald // init buffers 289d365bb51SMatthias Ringwald memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage)); 290d365bb51SMatthias Ringwald btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage)); 2916fb1424bSMatthias Ringwald audio_input_paused = 1; 292d365bb51SMatthias Ringwald 2936fb1424bSMatthias Ringwald #ifdef USE_AUDIO_INPUT 294d365bb51SMatthias Ringwald // config and setup audio recording 295d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance(); 296e0c8f71bSMatthias Ringwald if (audio_source != NULL){ 29794381a69SMatthias Ringwald audio_source->init(1, sample_rate, &audio_recording_callback); 298d365bb51SMatthias Ringwald audio_source->start_stream(); 299e0c8f71bSMatthias Ringwald } 3002b89dbfcSMatthias Ringwald #endif 3012b89dbfcSMatthias Ringwald 302c4e666bcSMatthias Ringwald return 1; 303c4e666bcSMatthias Ringwald } 3042b89dbfcSMatthias Ringwald 305379c5f5fSMatthias Ringwald static void audio_terminate(void){ 306d365bb51SMatthias Ringwald const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 307d365bb51SMatthias Ringwald if (!audio_sink) return; 308d365bb51SMatthias Ringwald audio_sink->close(); 309d365bb51SMatthias Ringwald 310d365bb51SMatthias Ringwald #ifdef USE_AUDIO_INPUT 311d365bb51SMatthias Ringwald const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance(); 312d365bb51SMatthias Ringwald if (!audio_source) return; 313d365bb51SMatthias Ringwald audio_source->close(); 314d365bb51SMatthias Ringwald #endif 3152b89dbfcSMatthias Ringwald } 316c4e666bcSMatthias Ringwald 317d861f4bfSMatthias Ringwald 31894381a69SMatthias Ringwald // CVSD - 8 kHz 319fcb08cdbSMilanka Ringwald 320bf958e42SMatthias Ringwald static void sco_demo_cvsd_init(void){ 321c4e666bcSMatthias Ringwald printf("SCO Demo: Init CVSD\n"); 322fbc7c9f2SMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 323fbc7c9f2SMilanka Ringwald } 324fbc7c9f2SMilanka Ringwald 325bf958e42SMatthias Ringwald static void sco_demo_cvsd_receive(const uint8_t * packet, uint16_t size){ 3262c7ae6e1SMatthias Ringwald 3275303ddeeSMatthias Ringwald int16_t audio_frame_out[128]; // 3281f8694ccSMatthias Ringwald 3291f8694ccSMatthias Ringwald if (size > sizeof(audio_frame_out)){ 330bf958e42SMatthias Ringwald printf("sco_demo_cvsd_receive: SCO packet larger than local output buffer - dropping data.\n"); 3311f8694ccSMatthias Ringwald return; 3321f8694ccSMatthias Ringwald } 3332c7ae6e1SMatthias Ringwald 334c4e666bcSMatthias Ringwald const int audio_bytes_read = size - 3; 335379c5f5fSMatthias Ringwald const int num_samples = audio_bytes_read / BYTES_PER_FRAME; 3365303ddeeSMatthias Ringwald 3375303ddeeSMatthias Ringwald // convert into host endian 3385303ddeeSMatthias Ringwald int16_t audio_frame_in[128]; 3395303ddeeSMatthias Ringwald int i; 3405303ddeeSMatthias Ringwald for (i=0;i<num_samples;i++){ 3415303ddeeSMatthias Ringwald audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 3425303ddeeSMatthias Ringwald } 3435303ddeeSMatthias Ringwald 3445f4f94c7SMatthias Ringwald // treat packet as bad frame if controller does not report 'all good' 3455f4f94c7SMatthias Ringwald bool bad_frame = (packet[1] & 0x30) != 0; 3465f4f94c7SMatthias Ringwald 3475f4f94c7SMatthias Ringwald btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out); 3485303ddeeSMatthias Ringwald 3492c7ae6e1SMatthias Ringwald #ifdef SCO_WAV_FILENAME 3502c7ae6e1SMatthias Ringwald // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 3512c7ae6e1SMatthias Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 3522c7ae6e1SMatthias Ringwald wav_writer_write_le_int16(samples_to_write, audio_frame_out); 3532c7ae6e1SMatthias Ringwald num_samples_to_write -= samples_to_write; 3542c7ae6e1SMatthias Ringwald if (num_samples_to_write == 0){ 3552c7ae6e1SMatthias Ringwald wav_writer_close(); 3562c7ae6e1SMatthias Ringwald } 3572c7ae6e1SMatthias Ringwald #endif 3582c7ae6e1SMatthias Ringwald 359379c5f5fSMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 360fcb08cdbSMilanka Ringwald } 361fcb08cdbSMilanka Ringwald 362bf958e42SMatthias Ringwald static void sco_demo_cvsd_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){ 3636fb1424bSMatthias Ringwald uint16_t bytes_to_copy = sco_payload_length; 3646fb1424bSMatthias Ringwald 3652b89dbfcSMatthias Ringwald // get data from ringbuffer 3662b89dbfcSMatthias Ringwald uint16_t pos = 0; 367379c5f5fSMatthias Ringwald if (!audio_input_paused){ 3686fb1424bSMatthias Ringwald uint16_t samples_to_copy = sco_payload_length / 2; 3692b89dbfcSMatthias Ringwald uint32_t bytes_read = 0; 3706fb1424bSMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read); 3718fd6902dSMatthias Ringwald // flip 16 on big endian systems 3728fd6902dSMatthias Ringwald // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 3738fd6902dSMatthias Ringwald if (btstack_is_big_endian()){ 3746fb1424bSMatthias Ringwald uint16_t i; 3756fb1424bSMatthias Ringwald for (i=0;i<samples_to_copy/2;i+=2){ 3766fb1424bSMatthias Ringwald uint8_t tmp = payload_buffer[i*2]; 3776fb1424bSMatthias Ringwald payload_buffer[i*2] = payload_buffer[i*2+1]; 3786fb1424bSMatthias Ringwald payload_buffer[i*2+1] = tmp; 3798fd6902dSMatthias Ringwald } 3808fd6902dSMatthias Ringwald } 3812b89dbfcSMatthias Ringwald bytes_to_copy -= bytes_read; 3822b89dbfcSMatthias Ringwald pos += bytes_read; 3832b89dbfcSMatthias Ringwald } 3842b89dbfcSMatthias Ringwald 3852b89dbfcSMatthias Ringwald // fill with 0 if not enough 3862b89dbfcSMatthias Ringwald if (bytes_to_copy){ 3876fb1424bSMatthias Ringwald memset(payload_buffer + pos, 0, bytes_to_copy); 388379c5f5fSMatthias Ringwald audio_input_paused = 1; 3892b89dbfcSMatthias Ringwald } 3902b89dbfcSMatthias Ringwald } 39194381a69SMatthias Ringwald 392bf958e42SMatthias Ringwald static void sco_demo_cvsd_close(void){ 393bf958e42SMatthias 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); 394bf958e42SMatthias Ringwald } 395bf958e42SMatthias Ringwald 396bf958e42SMatthias Ringwald static const codec_support_t codec_cvsd = { 397bf958e42SMatthias Ringwald .init = &sco_demo_cvsd_init, 398bf958e42SMatthias Ringwald .receive = &sco_demo_cvsd_receive, 399bf958e42SMatthias Ringwald .fill_payload = &sco_demo_cvsd_fill_payload, 40079cc780fSMatthias Ringwald .close = &sco_demo_cvsd_close, 40179cc780fSMatthias Ringwald .sample_rate = SAMPLE_RATE_8KHZ 402bf958e42SMatthias Ringwald }; 403bf958e42SMatthias Ringwald 404681cb550SMatthias Ringwald // encode using hfp_codec 405681cb550SMatthias Ringwald #if defined(ENABLE_HFP_WIDE_BAND_SPEECH) || defined(ENABLE_HFP_SUPER_WIDE_BAND_SPEECH) 406d4872f4eSMatthias Ringwald static void sco_demo_codec_fill_payload(uint8_t * payload_buffer, uint16_t sco_payload_length){ 407681cb550SMatthias Ringwald if (!audio_input_paused){ 408681cb550SMatthias Ringwald int num_samples = hfp_codec_num_audio_samples_per_frame(&hfp_codec); 409681cb550SMatthias Ringwald btstack_assert(num_samples <= SAMPLES_PER_FRAME_MAX); 410681cb550SMatthias Ringwald uint16_t samples_available = btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) / BYTES_PER_FRAME; 411681cb550SMatthias Ringwald if (hfp_codec_can_encode_audio_frame_now(&hfp_codec) && samples_available >= num_samples){ 412681cb550SMatthias Ringwald int16_t sample_buffer[SAMPLES_PER_FRAME_MAX]; 413681cb550SMatthias Ringwald uint32_t bytes_read; 414681cb550SMatthias Ringwald btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 415681cb550SMatthias Ringwald hfp_codec_encode_audio_frame(&hfp_codec, sample_buffer); 416681cb550SMatthias Ringwald num_audio_frames++; 417681cb550SMatthias Ringwald } 418681cb550SMatthias Ringwald } 419681cb550SMatthias Ringwald // get data from encoder, fill with 0 if not enough 420681cb550SMatthias Ringwald if (audio_input_paused || hfp_codec_num_bytes_available(&hfp_codec) < sco_payload_length){ 421681cb550SMatthias Ringwald // just send '0's 422681cb550SMatthias Ringwald memset(payload_buffer, 0, sco_payload_length); 423681cb550SMatthias Ringwald audio_input_paused = 1; 424681cb550SMatthias Ringwald } else { 425681cb550SMatthias Ringwald hfp_codec_read_from_stream(&hfp_codec, payload_buffer, sco_payload_length); 426681cb550SMatthias Ringwald } 427681cb550SMatthias Ringwald } 428681cb550SMatthias Ringwald #endif 429681cb550SMatthias Ringwald 43094381a69SMatthias Ringwald // mSBC - 16 kHz 43194381a69SMatthias Ringwald 43294381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 43394381a69SMatthias Ringwald 43494381a69SMatthias Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 43594381a69SMatthias Ringwald UNUSED(context); 43694381a69SMatthias Ringwald UNUSED(sample_rate); 43794381a69SMatthias Ringwald UNUSED(data); 43894381a69SMatthias Ringwald UNUSED(num_samples); 43994381a69SMatthias Ringwald UNUSED(num_channels); 44094381a69SMatthias Ringwald 44194381a69SMatthias Ringwald // samples in callback in host endianess, ready for playback 44294381a69SMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 44394381a69SMatthias Ringwald 44494381a69SMatthias Ringwald #ifdef SCO_WAV_FILENAME 44594381a69SMatthias Ringwald if (!num_samples_to_write) return; 44694381a69SMatthias Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 44794381a69SMatthias Ringwald num_samples_to_write -= num_samples; 44894381a69SMatthias Ringwald wav_writer_write_int16(num_samples, data); 44994381a69SMatthias Ringwald if (num_samples_to_write == 0){ 45094381a69SMatthias Ringwald wav_writer_close(); 451f7c85330SMatthias Ringwald } 45294381a69SMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 4531a919128SMatthias Ringwald } 45494381a69SMatthias Ringwald 455bf958e42SMatthias Ringwald static void sco_demo_msbc_init(void){ 45694381a69SMatthias Ringwald printf("SCO Demo: Init mSBC\n"); 457*37abe280SMatthias Ringwald sbc_decoder_instance = btstack_sbc_decoder_bluedroid_init_instance(&sbc_decoder_context); 458*37abe280SMatthias Ringwald sbc_decoder_instance->configure(&sbc_decoder_context, SBC_MODE_mSBC, &handle_pcm_data, NULL); 4590a4f399aSMatthias Ringwald hfp_codec_init_msbc(&hfp_codec, &msbc_encoder_state); 46094381a69SMatthias Ringwald } 46194381a69SMatthias Ringwald 462bf958e42SMatthias Ringwald static void sco_demo_msbc_receive(const uint8_t * packet, uint16_t size){ 463*37abe280SMatthias Ringwald sbc_decoder_instance->decode_signed_16(&sbc_decoder_context, (packet[1] >> 4) & 3, packet + 3, size - 3); 46494381a69SMatthias Ringwald } 46594381a69SMatthias Ringwald 466bf958e42SMatthias Ringwald static void sco_demo_msbc_close(void){ 467*37abe280SMatthias Ringwald printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.\n", sbc_decoder_context.good_frames_nr, sbc_decoder_context.zero_frames_nr, sbc_decoder_context.bad_frames_nr); 468bf958e42SMatthias Ringwald } 469bf958e42SMatthias Ringwald 470bf958e42SMatthias Ringwald static const codec_support_t codec_msbc = { 471bf958e42SMatthias Ringwald .init = &sco_demo_msbc_init, 472bf958e42SMatthias Ringwald .receive = &sco_demo_msbc_receive, 473681cb550SMatthias Ringwald .fill_payload = &sco_demo_codec_fill_payload, 47479cc780fSMatthias Ringwald .close = &sco_demo_msbc_close, 47579cc780fSMatthias Ringwald .sample_rate = SAMPLE_RATE_16KHZ 476bf958e42SMatthias Ringwald }; 477bf958e42SMatthias Ringwald 47894381a69SMatthias Ringwald #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 47994381a69SMatthias Ringwald 480681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 481681cb550SMatthias Ringwald 482681cb550SMatthias Ringwald #define LC3_SWB_SAMPLES_PER_FRAME 240 483681cb550SMatthias Ringwald #define LC3_SWB_OCTETS_PER_FRAME 58 484681cb550SMatthias Ringwald 485681cb550SMatthias Ringwald static bool sco_demo_lc3swb_frame_callback(bool bad_frame, const uint8_t * frame_data, uint16_t frame_len){ 486681cb550SMatthias Ringwald 487681cb550SMatthias Ringwald // skip H2 header for good frames 488681cb550SMatthias Ringwald if (bad_frame == false){ 489681cb550SMatthias Ringwald btstack_assert(frame_data != NULL); 490681cb550SMatthias Ringwald frame_data += 2; 491681cb550SMatthias Ringwald } 492681cb550SMatthias Ringwald 493681cb550SMatthias Ringwald uint8_t tmp_BEC_detect = 0; 494681cb550SMatthias Ringwald uint8_t BFI = bad_frame ? 1 : 0; 495681cb550SMatthias Ringwald int16_t samples[LC3_SWB_SAMPLES_PER_FRAME]; 496681cb550SMatthias Ringwald (void) lc3_decoder->decode_signed_16(&lc3_decoder_context, frame_data, BFI, 497681cb550SMatthias Ringwald samples, 1, &tmp_BEC_detect); 498681cb550SMatthias Ringwald 499681cb550SMatthias Ringwald // samples in callback in host endianess, ready for playback 500681cb550SMatthias Ringwald btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)samples, LC3_SWB_SAMPLES_PER_FRAME*2); 501681cb550SMatthias Ringwald 502681cb550SMatthias Ringwald #ifdef SCO_WAV_FILENAME 503681cb550SMatthias Ringwald if (num_samples_to_write > 0){ 504681cb550SMatthias Ringwald uint16_t num_samples = btstack_min(LC3_SWB_SAMPLES_PER_FRAME, num_samples_to_write); 505681cb550SMatthias Ringwald num_samples_to_write -= num_samples; 506681cb550SMatthias Ringwald wav_writer_write_int16(num_samples, samples); 507681cb550SMatthias Ringwald if (num_samples_to_write == 0){ 508681cb550SMatthias Ringwald wav_writer_close(); 509681cb550SMatthias Ringwald } 510681cb550SMatthias Ringwald } 511681cb550SMatthias Ringwald #endif /* SCO_WAV_FILENAME */ 512681cb550SMatthias Ringwald 513681cb550SMatthias Ringwald // frame is good, if it isn't a bad frame and we didn't detect other errors 514681cb550SMatthias Ringwald return (bad_frame == false) && (tmp_BEC_detect == 0); 515681cb550SMatthias Ringwald } 516681cb550SMatthias Ringwald 517681cb550SMatthias Ringwald static void sco_demo_lc3swb_init(void){ 518681cb550SMatthias Ringwald 519681cb550SMatthias Ringwald printf("SCO Demo: Init LC3-SWB\n"); 520681cb550SMatthias Ringwald 5213b7e9cecSMatthias Ringwald hfp_codec.lc3_encoder_context = &lc3_encoder_context; 522aeb2ea11SMatthias Ringwald const btstack_lc3_encoder_t * lc3_encoder = btstack_lc3_encoder_google_init_instance((btstack_lc3_encoder_google_t *) hfp_codec.lc3_encoder_context); 523aeb2ea11SMatthias Ringwald hfp_codec_init_lc3_swb(&hfp_codec, lc3_encoder, &lc3_encoder_context); 524681cb550SMatthias Ringwald 525681cb550SMatthias Ringwald // init lc3 decoder 526681cb550SMatthias Ringwald lc3_decoder = btstack_lc3_decoder_google_init_instance(&lc3_decoder_context); 527681cb550SMatthias Ringwald lc3_decoder->configure(&lc3_decoder_context, SAMPLE_RATE_32KHZ, BTSTACK_LC3_FRAME_DURATION_7500US, LC3_SWB_OCTETS_PER_FRAME); 528681cb550SMatthias Ringwald 529681cb550SMatthias Ringwald // init HPF H2 framing 530681cb550SMatthias Ringwald hfp_h2_sync_init(&hfp_h2_sync, &sco_demo_lc3swb_frame_callback); 531681cb550SMatthias Ringwald } 532681cb550SMatthias Ringwald 533681cb550SMatthias Ringwald static void sco_demo_lc3swb_receive(const uint8_t * packet, uint16_t size){ 534681cb550SMatthias Ringwald uint8_t packet_status = (packet[1] >> 4) & 3; 535681cb550SMatthias Ringwald bool bad_frame = packet_status != 0; 536681cb550SMatthias Ringwald hfp_h2_sync_process(&hfp_h2_sync, bad_frame, &packet[3], size-3); 537681cb550SMatthias Ringwald } 538681cb550SMatthias Ringwald 539681cb550SMatthias Ringwald static void sco_demo_lc3swb_close(void){ 540681cb550SMatthias Ringwald // TODO: report 541681cb550SMatthias Ringwald } 542681cb550SMatthias Ringwald 543681cb550SMatthias Ringwald static const codec_support_t codec_lc3swb = { 544681cb550SMatthias Ringwald .init = &sco_demo_lc3swb_init, 545681cb550SMatthias Ringwald .receive = &sco_demo_lc3swb_receive, 546681cb550SMatthias Ringwald .fill_payload = &sco_demo_codec_fill_payload, 547681cb550SMatthias Ringwald .close = &sco_demo_lc3swb_close, 548681cb550SMatthias Ringwald .sample_rate = SAMPLE_RATE_32KHZ 549681cb550SMatthias Ringwald }; 550681cb550SMatthias Ringwald #endif 551681cb550SMatthias Ringwald 55294381a69SMatthias Ringwald void sco_demo_init(void){ 55394381a69SMatthias Ringwald 55494381a69SMatthias Ringwald #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS 55594381a69SMatthias Ringwald printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n"); 55694381a69SMatthias Ringwald gap_secure_connections_enable(false); 55794381a69SMatthias Ringwald #endif 55894381a69SMatthias Ringwald 559681cb550SMatthias Ringwald // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode) 560681cb550SMatthias Ringwald hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 561681cb550SMatthias Ringwald 56294381a69SMatthias Ringwald // status 56394381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 56494381a69SMatthias Ringwald printf("SCO Demo: Sending and receiving audio via btstack_audio.\n"); 56594381a69SMatthias Ringwald #endif 56694381a69SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 56794381a69SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n"); 56894381a69SMatthias Ringwald #endif 5691762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER 570681cb550SMatthias Ringwald printf("SCO Demo: Sending modplayer wave, audio output via btstack_audio.\n"); 5711762039cSMatthias Ringwald // init mod 5721762039cSMatthias Ringwald int hxcmod_initialized = hxcmod_init(&mod_context); 5731762039cSMatthias Ringwald btstack_assert(hxcmod_initialized != 0); 5741762039cSMatthias Ringwald #endif 57594381a69SMatthias Ringwald } 57694381a69SMatthias Ringwald 577bf958e42SMatthias Ringwald void sco_demo_set_codec(uint8_t negotiated_codec){ 57894381a69SMatthias Ringwald switch (negotiated_codec){ 57994381a69SMatthias Ringwald case HFP_CODEC_CVSD: 580bf958e42SMatthias Ringwald codec_current = &codec_cvsd; 58194381a69SMatthias Ringwald break; 58294381a69SMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 58394381a69SMatthias Ringwald case HFP_CODEC_MSBC: 584bf958e42SMatthias Ringwald codec_current = &codec_msbc; 58594381a69SMatthias Ringwald break; 58694381a69SMatthias Ringwald #endif 587681cb550SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 588681cb550SMatthias Ringwald case HFP_CODEC_LC3_SWB: 589681cb550SMatthias Ringwald codec_current = &codec_lc3swb; 590681cb550SMatthias Ringwald break; 591681cb550SMatthias Ringwald #endif 59294381a69SMatthias Ringwald default: 59394381a69SMatthias Ringwald btstack_assert(false); 59494381a69SMatthias Ringwald break; 59594381a69SMatthias Ringwald } 596bf958e42SMatthias Ringwald 597bf958e42SMatthias Ringwald codec_current->init(); 5989ad691b0SMatthias Ringwald 5999ad691b0SMatthias Ringwald audio_initialize(codec_current->sample_rate); 6009ad691b0SMatthias Ringwald 6019ad691b0SMatthias Ringwald audio_prebuffer_bytes = SCO_PREBUFFER_MS * (codec_current->sample_rate/1000) * BYTES_PER_FRAME; 6029ad691b0SMatthias Ringwald 6039ad691b0SMatthias Ringwald #ifdef SCO_WAV_FILENAME 6049ad691b0SMatthias Ringwald num_samples_to_write = codec_current->sample_rate * SCO_WAV_DURATION_IN_SECONDS; 6059ad691b0SMatthias Ringwald wav_writer_open(SCO_WAV_FILENAME, 1, codec_current->sample_rate); 6069ad691b0SMatthias Ringwald #endif 6079ad691b0SMatthias Ringwald 6089ad691b0SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 6099ad691b0SMatthias Ringwald sine_wave_steps_per_sample = SINE_WAVE_SAMPLE_RATE / codec_current->sample_rate; 6109ad691b0SMatthias Ringwald sco_demo_audio_generator = &sco_demo_sine_wave_host_endian; 6119ad691b0SMatthias Ringwald #endif 6121762039cSMatthias Ringwald 6131762039cSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_MODPLAYER 6141762039cSMatthias Ringwald // load mod 6151762039cSMatthias Ringwald hxcmod_setcfg(&mod_context, codec_current->sample_rate, 16, 1, 1, 1); 6161762039cSMatthias Ringwald hxcmod_load(&mod_context, (void *) &mod_data, mod_len); 6171762039cSMatthias Ringwald sco_demo_audio_generator = &sco_demo_modplayer; 6181762039cSMatthias Ringwald #endif 61994381a69SMatthias Ringwald } 62094381a69SMatthias Ringwald 62194381a69SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 62294381a69SMatthias Ringwald static uint32_t packets = 0; 62394381a69SMatthias Ringwald static uint32_t crc_errors = 0; 62494381a69SMatthias Ringwald static uint32_t data_received = 0; 62594381a69SMatthias Ringwald static uint32_t byte_errors = 0; 62694381a69SMatthias Ringwald 62794381a69SMatthias Ringwald count_received++; 62894381a69SMatthias Ringwald 62994381a69SMatthias Ringwald data_received += size - 3; 63094381a69SMatthias Ringwald packets++; 63194381a69SMatthias Ringwald if (data_received > 100000){ 63294381a69SMatthias 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); 63394381a69SMatthias Ringwald crc_errors = 0; 63494381a69SMatthias Ringwald byte_errors = 0; 63594381a69SMatthias Ringwald data_received = 0; 63694381a69SMatthias Ringwald packets = 0; 63794381a69SMatthias Ringwald } 63894381a69SMatthias Ringwald 639bf958e42SMatthias Ringwald codec_current->receive(packet, size); 64094381a69SMatthias Ringwald } 64194381a69SMatthias Ringwald 64294381a69SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 64394381a69SMatthias Ringwald 64494381a69SMatthias Ringwald if (sco_handle == HCI_CON_HANDLE_INVALID) return; 64594381a69SMatthias Ringwald 646b8543c7aSMatthias Ringwald int sco_packet_length = hci_get_sco_packet_length_for_connection(sco_handle); 64794381a69SMatthias Ringwald int sco_payload_length = sco_packet_length - 3; 64894381a69SMatthias Ringwald 64994381a69SMatthias Ringwald hci_reserve_packet_buffer(); 65094381a69SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 65194381a69SMatthias Ringwald 652bf958e42SMatthias Ringwald #ifdef USE_ADUIO_GENERATOR 653bf958e42SMatthias Ringwald #define REFILL_SAMPLES 16 654bf958e42SMatthias Ringwald // re-fill audio buffer 655bf958e42SMatthias Ringwald uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2; 656bf958e42SMatthias Ringwald while (samples_free > 0){ 657bf958e42SMatthias Ringwald int16_t samples_buffer[REFILL_SAMPLES]; 658bf958e42SMatthias Ringwald uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES); 659bf958e42SMatthias Ringwald (*sco_demo_audio_generator)(samples_to_add, samples_buffer); 660bf958e42SMatthias Ringwald btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2); 661bf958e42SMatthias Ringwald samples_free -= samples_to_add; 66294381a69SMatthias Ringwald } 663bf958e42SMatthias Ringwald #endif 664bf958e42SMatthias Ringwald 665bf958e42SMatthias Ringwald // resume if pre-buffer is filled 666bf958e42SMatthias Ringwald if (audio_input_paused){ 667bf958e42SMatthias Ringwald if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= audio_prebuffer_bytes){ 668bf958e42SMatthias Ringwald // resume sending 669bf958e42SMatthias Ringwald audio_input_paused = 0; 670bf958e42SMatthias Ringwald } 671bf958e42SMatthias Ringwald } 672bf958e42SMatthias Ringwald 673bf958e42SMatthias Ringwald // fill payload by codec 674bf958e42SMatthias Ringwald codec_current->fill_payload(&sco_packet[3], sco_payload_length); 6752b89dbfcSMatthias Ringwald 676c4e666bcSMatthias Ringwald // set handle + flags 677c4e666bcSMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 678c4e666bcSMatthias Ringwald // set len 679c4e666bcSMatthias Ringwald sco_packet[2] = sco_payload_length; 680c4e666bcSMatthias Ringwald // finally send packet 681f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 682f7c85330SMatthias Ringwald 683f7c85330SMatthias Ringwald // request another send event 684f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 685f7c85330SMatthias Ringwald 6864a96141eSMatthias Ringwald count_sent++; 68794381a69SMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) { 68894381a69SMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 68994381a69SMatthias Ringwald } 690f7c85330SMatthias Ringwald } 691f7c85330SMatthias Ringwald 69294381a69SMatthias Ringwald void sco_demo_close(void){ 69394381a69SMatthias Ringwald printf("SCO demo close\n"); 6941a919128SMatthias Ringwald 69594381a69SMatthias Ringwald printf("SCO demo statistics: "); 696bf958e42SMatthias Ringwald codec_current->close(); 697bf958e42SMatthias Ringwald codec_current = NULL; 69894381a69SMatthias Ringwald 69994381a69SMatthias Ringwald #if defined(SCO_WAV_FILENAME) 70094381a69SMatthias Ringwald wav_writer_close(); 7018b29cfc6SMatthias Ringwald #endif 7028b29cfc6SMatthias Ringwald 70394381a69SMatthias Ringwald audio_terminate(); 704f7c85330SMatthias Ringwald } 705