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" 47*0c87db9eSMilanka Ringwald #include "btstack_sbc.h" 48220eb563SMilanka Ringwald #include "hfp_msbc.h" 49220eb563SMilanka Ringwald #include "hfp.h" 50fcb08cdbSMilanka Ringwald 51f7c85330SMatthias Ringwald // configure test mode 52f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE 0 53f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII 1 54f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER 2 55f7c85330SMatthias Ringwald 568b29cfc6SMatthias Ringwald 57f7c85330SMatthias Ringwald // SCO demo configuration 58fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE 59f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100 60f7c85330SMatthias Ringwald 618b29cfc6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO 628b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav" 637294d009SMatthias Ringwald // #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 64220eb563SMilanka Ringwald 658b29cfc6SMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 30 668b29cfc6SMatthias Ringwald #endif 678b29cfc6SMatthias Ringwald 68f7c85330SMatthias Ringwald 69f7c85330SMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) 70f7c85330SMatthias Ringwald #define USE_PORTAUDIO 71f7c85330SMatthias Ringwald #endif 72f7c85330SMatthias Ringwald 73f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 74f7c85330SMatthias Ringwald #include <portaudio.h> 758b29cfc6SMatthias Ringwald // portaudio config 768b29cfc6SMatthias Ringwald #define NUM_CHANNELS 1 778b29cfc6SMatthias Ringwald #define SAMPLE_RATE 8000 788b29cfc6SMatthias Ringwald #define FRAMES_PER_BUFFER 24 798b29cfc6SMatthias Ringwald #define PA_SAMPLE_TYPE paInt8 80f7c85330SMatthias Ringwald // portaudio globals 81f7c85330SMatthias Ringwald static PaStream * stream; 82f7c85330SMatthias Ringwald #endif 83f7c85330SMatthias Ringwald 84fcb08cdbSMilanka Ringwald typedef struct wav_writer_state { 85fcb08cdbSMilanka Ringwald FILE * wav_file; 86fcb08cdbSMilanka Ringwald int total_num_samples; 87fcb08cdbSMilanka Ringwald int frame_count; 88fcb08cdbSMilanka Ringwald } wav_writer_state_t; 89fcb08cdbSMilanka Ringwald 90fcb08cdbSMilanka Ringwald static int dump_data = 1; 91fcb08cdbSMilanka Ringwald 92220eb563SMilanka Ringwald static int phase = 0; 93fcb08cdbSMilanka Ringwald static int count_sent = 0; 94fcb08cdbSMilanka Ringwald static int count_received = 0; 95d76591efSMatthias Ringwald static uint8_t negotiated_codec = 0; 96220eb563SMilanka Ringwald static int num_audio_frames = 0; 97fcb08cdbSMilanka Ringwald 987294d009SMatthias Ringwald FILE * msbc_file; 997294d009SMatthias Ringwald 100f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 101d6a06398SMatthias Ringwald 102d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 8 kHz 103f7c85330SMatthias Ringwald static const uint8_t sine[] = { 104f7c85330SMatthias Ringwald 0, 15, 31, 46, 61, 74, 86, 97, 107, 114, 105f7c85330SMatthias Ringwald 120, 124, 126, 126, 124, 120, 114, 107, 97, 86, 106f7c85330SMatthias Ringwald 74, 61, 46, 31, 15, 0, 241, 225, 210, 195, 107f7c85330SMatthias Ringwald 182, 170, 159, 149, 142, 136, 132, 130, 130, 132, 108f7c85330SMatthias Ringwald 136, 142, 149, 159, 170, 182, 195, 210, 225, 241, 109f7c85330SMatthias Ringwald }; 110f7c85330SMatthias Ringwald 111d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz 112d6a06398SMatthias Ringwald static const int16_t sine_int16[] = { 113d6a06398SMatthias Ringwald 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 114d6a06398SMatthias Ringwald 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 115d6a06398SMatthias Ringwald 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 116d6a06398SMatthias Ringwald 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 117d6a06398SMatthias Ringwald 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 118d6a06398SMatthias Ringwald 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 119d6a06398SMatthias Ringwald -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 120d6a06398SMatthias Ringwald -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 121d6a06398SMatthias Ringwald -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 122d6a06398SMatthias Ringwald -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 123d6a06398SMatthias Ringwald }; 124f7c85330SMatthias Ringwald 1258b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME 1268b29cfc6SMatthias Ringwald 1278b29cfc6SMatthias Ringwald static int num_samples_to_write; 128fcb08cdbSMilanka Ringwald static wav_writer_state_t wav_writer_state; 1298b29cfc6SMatthias Ringwald 1302afeea7fSMilanka Ringwald static btstack_sbc_decoder_state_t decoder_state; 1318b29cfc6SMatthias Ringwald 1328b29cfc6SMatthias Ringwald static void little_endian_fstore_16(FILE * file, uint16_t value){ 1338b29cfc6SMatthias Ringwald uint8_t buf[2]; 1348b29cfc6SMatthias Ringwald little_endian_store_32(buf, 0, value); 1358b29cfc6SMatthias Ringwald fwrite(&buf, 1, 2, file); 1368b29cfc6SMatthias Ringwald } 1378b29cfc6SMatthias Ringwald 1388b29cfc6SMatthias Ringwald static void little_endian_fstore_32(FILE * file, uint32_t value){ 1398b29cfc6SMatthias Ringwald uint8_t buf[4]; 1408b29cfc6SMatthias Ringwald little_endian_store_32(buf, 0, value); 1418b29cfc6SMatthias Ringwald fwrite(&buf, 1, 4, file); 1428b29cfc6SMatthias Ringwald } 1438b29cfc6SMatthias Ringwald 1448b29cfc6SMatthias Ringwald static FILE * wav_init(const char * filename){ 145fcb08cdbSMilanka Ringwald FILE * f = fopen(filename, "wb"); 146fcb08cdbSMilanka Ringwald printf("SCO Demo: creating wav file %s, %p\n", filename, f); 147fcb08cdbSMilanka Ringwald return f; 1488b29cfc6SMatthias Ringwald } 1498b29cfc6SMatthias Ringwald 1508b29cfc6SMatthias Ringwald static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){ 1518b29cfc6SMatthias Ringwald /* write RIFF header */ 1528b29cfc6SMatthias Ringwald fwrite("RIFF", 1, 4, file); 1538b29cfc6SMatthias Ringwald // num_samples = blocks * subbands 1548b29cfc6SMatthias Ringwald uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels); 1558b29cfc6SMatthias Ringwald little_endian_fstore_32(file, data_bytes + 36); 1568b29cfc6SMatthias Ringwald fwrite("WAVE", 1, 4, file); 1578b29cfc6SMatthias Ringwald 1588b29cfc6SMatthias Ringwald int byte_rate = sample_rate * num_channels * bytes_per_sample; 1598b29cfc6SMatthias Ringwald int bits_per_sample = 8 * bytes_per_sample; 1608b29cfc6SMatthias Ringwald int block_align = num_channels * bits_per_sample; 1618b29cfc6SMatthias Ringwald int fmt_length = 16; 1628b29cfc6SMatthias Ringwald int fmt_format_tag = 1; // PCM 1638b29cfc6SMatthias Ringwald 1648b29cfc6SMatthias Ringwald /* write fmt chunk */ 1658b29cfc6SMatthias Ringwald fwrite("fmt ", 1, 4, file); 1668b29cfc6SMatthias Ringwald little_endian_fstore_32(file, fmt_length); 1678b29cfc6SMatthias Ringwald little_endian_fstore_16(file, fmt_format_tag); 1688b29cfc6SMatthias Ringwald little_endian_fstore_16(file, num_channels); 1698b29cfc6SMatthias Ringwald little_endian_fstore_32(file, sample_rate); 1708b29cfc6SMatthias Ringwald little_endian_fstore_32(file, byte_rate); 1718b29cfc6SMatthias Ringwald little_endian_fstore_16(file, block_align); 1728b29cfc6SMatthias Ringwald little_endian_fstore_16(file, bits_per_sample); 1738b29cfc6SMatthias Ringwald 1748b29cfc6SMatthias Ringwald /* write data chunk */ 1758b29cfc6SMatthias Ringwald fwrite("data", 1, 4, file); 1768b29cfc6SMatthias Ringwald little_endian_fstore_32(file, data_bytes); 1778b29cfc6SMatthias Ringwald } 1788b29cfc6SMatthias Ringwald 1798b29cfc6SMatthias Ringwald static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){ 1808b29cfc6SMatthias Ringwald fwrite(data, num_samples, 1, file); 1818b29cfc6SMatthias Ringwald } 1828b29cfc6SMatthias Ringwald 183fcb08cdbSMilanka Ringwald static void write_wav_data_int16(FILE * file, int num_samples, int16_t * data){ 184fcb08cdbSMilanka Ringwald fwrite(data, num_samples, 2, file); 185fcb08cdbSMilanka Ringwald } 186fcb08cdbSMilanka Ringwald 187fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 188fcb08cdbSMilanka Ringwald log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write); 189fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 190fcb08cdbSMilanka Ringwald 191fcb08cdbSMilanka Ringwald wav_writer_state_t * writer_state = (wav_writer_state_t*) context; 192fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 193fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 194fcb08cdbSMilanka Ringwald 195fcb08cdbSMilanka Ringwald write_wav_data_int16(writer_state->wav_file, num_samples, data); 196fcb08cdbSMilanka Ringwald writer_state->total_num_samples+=num_samples; 197fcb08cdbSMilanka Ringwald writer_state->frame_count++; 198fcb08cdbSMilanka Ringwald 199fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 200fcb08cdbSMilanka Ringwald sco_demo_close(); 201fcb08cdbSMilanka Ringwald } 202fcb08cdbSMilanka Ringwald } 203fcb08cdbSMilanka Ringwald 204220eb563SMilanka Ringwald static void sco_demo_fill_audio_frame(void){ 205220eb563SMilanka Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 206d6a06398SMatthias Ringwald int i; 207d6a06398SMatthias Ringwald int16_t sample_buffer[8*16*2]; 208d6a06398SMatthias Ringwald for (i=0; i < hfp_msbc_num_audio_samples_per_frame(); i++){ 209d6a06398SMatthias Ringwald sample_buffer[i] = sine_int16[phase++]; 210d6a06398SMatthias Ringwald if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){ 211d6a06398SMatthias Ringwald phase = 0; 212d6a06398SMatthias Ringwald } 213d6a06398SMatthias Ringwald } 214d6a06398SMatthias Ringwald hfp_msbc_encode_audio_frame(sample_buffer); 215220eb563SMilanka Ringwald num_audio_frames++; 216220eb563SMilanka Ringwald } 217fcb08cdbSMilanka Ringwald 218fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 219fcb08cdbSMilanka Ringwald wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME); 220fcb08cdbSMilanka Ringwald wav_writer_state.frame_count = 0; 221fcb08cdbSMilanka Ringwald wav_writer_state.total_num_samples = 0; 222fcb08cdbSMilanka Ringwald 2232afeea7fSMilanka Ringwald btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, (void*)&wav_writer_state); 224fcb08cdbSMilanka Ringwald 225fcb08cdbSMilanka Ringwald const int sample_rate = 16000; 226fcb08cdbSMilanka Ringwald const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 227fcb08cdbSMilanka Ringwald const int bytes_per_sample = 2; 228fcb08cdbSMilanka Ringwald const int num_channels = 1; 229fcb08cdbSMilanka Ringwald num_samples_to_write = num_samples; 230fcb08cdbSMilanka Ringwald 231fcb08cdbSMilanka Ringwald write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample); 232220eb563SMilanka Ringwald 233220eb563SMilanka Ringwald hfp_msbc_init(); 234220eb563SMilanka Ringwald sco_demo_fill_audio_frame(); 235973d7173SMatthias Ringwald 2367294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME 2377294d009SMatthias Ringwald msbc_file = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 2387294d009SMatthias Ringwald printf("SCO Demo: creating mSBC file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file); 2397294d009SMatthias Ringwald #endif 2407294d009SMatthias Ringwald 241973d7173SMatthias Ringwald // HACK: should be handled by HFP or HSP layer on (e)SCO connection request, not here 242973d7173SMatthias Ringwald // transparent data 243973d7173SMatthias Ringwald hci_set_sco_voice_setting(0x0003); 244fcb08cdbSMilanka Ringwald } 245fcb08cdbSMilanka Ringwald 246fcb08cdbSMilanka Ringwald static void sco_demo_init_CVSD(void){ 247fcb08cdbSMilanka Ringwald wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME); 248fcb08cdbSMilanka Ringwald wav_writer_state.frame_count = 0; 249fcb08cdbSMilanka Ringwald wav_writer_state.total_num_samples = 0; 250fcb08cdbSMilanka Ringwald 251fcb08cdbSMilanka Ringwald const int sample_rate = 8000; 252fcb08cdbSMilanka Ringwald const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 253fcb08cdbSMilanka Ringwald const int num_channels = 1; 254fcb08cdbSMilanka Ringwald const int bytes_per_sample = 1; 255fcb08cdbSMilanka Ringwald num_samples_to_write = num_samples; 256fcb08cdbSMilanka Ringwald write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample); 257973d7173SMatthias Ringwald 258973d7173SMatthias Ringwald // HACK: should be handled by HFP or HSP layer on (e)SCO connection request, not here 259973d7173SMatthias Ringwald // signed 8 bit pcm data with CVSD over the air 260973d7173SMatthias Ringwald hci_set_sco_voice_setting(0x0040); 261fcb08cdbSMilanka Ringwald } 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){ 2662afeea7fSMilanka Ringwald btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 267fcb08cdbSMilanka Ringwald dump_data = 0; 268fcb08cdbSMilanka Ringwald } 269fcb08cdbSMilanka Ringwald } 270fcb08cdbSMilanka Ringwald 271fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 272fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 273fcb08cdbSMilanka Ringwald const int num_samples = size - 3; 274fcb08cdbSMilanka Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 275fcb08cdbSMilanka Ringwald // convert 8 bit signed to 8 bit unsigned 276fcb08cdbSMilanka Ringwald int i; 277fcb08cdbSMilanka Ringwald for (i=0;i<samples_to_write;i++){ 278fcb08cdbSMilanka Ringwald packet[3+i] += 128; 279fcb08cdbSMilanka Ringwald } 280613518d1SMilanka Ringwald 2816e046a36SMatthias Ringwald wav_writer_state_t * writer_state = &wav_writer_state; 282613518d1SMilanka Ringwald write_wav_data_uint8(writer_state->wav_file, samples_to_write, &packet[3]); 283fcb08cdbSMilanka Ringwald num_samples_to_write -= samples_to_write; 284fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 285fcb08cdbSMilanka Ringwald sco_demo_close(); 286fcb08cdbSMilanka Ringwald } 287fcb08cdbSMilanka Ringwald dump_data = 0; 288fcb08cdbSMilanka Ringwald } 289fcb08cdbSMilanka Ringwald } 290fcb08cdbSMilanka Ringwald 2918b29cfc6SMatthias Ringwald #endif 2924a96141eSMatthias Ringwald #endif 2938b29cfc6SMatthias Ringwald 294fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 295fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 296fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME 297fcb08cdbSMilanka Ringwald 298613518d1SMilanka Ringwald #if 0 299fcb08cdbSMilanka Ringwald printf("SCO Demo: closing wav file\n"); 300220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 3016e046a36SMatthias Ringwald wav_writer_state_t * writer_state = &wav_writer_state; 302fcb08cdbSMilanka Ringwald if (!writer_state->wav_file) return; 303fcb08cdbSMilanka Ringwald rewind(writer_state->wav_file); 3042afeea7fSMilanka 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); 305fcb08cdbSMilanka Ringwald fclose(writer_state->wav_file); 306fcb08cdbSMilanka Ringwald writer_state->wav_file = NULL; 307fcb08cdbSMilanka Ringwald } 308613518d1SMilanka Ringwald #endif 309fcb08cdbSMilanka Ringwald #endif 310fcb08cdbSMilanka Ringwald #endif 311fcb08cdbSMilanka Ringwald } 312fcb08cdbSMilanka Ringwald 313fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 314fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 315fcb08cdbSMilanka Ringwald negotiated_codec = codec; 316fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 31717cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 318220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 319fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 320fcb08cdbSMilanka Ringwald } else { 321fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 322fcb08cdbSMilanka Ringwald } 323fcb08cdbSMilanka Ringwald #endif 324fcb08cdbSMilanka Ringwald #endif 325fcb08cdbSMilanka Ringwald } 326fcb08cdbSMilanka Ringwald 327f7c85330SMatthias Ringwald void sco_demo_init(void){ 328f7c85330SMatthias Ringwald 329f7c85330SMatthias Ringwald // status 330f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 331f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 332f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 333f7c85330SMatthias Ringwald #else 334f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 335f7c85330SMatthias Ringwald #endif 336f7c85330SMatthias Ringwald #endif 337f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 338f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 339f7c85330SMatthias Ringwald #endif 340f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 341f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 342f7c85330SMatthias Ringwald #endif 343f7c85330SMatthias Ringwald 344f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 345f7c85330SMatthias Ringwald int err; 346f7c85330SMatthias Ringwald PaStreamParameters outputParameters; 347f7c85330SMatthias Ringwald 348f7c85330SMatthias Ringwald /* -- initialize PortAudio -- */ 349f7c85330SMatthias Ringwald err = Pa_Initialize(); 350f7c85330SMatthias Ringwald if( err != paNoError ) return; 351f7c85330SMatthias Ringwald /* -- setup input and output -- */ 352f7c85330SMatthias Ringwald outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 353f7c85330SMatthias Ringwald outputParameters.channelCount = NUM_CHANNELS; 354f7c85330SMatthias Ringwald outputParameters.sampleFormat = PA_SAMPLE_TYPE; 355f7c85330SMatthias Ringwald outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 356f7c85330SMatthias Ringwald outputParameters.hostApiSpecificStreamInfo = NULL; 357f7c85330SMatthias Ringwald /* -- setup stream -- */ 358f7c85330SMatthias Ringwald err = Pa_OpenStream( 359f7c85330SMatthias Ringwald &stream, 360f7c85330SMatthias Ringwald NULL, // &inputParameters, 361f7c85330SMatthias Ringwald &outputParameters, 362f7c85330SMatthias Ringwald SAMPLE_RATE, 363f7c85330SMatthias Ringwald FRAMES_PER_BUFFER, 364f7c85330SMatthias Ringwald paClipOff, /* we won't output out of range samples so don't bother clipping them */ 365f7c85330SMatthias Ringwald NULL, /* no callback, use blocking API */ 366f7c85330SMatthias Ringwald NULL ); /* no callback, so no callback userData */ 367f7c85330SMatthias Ringwald if( err != paNoError ) return; 368f7c85330SMatthias Ringwald /* -- start stream -- */ 369f7c85330SMatthias Ringwald err = Pa_StartStream( stream ); 370f7c85330SMatthias Ringwald if( err != paNoError ) return; 371f7c85330SMatthias Ringwald #endif 372f7c85330SMatthias Ringwald 3737294d009SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE 374f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 3757294d009SMatthias Ringwald #endif 376f7c85330SMatthias Ringwald 377f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 378f7c85330SMatthias Ringwald phase = 'a'; 379f7c85330SMatthias Ringwald #endif 380f7c85330SMatthias Ringwald } 381f7c85330SMatthias Ringwald 3824a96141eSMatthias Ringwald static void sco_report(void){ 3834a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 3844a96141eSMatthias Ringwald } 385f7c85330SMatthias Ringwald 386d76591efSMatthias Ringwald static void sco_assert_codec_set(void){ 387d76591efSMatthias Ringwald // if SCO is open but we didn't hear about the codec yet, we fall back to CVSD 388d76591efSMatthias Ringwald if (!negotiated_codec){ 389d76591efSMatthias Ringwald sco_demo_set_codec(HFP_CODEC_CVSD); 390d76591efSMatthias Ringwald } 391d76591efSMatthias Ringwald } 392d76591efSMatthias Ringwald 393f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 394f7c85330SMatthias Ringwald 395f7c85330SMatthias Ringwald if (!sco_handle) return; 396f7c85330SMatthias Ringwald 397d76591efSMatthias Ringwald sco_assert_codec_set(); 398d76591efSMatthias Ringwald 399f7c85330SMatthias Ringwald const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length(); 400f7c85330SMatthias Ringwald const int sco_payload_length = sco_packet_length - 3; 401f7c85330SMatthias Ringwald 402f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 403f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 404f7c85330SMatthias Ringwald // set handle + flags 405f7c85330SMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 406f7c85330SMatthias Ringwald // set len 407f7c85330SMatthias Ringwald sco_packet[2] = sco_payload_length; 408220eb563SMilanka Ringwald const int audio_samples_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2 409f7c85330SMatthias Ringwald 410f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 411220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 412220eb563SMilanka Ringwald 413220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 414220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 415220eb563SMilanka Ringwald } 416220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 417d76591efSMatthias Ringwald if (msbc_file){ 418d76591efSMatthias Ringwald // log outgoing mSBC data for testing 4197294d009SMatthias Ringwald fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file); 420d76591efSMatthias Ringwald } 4217294d009SMatthias Ringwald 422220eb563SMilanka Ringwald sco_demo_fill_audio_frame(); 423220eb563SMilanka Ringwald } else { 424f7c85330SMatthias Ringwald int i; 425220eb563SMilanka Ringwald for (i=0;i<audio_samples_per_packet;i++){ 426f7c85330SMatthias Ringwald sco_packet[3+i] = sine[phase]; 427f7c85330SMatthias Ringwald phase++; 428f7c85330SMatthias Ringwald if (phase >= sizeof(sine)) phase = 0; 429f7c85330SMatthias Ringwald } 430220eb563SMilanka Ringwald } 431f7c85330SMatthias Ringwald #else 432f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 433220eb563SMilanka Ringwald memset(&sco_packet[3], phase++, audio_samples_per_packet); 434f7c85330SMatthias Ringwald if (phase > 'z') phase = 'a'; 435f7c85330SMatthias Ringwald #else 43638b2eaafSMatthias Ringwald int j; 437220eb563SMilanka Ringwald for (j=0;j<audio_samples_per_packet;j++){ 43838b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 439f7c85330SMatthias Ringwald } 440f7c85330SMatthias Ringwald #endif 441f7c85330SMatthias Ringwald #endif 442220eb563SMilanka Ringwald 443f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 444f7c85330SMatthias Ringwald 445f7c85330SMatthias Ringwald // request another send event 446f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 447f7c85330SMatthias Ringwald 4484a96141eSMatthias Ringwald count_sent++; 4494a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 450f7c85330SMatthias Ringwald } 451f7c85330SMatthias Ringwald 452f7c85330SMatthias Ringwald /** 453f7c85330SMatthias Ringwald * @brief Process received data 454f7c85330SMatthias Ringwald */ 455f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 456f7c85330SMatthias Ringwald 457d76591efSMatthias Ringwald sco_assert_codec_set(); 4588b29cfc6SMatthias Ringwald 459fcb08cdbSMilanka Ringwald dump_data = 1; 4608b29cfc6SMatthias Ringwald 4614a96141eSMatthias Ringwald count_received++; 4624a96141eSMatthias Ringwald // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report(); 4634a96141eSMatthias Ringwald 4644a96141eSMatthias Ringwald 4654a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 4668b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME 467220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 468fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 469fcb08cdbSMilanka Ringwald } else { 470fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 4718b29cfc6SMatthias Ringwald } 4728b29cfc6SMatthias Ringwald #endif 4734a96141eSMatthias Ringwald #endif 4748b29cfc6SMatthias Ringwald 475f7c85330SMatthias Ringwald if (packet[1] & 0xf0){ 476f7c85330SMatthias Ringwald printf("SCO CRC Error: %x - data: ", packet[1] >> 4); 477f7c85330SMatthias Ringwald printf_hexdump(&packet[3], size-3); 478f7c85330SMatthias Ringwald return; 479f7c85330SMatthias Ringwald } 480f7c85330SMatthias Ringwald 481f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 482f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 483f7c85330SMatthias Ringwald uint32_t start = btstack_run_loop_get_time_ms(); 484f7c85330SMatthias Ringwald Pa_WriteStream( stream, &packet[3], size -3); 485f7c85330SMatthias Ringwald uint32_t end = btstack_run_loop_get_time_ms(); 486f7c85330SMatthias Ringwald if (end - start > 5){ 487f7c85330SMatthias Ringwald printf("Portaudio: write stream took %u ms\n", end - start); 488f7c85330SMatthias Ringwald } 4898b29cfc6SMatthias Ringwald dump_data = 0; 490f7c85330SMatthias Ringwald #endif 4918b29cfc6SMatthias Ringwald #endif 4928b29cfc6SMatthias Ringwald 4938b29cfc6SMatthias Ringwald if (dump_data){ 494f7c85330SMatthias Ringwald printf("data: "); 495f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 496f7c85330SMatthias Ringwald int i; 497f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 498f7c85330SMatthias Ringwald printf("%c", packet[i]); 499f7c85330SMatthias Ringwald } 500f7c85330SMatthias Ringwald printf("\n"); 5018b29cfc6SMatthias Ringwald dump_data = 0; 5028b29cfc6SMatthias Ringwald #else 503f7c85330SMatthias Ringwald printf_hexdump(&packet[3], size-3); 504f7c85330SMatthias Ringwald #endif 5058b29cfc6SMatthias Ringwald } 506f7c85330SMatthias Ringwald } 507