1f7c85330SMatthias Ringwald /* 2f7c85330SMatthias Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3f7c85330SMatthias Ringwald * 4f7c85330SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5f7c85330SMatthias Ringwald * modification, are permitted provided that the following conditions 6f7c85330SMatthias Ringwald * are met: 7f7c85330SMatthias Ringwald * 8f7c85330SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9f7c85330SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10f7c85330SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11f7c85330SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12f7c85330SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13f7c85330SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14f7c85330SMatthias Ringwald * contributors may be used to endorse or promote products derived 15f7c85330SMatthias Ringwald * from this software without specific prior written permission. 16f7c85330SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17f7c85330SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18f7c85330SMatthias Ringwald * monetary gain. 19f7c85330SMatthias Ringwald * 20f7c85330SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21f7c85330SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22f7c85330SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23f7c85330SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24f7c85330SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25f7c85330SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26f7c85330SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27f7c85330SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28f7c85330SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29f7c85330SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30f7c85330SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31f7c85330SMatthias Ringwald * SUCH DAMAGE. 32f7c85330SMatthias Ringwald * 33f7c85330SMatthias Ringwald * Please inquire about commercial licensing options at 34f7c85330SMatthias Ringwald * [email protected] 35f7c85330SMatthias Ringwald * 36f7c85330SMatthias Ringwald */ 37f7c85330SMatthias Ringwald 38f7c85330SMatthias Ringwald /* 39f7c85330SMatthias Ringwald * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo 40f7c85330SMatthias Ringwald */ 41f7c85330SMatthias Ringwald 422ec72fbbSMilanka Ringwald 432ec72fbbSMilanka Ringwald #include <stdio.h> 442ec72fbbSMilanka Ringwald 45f7c85330SMatthias Ringwald #include "sco_demo_util.h" 46fcb08cdbSMilanka Ringwald #include "btstack_debug.h" 470c87db9eSMilanka Ringwald #include "btstack_sbc.h" 48*379d044eSMilanka Ringwald #include "btstack_cvsd_plc.h" 49220eb563SMilanka Ringwald #include "hfp_msbc.h" 50220eb563SMilanka Ringwald #include "hfp.h" 51fcb08cdbSMilanka Ringwald 52f7c85330SMatthias Ringwald // configure test mode 53f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE 0 54f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII 1 55f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER 2 56f7c85330SMatthias Ringwald 578b29cfc6SMatthias Ringwald 58f7c85330SMatthias Ringwald // SCO demo configuration 59fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE 60f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 61f7c85330SMatthias Ringwald 628b29cfc6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 638b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 64d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 65d5e5f834SMatthias Ringwald #define SCO_MSBC_IN_FILENAME "sco_input.mscb" 66220eb563SMilanka Ringwald 678b29cfc6SMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 30 688b29cfc6SMatthias Ringwald #endif 698b29cfc6SMatthias Ringwald 70f7c85330SMatthias Ringwald 71f7c85330SMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) 72f7c85330SMatthias Ringwald #define USE_PORTAUDIO 73f7c85330SMatthias Ringwald #endif 74f7c85330SMatthias Ringwald 75f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 76f7c85330SMatthias Ringwald #include <portaudio.h> 778b29cfc6SMatthias Ringwald // portaudio config 788b29cfc6SMatthias Ringwald #define NUM_CHANNELS 1 798b29cfc6SMatthias Ringwald #define SAMPLE_RATE 8000 808b29cfc6SMatthias Ringwald #define FRAMES_PER_BUFFER 24 818b29cfc6SMatthias Ringwald #define PA_SAMPLE_TYPE paInt8 82f7c85330SMatthias Ringwald // portaudio globals 83f7c85330SMatthias Ringwald static PaStream * stream; 84f7c85330SMatthias Ringwald #endif 85f7c85330SMatthias Ringwald 86fcb08cdbSMilanka Ringwald typedef struct wav_writer_state { 87fcb08cdbSMilanka Ringwald FILE * wav_file; 88fcb08cdbSMilanka Ringwald int total_num_samples; 89fcb08cdbSMilanka Ringwald int frame_count; 90fcb08cdbSMilanka Ringwald } wav_writer_state_t; 91fcb08cdbSMilanka Ringwald 92fcb08cdbSMilanka Ringwald static int dump_data = 1; 93fcb08cdbSMilanka Ringwald 94220eb563SMilanka Ringwald static int phase = 0; 95fcb08cdbSMilanka Ringwald static int count_sent = 0; 96fcb08cdbSMilanka Ringwald static int count_received = 0; 97d76591efSMatthias Ringwald static uint8_t negotiated_codec = 0; 98220eb563SMilanka Ringwald static int num_audio_frames = 0; 99fcb08cdbSMilanka Ringwald 100d5e5f834SMatthias Ringwald FILE * msbc_file_in; 101d5e5f834SMatthias Ringwald FILE * msbc_file_out; 1027294d009SMatthias Ringwald 103f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 104d6a06398SMatthias Ringwald 105d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 8 kHz 106f7c85330SMatthias Ringwald static const uint8_t sine[] = { 107f7c85330SMatthias Ringwald 0, 15, 31, 46, 61, 74, 86, 97, 107, 114, 108f7c85330SMatthias Ringwald 120, 124, 126, 126, 124, 120, 114, 107, 97, 86, 109f7c85330SMatthias Ringwald 74, 61, 46, 31, 15, 0, 241, 225, 210, 195, 110f7c85330SMatthias Ringwald 182, 170, 159, 149, 142, 136, 132, 130, 130, 132, 111f7c85330SMatthias Ringwald 136, 142, 149, 159, 170, 182, 195, 210, 225, 241, 112f7c85330SMatthias Ringwald }; 113f7c85330SMatthias Ringwald 114d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz 115d6a06398SMatthias Ringwald static const int16_t sine_int16[] = { 116d6a06398SMatthias Ringwald 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 117d6a06398SMatthias Ringwald 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 118d6a06398SMatthias Ringwald 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 119d6a06398SMatthias Ringwald 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 120d6a06398SMatthias Ringwald 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 121d6a06398SMatthias Ringwald 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 122d6a06398SMatthias Ringwald -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 123d6a06398SMatthias Ringwald -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 124d6a06398SMatthias Ringwald -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 125d6a06398SMatthias Ringwald -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 126d6a06398SMatthias Ringwald }; 127f7c85330SMatthias Ringwald 1288b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME 1298b29cfc6SMatthias Ringwald 1308b29cfc6SMatthias Ringwald static int num_samples_to_write; 131fcb08cdbSMilanka Ringwald static wav_writer_state_t wav_writer_state; 1328b29cfc6SMatthias Ringwald 1332afeea7fSMilanka Ringwald static btstack_sbc_decoder_state_t decoder_state; 134*379d044eSMilanka Ringwald static btstack_cvsd_plc_t sbc_plc_state; 1358b29cfc6SMatthias Ringwald 1368b29cfc6SMatthias Ringwald static void little_endian_fstore_16(FILE * file, uint16_t value){ 1378b29cfc6SMatthias Ringwald uint8_t buf[2]; 1388b29cfc6SMatthias Ringwald little_endian_store_32(buf, 0, value); 1398b29cfc6SMatthias Ringwald fwrite(&buf, 1, 2, file); 1408b29cfc6SMatthias Ringwald } 1418b29cfc6SMatthias Ringwald 1428b29cfc6SMatthias Ringwald static void little_endian_fstore_32(FILE * file, uint32_t value){ 1438b29cfc6SMatthias Ringwald uint8_t buf[4]; 1448b29cfc6SMatthias Ringwald little_endian_store_32(buf, 0, value); 1458b29cfc6SMatthias Ringwald fwrite(&buf, 1, 4, file); 1468b29cfc6SMatthias Ringwald } 1478b29cfc6SMatthias Ringwald 1488b29cfc6SMatthias Ringwald static FILE * wav_init(const char * filename){ 149fcb08cdbSMilanka Ringwald FILE * f = fopen(filename, "wb"); 150fcb08cdbSMilanka Ringwald printf("SCO Demo: creating wav file %s, %p\n", filename, f); 151fcb08cdbSMilanka Ringwald return f; 1528b29cfc6SMatthias Ringwald } 1538b29cfc6SMatthias Ringwald 1548b29cfc6SMatthias Ringwald static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){ 1558b29cfc6SMatthias Ringwald /* write RIFF header */ 1568b29cfc6SMatthias Ringwald fwrite("RIFF", 1, 4, file); 1578b29cfc6SMatthias Ringwald // num_samples = blocks * subbands 1588b29cfc6SMatthias Ringwald uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels); 1598b29cfc6SMatthias Ringwald little_endian_fstore_32(file, data_bytes + 36); 1608b29cfc6SMatthias Ringwald fwrite("WAVE", 1, 4, file); 1618b29cfc6SMatthias Ringwald 1628b29cfc6SMatthias Ringwald int byte_rate = sample_rate * num_channels * bytes_per_sample; 1638b29cfc6SMatthias Ringwald int bits_per_sample = 8 * bytes_per_sample; 1648b29cfc6SMatthias Ringwald int block_align = num_channels * bits_per_sample; 1658b29cfc6SMatthias Ringwald int fmt_length = 16; 1668b29cfc6SMatthias Ringwald int fmt_format_tag = 1; // PCM 1678b29cfc6SMatthias Ringwald 1688b29cfc6SMatthias Ringwald /* write fmt chunk */ 1698b29cfc6SMatthias Ringwald fwrite("fmt ", 1, 4, file); 1708b29cfc6SMatthias Ringwald little_endian_fstore_32(file, fmt_length); 1718b29cfc6SMatthias Ringwald little_endian_fstore_16(file, fmt_format_tag); 1728b29cfc6SMatthias Ringwald little_endian_fstore_16(file, num_channels); 1738b29cfc6SMatthias Ringwald little_endian_fstore_32(file, sample_rate); 1748b29cfc6SMatthias Ringwald little_endian_fstore_32(file, byte_rate); 1758b29cfc6SMatthias Ringwald little_endian_fstore_16(file, block_align); 1768b29cfc6SMatthias Ringwald little_endian_fstore_16(file, bits_per_sample); 1778b29cfc6SMatthias Ringwald 1788b29cfc6SMatthias Ringwald /* write data chunk */ 1798b29cfc6SMatthias Ringwald fwrite("data", 1, 4, file); 1808b29cfc6SMatthias Ringwald little_endian_fstore_32(file, data_bytes); 1818b29cfc6SMatthias Ringwald } 1828b29cfc6SMatthias Ringwald 1838b29cfc6SMatthias Ringwald static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){ 1848b29cfc6SMatthias Ringwald fwrite(data, num_samples, 1, file); 1858b29cfc6SMatthias Ringwald } 1868b29cfc6SMatthias Ringwald 187fcb08cdbSMilanka Ringwald static void write_wav_data_int16(FILE * file, int num_samples, int16_t * data){ 188fcb08cdbSMilanka Ringwald fwrite(data, num_samples, 2, file); 189fcb08cdbSMilanka Ringwald } 190fcb08cdbSMilanka Ringwald 191fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 192fcb08cdbSMilanka Ringwald log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write); 193fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 194fcb08cdbSMilanka Ringwald 195fcb08cdbSMilanka Ringwald wav_writer_state_t * writer_state = (wav_writer_state_t*) context; 196fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 197fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 198fcb08cdbSMilanka Ringwald 199fcb08cdbSMilanka Ringwald write_wav_data_int16(writer_state->wav_file, num_samples, data); 200fcb08cdbSMilanka Ringwald writer_state->total_num_samples+=num_samples; 201fcb08cdbSMilanka Ringwald writer_state->frame_count++; 202fcb08cdbSMilanka Ringwald 203fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 204fcb08cdbSMilanka Ringwald sco_demo_close(); 205fcb08cdbSMilanka Ringwald } 206fcb08cdbSMilanka Ringwald } 207fcb08cdbSMilanka Ringwald 208220eb563SMilanka Ringwald static void sco_demo_fill_audio_frame(void){ 209220eb563SMilanka Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 210d6a06398SMatthias Ringwald int i; 211d6a06398SMatthias Ringwald int16_t sample_buffer[8*16*2]; 212d6a06398SMatthias Ringwald for (i=0; i < hfp_msbc_num_audio_samples_per_frame(); i++){ 213d6a06398SMatthias Ringwald sample_buffer[i] = sine_int16[phase++]; 214d6a06398SMatthias Ringwald if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){ 215d6a06398SMatthias Ringwald phase = 0; 216d6a06398SMatthias Ringwald } 217d6a06398SMatthias Ringwald } 218d6a06398SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 219220eb563SMilanka Ringwald num_audio_frames++; 220220eb563SMilanka Ringwald } 221fcb08cdbSMilanka Ringwald 222fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 223fcb08cdbSMilanka Ringwald wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME); 224fcb08cdbSMilanka Ringwald wav_writer_state.frame_count = 0; 225fcb08cdbSMilanka Ringwald wav_writer_state.total_num_samples = 0; 226fcb08cdbSMilanka Ringwald 2272afeea7fSMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, (void*)&wav_writer_state); 228fcb08cdbSMilanka Ringwald 229fcb08cdbSMilanka Ringwald const int sample_rate = 16000; 230fcb08cdbSMilanka Ringwald const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 231fcb08cdbSMilanka Ringwald const int bytes_per_sample = 2; 232fcb08cdbSMilanka Ringwald const int num_channels = 1; 233fcb08cdbSMilanka Ringwald num_samples_to_write = num_samples; 234fcb08cdbSMilanka Ringwald 235fcb08cdbSMilanka Ringwald write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample); 236220eb563SMilanka Ringwald 237220eb563SMilanka Ringwald hfp_msbc_init(); 238220eb563SMilanka Ringwald sco_demo_fill_audio_frame(); 239973d7173SMatthias Ringwald 240d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME 241d5e5f834SMatthias Ringwald msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 242d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 243d5e5f834SMatthias Ringwald #endif 2447294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 245d5e5f834SMatthias Ringwald msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 246d5e5f834SMatthias Ringwald printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 2477294d009SMatthias Ringwald #endif 248fcb08cdbSMilanka Ringwald } 249fcb08cdbSMilanka Ringwald 250fcb08cdbSMilanka Ringwald static void sco_demo_init_CVSD(void){ 251*379d044eSMilanka Ringwald btstack_cvsd_plc_init(&cvsd_plc_state); 252fcb08cdbSMilanka Ringwald wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME); 253fcb08cdbSMilanka Ringwald wav_writer_state.frame_count = 0; 254fcb08cdbSMilanka Ringwald wav_writer_state.total_num_samples = 0; 255fcb08cdbSMilanka Ringwald 256fcb08cdbSMilanka Ringwald const int sample_rate = 8000; 257fcb08cdbSMilanka Ringwald const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 258fcb08cdbSMilanka Ringwald const int num_channels = 1; 259fcb08cdbSMilanka Ringwald const int bytes_per_sample = 1; 260fcb08cdbSMilanka Ringwald num_samples_to_write = num_samples; 261fcb08cdbSMilanka Ringwald write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample); 262fcb08cdbSMilanka Ringwald } 263fcb08cdbSMilanka Ringwald 264fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 265fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 266d5e5f834SMatthias Ringwald if (msbc_file_in){ 267d5e5f834SMatthias Ringwald // log incoming mSBC data for testing 268d5e5f834SMatthias Ringwald fwrite(packet+3, size-3, 1, msbc_file_in); 269d5e5f834SMatthias Ringwald } 2702afeea7fSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 271fcb08cdbSMilanka Ringwald dump_data = 0; 272fcb08cdbSMilanka Ringwald } 273fcb08cdbSMilanka Ringwald } 274fcb08cdbSMilanka Ringwald 275*379d044eSMilanka Ringwald static int8_t audio_frame_out[24]; 276*379d044eSMilanka Ringwald 277*379d044eSMilanka Ringwald static int count_equal_bytes(uint8_t * packet, uint16_t size){ 278*379d044eSMilanka Ringwald int count = 0; 279*379d044eSMilanka Ringwald int temp_count = 1; 280*379d044eSMilanka Ringwald int i; 281*379d044eSMilanka Ringwald for (i = 0; i < size-1; i++){ 282*379d044eSMilanka Ringwald if (packet[i] == packet[i+1]){ 283*379d044eSMilanka Ringwald temp_count++; 284*379d044eSMilanka Ringwald continue; 285*379d044eSMilanka Ringwald } 286*379d044eSMilanka Ringwald if (count < temp_count){ 287*379d044eSMilanka Ringwald count = temp_count; 288*379d044eSMilanka Ringwald } 289*379d044eSMilanka Ringwald temp_count = 1; 290*379d044eSMilanka Ringwald } 291*379d044eSMilanka Ringwald if (temp_count > count + 1){ 292*379d044eSMilanka Ringwald count = temp_count; 293*379d044eSMilanka Ringwald } 294*379d044eSMilanka Ringwald return count; 295*379d044eSMilanka Ringwald } 296*379d044eSMilanka Ringwald 297*379d044eSMilanka Ringwald static void btstack_cvsd_handle_audio_frame(uint8_t * packet, uint16_t size){ 298*379d044eSMilanka Ringwald if (count_equal_bytes(packet, size) > size/2){ 299*379d044eSMilanka Ringwald btstack_cvsd_plc_bad_frame(&cvsd_plc_state, audio_frame_out); 300*379d044eSMilanka Ringwald } else { 301*379d044eSMilanka Ringwald btstack_cvsd_plc_good_frame(&cvsd_plc_state, packet, audio_frame_out); 302*379d044eSMilanka Ringwald } 303*379d044eSMilanka Ringwald } 304*379d044eSMilanka Ringwald 305fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 306fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 307fcb08cdbSMilanka Ringwald const int num_samples = size - 3; 308fcb08cdbSMilanka Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 309*379d044eSMilanka Ringwald 310*379d044eSMilanka Ringwald btstack_cvsd_handle_audio_frame(packet+3,num_samples); 311*379d044eSMilanka Ringwald 312fcb08cdbSMilanka Ringwald // convert 8 bit signed to 8 bit unsigned 313fcb08cdbSMilanka Ringwald int i; 314fcb08cdbSMilanka Ringwald for (i=0;i<samples_to_write;i++){ 315*379d044eSMilanka Ringwald audio_frame_out[i] += 128; 316fcb08cdbSMilanka Ringwald } 317613518d1SMilanka Ringwald 3186e046a36SMatthias Ringwald wav_writer_state_t * writer_state = &wav_writer_state; 319*379d044eSMilanka Ringwald write_wav_data_uint8(writer_state->wav_file, samples_to_write, audio_frame_out); 320fcb08cdbSMilanka Ringwald num_samples_to_write -= samples_to_write; 321fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 322fcb08cdbSMilanka Ringwald sco_demo_close(); 323fcb08cdbSMilanka Ringwald } 324fcb08cdbSMilanka Ringwald dump_data = 0; 325b3f76298SMilanka Ringwald 326b3f76298SMilanka Ringwald // convert back 327b3f76298SMilanka Ringwald int i; 328b3f76298SMilanka Ringwald for (i=0;i<samples_to_write;i++){ 329*379d044eSMilanka Ringwald audio_frame_out[i] += 128; 330b3f76298SMilanka Ringwald } 331fcb08cdbSMilanka Ringwald } 332fcb08cdbSMilanka Ringwald } 333fcb08cdbSMilanka Ringwald 3348b29cfc6SMatthias Ringwald #endif 3354a96141eSMatthias Ringwald #endif 3368b29cfc6SMatthias Ringwald 337fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 338fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 339fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME 340fcb08cdbSMilanka Ringwald 341613518d1SMilanka Ringwald #if 0 342fcb08cdbSMilanka Ringwald printf("SCO Demo: closing wav file\n"); 343220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 3446e046a36SMatthias Ringwald wav_writer_state_t * writer_state = &wav_writer_state; 345fcb08cdbSMilanka Ringwald if (!writer_state->wav_file) return; 346fcb08cdbSMilanka Ringwald rewind(writer_state->wav_file); 3472afeea7fSMilanka Ringwald write_wav_header(writer_state->wav_file, writer_state->total_num_samples, btstack_sbc_decoder_num_channels(&decoder_state), btstack_sbc_decoder_sample_rate(&decoder_state),2); 348fcb08cdbSMilanka Ringwald fclose(writer_state->wav_file); 349fcb08cdbSMilanka Ringwald writer_state->wav_file = NULL; 350fcb08cdbSMilanka Ringwald } 351613518d1SMilanka Ringwald #endif 352fcb08cdbSMilanka Ringwald #endif 353fcb08cdbSMilanka Ringwald #endif 354fcb08cdbSMilanka Ringwald } 355fcb08cdbSMilanka Ringwald 356fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 357fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 358fcb08cdbSMilanka Ringwald negotiated_codec = codec; 359fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 36017cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 361220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 362fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 363fcb08cdbSMilanka Ringwald } else { 364fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 365fcb08cdbSMilanka Ringwald } 366fcb08cdbSMilanka Ringwald #endif 367fcb08cdbSMilanka Ringwald #endif 368fcb08cdbSMilanka Ringwald } 369fcb08cdbSMilanka Ringwald 370f7c85330SMatthias Ringwald void sco_demo_init(void){ 371f7c85330SMatthias Ringwald 372f7c85330SMatthias Ringwald // status 373f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 374f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 375f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 376f7c85330SMatthias Ringwald #else 377f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 378f7c85330SMatthias Ringwald #endif 379f7c85330SMatthias Ringwald #endif 380f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 381f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 382f7c85330SMatthias Ringwald #endif 383f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 384f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 385f7c85330SMatthias Ringwald #endif 386f7c85330SMatthias Ringwald 387f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 388f7c85330SMatthias Ringwald int err; 389f7c85330SMatthias Ringwald PaStreamParameters outputParameters; 390f7c85330SMatthias Ringwald 391f7c85330SMatthias Ringwald /* -- initialize PortAudio -- */ 392f7c85330SMatthias Ringwald err = Pa_Initialize(); 393f7c85330SMatthias Ringwald if( err != paNoError ) return; 394f7c85330SMatthias Ringwald /* -- setup input and output -- */ 395f7c85330SMatthias Ringwald outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 396f7c85330SMatthias Ringwald outputParameters.channelCount = NUM_CHANNELS; 397f7c85330SMatthias Ringwald outputParameters.sampleFormat = PA_SAMPLE_TYPE; 398f7c85330SMatthias Ringwald outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 399f7c85330SMatthias Ringwald outputParameters.hostApiSpecificStreamInfo = NULL; 400f7c85330SMatthias Ringwald /* -- setup stream -- */ 401f7c85330SMatthias Ringwald err = Pa_OpenStream( 402f7c85330SMatthias Ringwald &stream, 403f7c85330SMatthias Ringwald NULL, // &inputParameters, 404f7c85330SMatthias Ringwald &outputParameters, 405f7c85330SMatthias Ringwald SAMPLE_RATE, 406f7c85330SMatthias Ringwald FRAMES_PER_BUFFER, 407f7c85330SMatthias Ringwald paClipOff, /* we won't output out of range samples so don't bother clipping them */ 408f7c85330SMatthias Ringwald NULL, /* no callback, use blocking API */ 409f7c85330SMatthias Ringwald NULL ); /* no callback, so no callback userData */ 410f7c85330SMatthias Ringwald if( err != paNoError ) return; 411f7c85330SMatthias Ringwald /* -- start stream -- */ 412f7c85330SMatthias Ringwald err = Pa_StartStream( stream ); 413f7c85330SMatthias Ringwald if( err != paNoError ) return; 414f7c85330SMatthias Ringwald #endif 415f7c85330SMatthias Ringwald 4167294d009SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE 417f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 4187294d009SMatthias Ringwald #endif 419f7c85330SMatthias Ringwald 420f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 421f7c85330SMatthias Ringwald phase = 'a'; 422f7c85330SMatthias Ringwald #endif 423f7c85330SMatthias Ringwald } 424f7c85330SMatthias Ringwald 4254a96141eSMatthias Ringwald static void sco_report(void){ 4264a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 4274a96141eSMatthias Ringwald } 428f7c85330SMatthias Ringwald 429f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 430f7c85330SMatthias Ringwald 431f7c85330SMatthias Ringwald if (!sco_handle) return; 432f7c85330SMatthias Ringwald 433f7c85330SMatthias Ringwald const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length(); 434f7c85330SMatthias Ringwald const int sco_payload_length = sco_packet_length - 3; 435f7c85330SMatthias Ringwald 436f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 437f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 438f7c85330SMatthias Ringwald // set handle + flags 439f7c85330SMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 440f7c85330SMatthias Ringwald // set len 441f7c85330SMatthias Ringwald sco_packet[2] = sco_payload_length; 442220eb563SMilanka Ringwald const int audio_samples_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2 443f7c85330SMatthias Ringwald 444f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 445220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 446220eb563SMilanka Ringwald 447220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 448220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 449220eb563SMilanka Ringwald } 450220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 451d5e5f834SMatthias Ringwald if (msbc_file_out){ 452d76591efSMatthias Ringwald // log outgoing mSBC data for testing 453d5e5f834SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 454d76591efSMatthias Ringwald } 4557294d009SMatthias Ringwald 456220eb563SMilanka Ringwald sco_demo_fill_audio_frame(); 457220eb563SMilanka Ringwald } else { 458f7c85330SMatthias Ringwald int i; 459220eb563SMilanka Ringwald for (i=0;i<audio_samples_per_packet;i++){ 460f7c85330SMatthias Ringwald sco_packet[3+i] = sine[phase]; 461f7c85330SMatthias Ringwald phase++; 462f7c85330SMatthias Ringwald if (phase >= sizeof(sine)) phase = 0; 463f7c85330SMatthias Ringwald } 464220eb563SMilanka Ringwald } 465f7c85330SMatthias Ringwald #else 466f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 467220eb563SMilanka Ringwald memset(&sco_packet[3], phase++, audio_samples_per_packet); 468f7c85330SMatthias Ringwald if (phase > 'z') phase = 'a'; 469f7c85330SMatthias Ringwald #else 47038b2eaafSMatthias Ringwald int j; 471220eb563SMilanka Ringwald for (j=0;j<audio_samples_per_packet;j++){ 47238b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 473f7c85330SMatthias Ringwald } 474f7c85330SMatthias Ringwald #endif 475f7c85330SMatthias Ringwald #endif 476220eb563SMilanka Ringwald 477f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 478f7c85330SMatthias Ringwald 479f7c85330SMatthias Ringwald // request another send event 480f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 481f7c85330SMatthias Ringwald 4824a96141eSMatthias Ringwald count_sent++; 4834a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 484f7c85330SMatthias Ringwald } 485f7c85330SMatthias Ringwald 486f7c85330SMatthias Ringwald /** 487f7c85330SMatthias Ringwald * @brief Process received data 488f7c85330SMatthias Ringwald */ 489f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 490f7c85330SMatthias Ringwald 491fcb08cdbSMilanka Ringwald dump_data = 1; 4928b29cfc6SMatthias Ringwald 4934a96141eSMatthias Ringwald count_received++; 4944a96141eSMatthias Ringwald // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report(); 4954a96141eSMatthias Ringwald 4964a96141eSMatthias Ringwald 4974a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 4988b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME 499220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 500fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 501fcb08cdbSMilanka Ringwald } else { 502fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 5038b29cfc6SMatthias Ringwald } 5048b29cfc6SMatthias Ringwald #endif 5054a96141eSMatthias Ringwald #endif 5068b29cfc6SMatthias Ringwald 507b3f76298SMilanka Ringwald if (packet[1] & 0x30){ 508b3f76298SMilanka Ringwald printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 509b3f76298SMilanka Ringwald log_info("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 510f7c85330SMatthias Ringwald printf_hexdump(&packet[3], size-3); 511b3f76298SMilanka Ringwald 512f7c85330SMatthias Ringwald return; 513f7c85330SMatthias Ringwald } 514f7c85330SMatthias Ringwald 515f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 516f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 517f7c85330SMatthias Ringwald uint32_t start = btstack_run_loop_get_time_ms(); 518f7c85330SMatthias Ringwald Pa_WriteStream( stream, &packet[3], size -3); 519f7c85330SMatthias Ringwald uint32_t end = btstack_run_loop_get_time_ms(); 520f7c85330SMatthias Ringwald if (end - start > 5){ 521f7c85330SMatthias Ringwald printf("Portaudio: write stream took %u ms\n", end - start); 522f7c85330SMatthias Ringwald } 5238b29cfc6SMatthias Ringwald dump_data = 0; 524f7c85330SMatthias Ringwald #endif 5258b29cfc6SMatthias Ringwald #endif 5268b29cfc6SMatthias Ringwald 5278b29cfc6SMatthias Ringwald if (dump_data){ 528f7c85330SMatthias Ringwald printf("data: "); 529f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 530f7c85330SMatthias Ringwald int i; 531f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 532f7c85330SMatthias Ringwald printf("%c", packet[i]); 533f7c85330SMatthias Ringwald } 534f7c85330SMatthias Ringwald printf("\n"); 5358b29cfc6SMatthias Ringwald dump_data = 0; 5368b29cfc6SMatthias Ringwald #else 537f7c85330SMatthias Ringwald printf_hexdump(&packet[3], size-3); 538f7c85330SMatthias Ringwald #endif 5398b29cfc6SMatthias Ringwald } 540f7c85330SMatthias Ringwald } 541