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" 474e074f72SMilanka Ringwald #include "btstack_sbc_decoder.h" 48*220eb563SMilanka Ringwald #include "btstack_sbc_encoder.h" 49*220eb563SMilanka Ringwald #include "hfp_msbc.h" 50*220eb563SMilanka 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" 64*220eb563SMilanka Ringwald #define SCO_MSBC_FILENAME "sco_output.msbc" 65*220eb563SMilanka Ringwald 668b29cfc6SMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 30 678b29cfc6SMatthias Ringwald #endif 688b29cfc6SMatthias Ringwald 69f7c85330SMatthias Ringwald 70f7c85330SMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) 71f7c85330SMatthias Ringwald #define USE_PORTAUDIO 72f7c85330SMatthias Ringwald #endif 73f7c85330SMatthias Ringwald 74f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 75f7c85330SMatthias Ringwald #include <portaudio.h> 768b29cfc6SMatthias Ringwald // portaudio config 778b29cfc6SMatthias Ringwald #define NUM_CHANNELS 1 788b29cfc6SMatthias Ringwald #define SAMPLE_RATE 8000 798b29cfc6SMatthias Ringwald #define FRAMES_PER_BUFFER 24 808b29cfc6SMatthias Ringwald #define PA_SAMPLE_TYPE paInt8 81f7c85330SMatthias Ringwald // portaudio globals 82f7c85330SMatthias Ringwald static PaStream * stream; 83f7c85330SMatthias Ringwald #endif 84f7c85330SMatthias Ringwald 85fcb08cdbSMilanka Ringwald typedef struct wav_writer_state { 86fcb08cdbSMilanka Ringwald FILE * wav_file; 87fcb08cdbSMilanka Ringwald int total_num_samples; 88fcb08cdbSMilanka Ringwald int frame_count; 89fcb08cdbSMilanka Ringwald } wav_writer_state_t; 90fcb08cdbSMilanka Ringwald 91fcb08cdbSMilanka Ringwald static int dump_data = 1; 92fcb08cdbSMilanka Ringwald 93*220eb563SMilanka Ringwald static int phase = 0; 94fcb08cdbSMilanka Ringwald static int count_sent = 0; 95fcb08cdbSMilanka Ringwald static int count_received = 0; 96*220eb563SMilanka Ringwald static uint8_t negotiated_codec = HFP_CODEC_CVSD; 97*220eb563SMilanka Ringwald static int num_audio_frames = 0; 98fcb08cdbSMilanka Ringwald 99f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 100f7c85330SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz 101f7c85330SMatthias Ringwald static const uint8_t sine[] = { 102f7c85330SMatthias Ringwald 0, 15, 31, 46, 61, 74, 86, 97, 107, 114, 103f7c85330SMatthias Ringwald 120, 124, 126, 126, 124, 120, 114, 107, 97, 86, 104f7c85330SMatthias Ringwald 74, 61, 46, 31, 15, 0, 241, 225, 210, 195, 105f7c85330SMatthias Ringwald 182, 170, 159, 149, 142, 136, 132, 130, 130, 132, 106f7c85330SMatthias Ringwald 136, 142, 149, 159, 170, 182, 195, 210, 225, 241, 107f7c85330SMatthias Ringwald }; 108f7c85330SMatthias Ringwald 109f7c85330SMatthias Ringwald 1108b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME 1118b29cfc6SMatthias Ringwald 1128b29cfc6SMatthias Ringwald static int num_samples_to_write; 113fcb08cdbSMilanka Ringwald static wav_writer_state_t wav_writer_state; 1148b29cfc6SMatthias Ringwald 115fcb08cdbSMilanka Ringwald static sbc_decoder_state_t decoder_state; 1168b29cfc6SMatthias Ringwald 1178b29cfc6SMatthias Ringwald static void little_endian_fstore_16(FILE * file, uint16_t value){ 1188b29cfc6SMatthias Ringwald uint8_t buf[2]; 1198b29cfc6SMatthias Ringwald little_endian_store_32(buf, 0, value); 1208b29cfc6SMatthias Ringwald fwrite(&buf, 1, 2, file); 1218b29cfc6SMatthias Ringwald } 1228b29cfc6SMatthias Ringwald 1238b29cfc6SMatthias Ringwald static void little_endian_fstore_32(FILE * file, uint32_t value){ 1248b29cfc6SMatthias Ringwald uint8_t buf[4]; 1258b29cfc6SMatthias Ringwald little_endian_store_32(buf, 0, value); 1268b29cfc6SMatthias Ringwald fwrite(&buf, 1, 4, file); 1278b29cfc6SMatthias Ringwald } 1288b29cfc6SMatthias Ringwald 1298b29cfc6SMatthias Ringwald static FILE * wav_init(const char * filename){ 130fcb08cdbSMilanka Ringwald FILE * f = fopen(filename, "wb"); 131fcb08cdbSMilanka Ringwald printf("SCO Demo: creating wav file %s, %p\n", filename, f); 132fcb08cdbSMilanka Ringwald return f; 1338b29cfc6SMatthias Ringwald } 1348b29cfc6SMatthias Ringwald 1358b29cfc6SMatthias Ringwald static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){ 1368b29cfc6SMatthias Ringwald /* write RIFF header */ 1378b29cfc6SMatthias Ringwald fwrite("RIFF", 1, 4, file); 1388b29cfc6SMatthias Ringwald // num_samples = blocks * subbands 1398b29cfc6SMatthias Ringwald uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels); 1408b29cfc6SMatthias Ringwald little_endian_fstore_32(file, data_bytes + 36); 1418b29cfc6SMatthias Ringwald fwrite("WAVE", 1, 4, file); 1428b29cfc6SMatthias Ringwald 1438b29cfc6SMatthias Ringwald int byte_rate = sample_rate * num_channels * bytes_per_sample; 1448b29cfc6SMatthias Ringwald int bits_per_sample = 8 * bytes_per_sample; 1458b29cfc6SMatthias Ringwald int block_align = num_channels * bits_per_sample; 1468b29cfc6SMatthias Ringwald int fmt_length = 16; 1478b29cfc6SMatthias Ringwald int fmt_format_tag = 1; // PCM 1488b29cfc6SMatthias Ringwald 1498b29cfc6SMatthias Ringwald /* write fmt chunk */ 1508b29cfc6SMatthias Ringwald fwrite("fmt ", 1, 4, file); 1518b29cfc6SMatthias Ringwald little_endian_fstore_32(file, fmt_length); 1528b29cfc6SMatthias Ringwald little_endian_fstore_16(file, fmt_format_tag); 1538b29cfc6SMatthias Ringwald little_endian_fstore_16(file, num_channels); 1548b29cfc6SMatthias Ringwald little_endian_fstore_32(file, sample_rate); 1558b29cfc6SMatthias Ringwald little_endian_fstore_32(file, byte_rate); 1568b29cfc6SMatthias Ringwald little_endian_fstore_16(file, block_align); 1578b29cfc6SMatthias Ringwald little_endian_fstore_16(file, bits_per_sample); 1588b29cfc6SMatthias Ringwald 1598b29cfc6SMatthias Ringwald /* write data chunk */ 1608b29cfc6SMatthias Ringwald fwrite("data", 1, 4, file); 1618b29cfc6SMatthias Ringwald little_endian_fstore_32(file, data_bytes); 1628b29cfc6SMatthias Ringwald } 1638b29cfc6SMatthias Ringwald 1648b29cfc6SMatthias Ringwald static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){ 1658b29cfc6SMatthias Ringwald fwrite(data, num_samples, 1, file); 1668b29cfc6SMatthias Ringwald } 1678b29cfc6SMatthias Ringwald 168fcb08cdbSMilanka Ringwald static void write_wav_data_int16(FILE * file, int num_samples, int16_t * data){ 169fcb08cdbSMilanka Ringwald fwrite(data, num_samples, 2, file); 170fcb08cdbSMilanka Ringwald } 171fcb08cdbSMilanka Ringwald 172fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 173fcb08cdbSMilanka Ringwald log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write); 174fcb08cdbSMilanka Ringwald if (!num_samples_to_write) return; 175fcb08cdbSMilanka Ringwald 176fcb08cdbSMilanka Ringwald wav_writer_state_t * writer_state = (wav_writer_state_t*) context; 177fcb08cdbSMilanka Ringwald num_samples = btstack_min(num_samples, num_samples_to_write); 178fcb08cdbSMilanka Ringwald num_samples_to_write -= num_samples; 179fcb08cdbSMilanka Ringwald 180fcb08cdbSMilanka Ringwald write_wav_data_int16(writer_state->wav_file, num_samples, data); 181fcb08cdbSMilanka Ringwald writer_state->total_num_samples+=num_samples; 182fcb08cdbSMilanka Ringwald writer_state->frame_count++; 183fcb08cdbSMilanka Ringwald 184fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 185fcb08cdbSMilanka Ringwald sco_demo_close(); 186fcb08cdbSMilanka Ringwald } 187fcb08cdbSMilanka Ringwald } 188fcb08cdbSMilanka Ringwald 189*220eb563SMilanka Ringwald static void sco_demo_generate_sine(int16_t * pcm_samples){ 190*220eb563SMilanka Ringwald int i; 191*220eb563SMilanka Ringwald for (i=0; i < hfp_msbc_num_audio_samples_per_frame(); i++){ 192*220eb563SMilanka Ringwald uint8_t buf[2]; 193*220eb563SMilanka Ringwald buf[0] = sine[phase++]; 194*220eb563SMilanka Ringwald if (phase >= sizeof(sine)) phase = 0; 195*220eb563SMilanka Ringwald buf[1] = sine[phase++]; 196*220eb563SMilanka Ringwald if (phase >= sizeof(sine)) phase = 0; 197*220eb563SMilanka Ringwald pcm_samples[i] = little_endian_read_16(buf, 0); 198*220eb563SMilanka Ringwald } 199*220eb563SMilanka Ringwald } 200*220eb563SMilanka Ringwald 201*220eb563SMilanka Ringwald static void sco_demo_fill_audio_frame(void){ 202*220eb563SMilanka Ringwald if (!hfp_msbc_can_encode_audio_frame_now()) return; 203*220eb563SMilanka Ringwald int16_t read_buffer[8*16*2]; 204*220eb563SMilanka Ringwald sco_demo_generate_sine(read_buffer); 205*220eb563SMilanka Ringwald hfp_msbc_encode_audio_frame(read_buffer); 206*220eb563SMilanka Ringwald num_audio_frames++; 207*220eb563SMilanka Ringwald } 208fcb08cdbSMilanka Ringwald 209fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){ 210fcb08cdbSMilanka Ringwald wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME); 211fcb08cdbSMilanka Ringwald wav_writer_state.frame_count = 0; 212fcb08cdbSMilanka Ringwald wav_writer_state.total_num_samples = 0; 213fcb08cdbSMilanka Ringwald 214fcb08cdbSMilanka Ringwald sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, (void*)&wav_writer_state); 215fcb08cdbSMilanka Ringwald 216fcb08cdbSMilanka Ringwald const int sample_rate = 16000; 217fcb08cdbSMilanka Ringwald const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 218fcb08cdbSMilanka Ringwald const int bytes_per_sample = 2; 219fcb08cdbSMilanka Ringwald const int num_channels = 1; 220fcb08cdbSMilanka Ringwald num_samples_to_write = num_samples; 221fcb08cdbSMilanka Ringwald 222fcb08cdbSMilanka Ringwald write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample); 223*220eb563SMilanka Ringwald 224*220eb563SMilanka Ringwald wav_init(SCO_MSBC_FILENAME); 225*220eb563SMilanka Ringwald hfp_msbc_init(); 226*220eb563SMilanka Ringwald sco_demo_fill_audio_frame(); 227fcb08cdbSMilanka Ringwald } 228fcb08cdbSMilanka Ringwald 229fcb08cdbSMilanka Ringwald static void sco_demo_init_CVSD(void){ 230fcb08cdbSMilanka Ringwald wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME); 231fcb08cdbSMilanka Ringwald wav_writer_state.frame_count = 0; 232fcb08cdbSMilanka Ringwald wav_writer_state.total_num_samples = 0; 233fcb08cdbSMilanka Ringwald 234fcb08cdbSMilanka Ringwald const int sample_rate = 8000; 235fcb08cdbSMilanka Ringwald const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 236fcb08cdbSMilanka Ringwald const int num_channels = 1; 237fcb08cdbSMilanka Ringwald const int bytes_per_sample = 1; 238fcb08cdbSMilanka Ringwald num_samples_to_write = num_samples; 239fcb08cdbSMilanka Ringwald write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample); 240fcb08cdbSMilanka Ringwald } 241fcb08cdbSMilanka Ringwald 242fcb08cdbSMilanka Ringwald 243fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 244fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 245fcb08cdbSMilanka Ringwald sbc_decoder_process_data(&decoder_state, packet+3, size-3); 246fcb08cdbSMilanka Ringwald dump_data = 0; 247fcb08cdbSMilanka Ringwald } 248fcb08cdbSMilanka Ringwald } 249fcb08cdbSMilanka Ringwald 250fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 251fcb08cdbSMilanka Ringwald if (num_samples_to_write){ 252fcb08cdbSMilanka Ringwald const int num_samples = size - 3; 253fcb08cdbSMilanka Ringwald const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 254fcb08cdbSMilanka Ringwald // convert 8 bit signed to 8 bit unsigned 255fcb08cdbSMilanka Ringwald int i; 256fcb08cdbSMilanka Ringwald for (i=0;i<samples_to_write;i++){ 257fcb08cdbSMilanka Ringwald packet[3+i] += 128; 258fcb08cdbSMilanka Ringwald } 259613518d1SMilanka Ringwald 260613518d1SMilanka Ringwald wav_writer_state_t * writer_state = (wav_writer_state_t*) decoder_state.context; 261613518d1SMilanka Ringwald write_wav_data_uint8(writer_state->wav_file, samples_to_write, &packet[3]); 262fcb08cdbSMilanka Ringwald num_samples_to_write -= samples_to_write; 263fcb08cdbSMilanka Ringwald if (num_samples_to_write == 0){ 264fcb08cdbSMilanka Ringwald sco_demo_close(); 265fcb08cdbSMilanka Ringwald } 266fcb08cdbSMilanka Ringwald dump_data = 0; 267fcb08cdbSMilanka Ringwald } 268fcb08cdbSMilanka Ringwald } 269fcb08cdbSMilanka Ringwald 2708b29cfc6SMatthias Ringwald #endif 2714a96141eSMatthias Ringwald #endif 2728b29cfc6SMatthias Ringwald 273fcb08cdbSMilanka Ringwald void sco_demo_close(void){ 274fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 275fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME 276fcb08cdbSMilanka Ringwald 277613518d1SMilanka Ringwald #if 0 278fcb08cdbSMilanka Ringwald printf("SCO Demo: closing wav file\n"); 279*220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 280fcb08cdbSMilanka Ringwald wav_writer_state_t * writer_state = (wav_writer_state_t*) decoder_state.context; 281fcb08cdbSMilanka Ringwald if (!writer_state->wav_file) return; 282fcb08cdbSMilanka Ringwald rewind(writer_state->wav_file); 283fcb08cdbSMilanka Ringwald write_wav_header(writer_state->wav_file, writer_state->total_num_samples, sbc_decoder_num_channels(&decoder_state), sbc_decoder_sample_rate(&decoder_state),2); 284fcb08cdbSMilanka Ringwald fclose(writer_state->wav_file); 285fcb08cdbSMilanka Ringwald writer_state->wav_file = NULL; 286fcb08cdbSMilanka Ringwald } 287613518d1SMilanka Ringwald #endif 288fcb08cdbSMilanka Ringwald #endif 289fcb08cdbSMilanka Ringwald #endif 290fcb08cdbSMilanka Ringwald } 291fcb08cdbSMilanka Ringwald 292fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){ 293fcb08cdbSMilanka Ringwald if (negotiated_codec == codec) return; 294fcb08cdbSMilanka Ringwald negotiated_codec = codec; 295fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 296fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME 297*220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 298fcb08cdbSMilanka Ringwald sco_demo_init_mSBC(); 299fcb08cdbSMilanka Ringwald } else { 300fcb08cdbSMilanka Ringwald sco_demo_init_CVSD(); 301fcb08cdbSMilanka Ringwald } 302fcb08cdbSMilanka Ringwald #endif 303*220eb563SMilanka Ringwald #ifdef SCO_SBC_FILENAME 304*220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 305*220eb563SMilanka Ringwald sco_demo_init_mSBC(); 306*220eb563SMilanka Ringwald } else { 307*220eb563SMilanka Ringwald sco_demo_init_CVSD(); 308*220eb563SMilanka Ringwald } 309*220eb563SMilanka Ringwald #endif 310*220eb563SMilanka Ringwald 311fcb08cdbSMilanka Ringwald #endif 312fcb08cdbSMilanka Ringwald } 313fcb08cdbSMilanka Ringwald 314f7c85330SMatthias Ringwald void sco_demo_init(void){ 315f7c85330SMatthias Ringwald 316f7c85330SMatthias Ringwald // status 317f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 318f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO 319f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 320f7c85330SMatthias Ringwald #else 321f7c85330SMatthias Ringwald printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 322f7c85330SMatthias Ringwald #endif 323f7c85330SMatthias Ringwald #endif 324f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 325f7c85330SMatthias Ringwald printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 326f7c85330SMatthias Ringwald #endif 327f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 328f7c85330SMatthias Ringwald printf("SCO Demo: Sending counter value, hexdump received data.\n"); 329f7c85330SMatthias Ringwald #endif 330f7c85330SMatthias Ringwald 331f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 332f7c85330SMatthias Ringwald int err; 333f7c85330SMatthias Ringwald PaStreamParameters outputParameters; 334f7c85330SMatthias Ringwald 335f7c85330SMatthias Ringwald /* -- initialize PortAudio -- */ 336f7c85330SMatthias Ringwald err = Pa_Initialize(); 337f7c85330SMatthias Ringwald if( err != paNoError ) return; 338f7c85330SMatthias Ringwald /* -- setup input and output -- */ 339f7c85330SMatthias Ringwald outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 340f7c85330SMatthias Ringwald outputParameters.channelCount = NUM_CHANNELS; 341f7c85330SMatthias Ringwald outputParameters.sampleFormat = PA_SAMPLE_TYPE; 342f7c85330SMatthias Ringwald outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 343f7c85330SMatthias Ringwald outputParameters.hostApiSpecificStreamInfo = NULL; 344f7c85330SMatthias Ringwald /* -- setup stream -- */ 345f7c85330SMatthias Ringwald err = Pa_OpenStream( 346f7c85330SMatthias Ringwald &stream, 347f7c85330SMatthias Ringwald NULL, // &inputParameters, 348f7c85330SMatthias Ringwald &outputParameters, 349f7c85330SMatthias Ringwald SAMPLE_RATE, 350f7c85330SMatthias Ringwald FRAMES_PER_BUFFER, 351f7c85330SMatthias Ringwald paClipOff, /* we won't output out of range samples so don't bother clipping them */ 352f7c85330SMatthias Ringwald NULL, /* no callback, use blocking API */ 353f7c85330SMatthias Ringwald NULL ); /* no callback, so no callback userData */ 354f7c85330SMatthias Ringwald if( err != paNoError ) return; 355f7c85330SMatthias Ringwald /* -- start stream -- */ 356f7c85330SMatthias Ringwald err = Pa_StartStream( stream ); 357f7c85330SMatthias Ringwald if( err != paNoError ) return; 358f7c85330SMatthias Ringwald #endif 359f7c85330SMatthias Ringwald 360fcb08cdbSMilanka Ringwald //#if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE 361f7c85330SMatthias Ringwald hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 362fcb08cdbSMilanka Ringwald //#endif 363f7c85330SMatthias Ringwald 364f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 365f7c85330SMatthias Ringwald phase = 'a'; 366f7c85330SMatthias Ringwald #endif 367f7c85330SMatthias Ringwald } 368f7c85330SMatthias Ringwald 3694a96141eSMatthias Ringwald static void sco_report(void){ 3704a96141eSMatthias Ringwald printf("SCO: sent %u, received %u\n", count_sent, count_received); 3714a96141eSMatthias Ringwald } 372f7c85330SMatthias Ringwald 373f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){ 374f7c85330SMatthias Ringwald 375f7c85330SMatthias Ringwald if (!sco_handle) return; 376f7c85330SMatthias Ringwald 377f7c85330SMatthias Ringwald const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length(); 378f7c85330SMatthias Ringwald const int sco_payload_length = sco_packet_length - 3; 379f7c85330SMatthias Ringwald 380f7c85330SMatthias Ringwald hci_reserve_packet_buffer(); 381f7c85330SMatthias Ringwald uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 382f7c85330SMatthias Ringwald // set handle + flags 383f7c85330SMatthias Ringwald little_endian_store_16(sco_packet, 0, sco_handle); 384f7c85330SMatthias Ringwald // set len 385f7c85330SMatthias Ringwald sco_packet[2] = sco_payload_length; 386*220eb563SMilanka Ringwald const int audio_samples_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2 387f7c85330SMatthias Ringwald 388f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 389*220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 390*220eb563SMilanka Ringwald 391*220eb563SMilanka Ringwald if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 392*220eb563SMilanka Ringwald log_error("mSBC stream is empty."); 393*220eb563SMilanka Ringwald } 394*220eb563SMilanka Ringwald hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 395*220eb563SMilanka Ringwald sco_demo_fill_audio_frame(); 396*220eb563SMilanka Ringwald } else { 397f7c85330SMatthias Ringwald int i; 398*220eb563SMilanka Ringwald for (i=0;i<audio_samples_per_packet;i++){ 399f7c85330SMatthias Ringwald sco_packet[3+i] = sine[phase]; 400f7c85330SMatthias Ringwald phase++; 401f7c85330SMatthias Ringwald if (phase >= sizeof(sine)) phase = 0; 402f7c85330SMatthias Ringwald } 403*220eb563SMilanka Ringwald } 404f7c85330SMatthias Ringwald #else 405f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 406*220eb563SMilanka Ringwald memset(&sco_packet[3], phase++, audio_samples_per_packet); 407f7c85330SMatthias Ringwald if (phase > 'z') phase = 'a'; 408f7c85330SMatthias Ringwald #else 40938b2eaafSMatthias Ringwald int j; 410*220eb563SMilanka Ringwald for (j=0;j<audio_samples_per_packet;j++){ 41138b2eaafSMatthias Ringwald sco_packet[3+j] = phase++; 412f7c85330SMatthias Ringwald } 413f7c85330SMatthias Ringwald #endif 414f7c85330SMatthias Ringwald #endif 415*220eb563SMilanka Ringwald 416f7c85330SMatthias Ringwald hci_send_sco_packet_buffer(sco_packet_length); 417f7c85330SMatthias Ringwald 418f7c85330SMatthias Ringwald // request another send event 419f7c85330SMatthias Ringwald hci_request_sco_can_send_now_event(); 420f7c85330SMatthias Ringwald 4214a96141eSMatthias Ringwald count_sent++; 4224a96141eSMatthias Ringwald if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 423f7c85330SMatthias Ringwald } 424f7c85330SMatthias Ringwald 425fcb08cdbSMilanka Ringwald 426f7c85330SMatthias Ringwald /** 427f7c85330SMatthias Ringwald * @brief Process received data 428f7c85330SMatthias Ringwald */ 429f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){ 430f7c85330SMatthias Ringwald 4318b29cfc6SMatthias Ringwald 432fcb08cdbSMilanka Ringwald dump_data = 1; 4338b29cfc6SMatthias Ringwald 4344a96141eSMatthias Ringwald count_received++; 4354a96141eSMatthias Ringwald // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report(); 4364a96141eSMatthias Ringwald 4374a96141eSMatthias Ringwald 4384a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 4398b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME 440*220eb563SMilanka Ringwald if (negotiated_codec == HFP_CODEC_MSBC){ 441fcb08cdbSMilanka Ringwald sco_demo_receive_mSBC(packet, size); 442fcb08cdbSMilanka Ringwald } else { 443fcb08cdbSMilanka Ringwald sco_demo_receive_CVSD(packet, size); 4448b29cfc6SMatthias Ringwald } 4458b29cfc6SMatthias Ringwald #endif 4464a96141eSMatthias Ringwald #endif 4478b29cfc6SMatthias Ringwald 448f7c85330SMatthias Ringwald if (packet[1] & 0xf0){ 449f7c85330SMatthias Ringwald printf("SCO CRC Error: %x - data: ", packet[1] >> 4); 450f7c85330SMatthias Ringwald printf_hexdump(&packet[3], size-3); 451f7c85330SMatthias Ringwald return; 452f7c85330SMatthias Ringwald } 453f7c85330SMatthias Ringwald 454f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 455f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO 456f7c85330SMatthias Ringwald uint32_t start = btstack_run_loop_get_time_ms(); 457f7c85330SMatthias Ringwald Pa_WriteStream( stream, &packet[3], size -3); 458f7c85330SMatthias Ringwald uint32_t end = btstack_run_loop_get_time_ms(); 459f7c85330SMatthias Ringwald if (end - start > 5){ 460f7c85330SMatthias Ringwald printf("Portaudio: write stream took %u ms\n", end - start); 461f7c85330SMatthias Ringwald } 4628b29cfc6SMatthias Ringwald dump_data = 0; 463f7c85330SMatthias Ringwald #endif 4648b29cfc6SMatthias Ringwald #endif 4658b29cfc6SMatthias Ringwald 4668b29cfc6SMatthias Ringwald if (dump_data){ 467f7c85330SMatthias Ringwald printf("data: "); 468f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 469f7c85330SMatthias Ringwald int i; 470f7c85330SMatthias Ringwald for (i=3;i<size;i++){ 471f7c85330SMatthias Ringwald printf("%c", packet[i]); 472f7c85330SMatthias Ringwald } 473f7c85330SMatthias Ringwald printf("\n"); 4748b29cfc6SMatthias Ringwald dump_data = 0; 4758b29cfc6SMatthias Ringwald #else 476f7c85330SMatthias Ringwald printf_hexdump(&packet[3], size-3); 477f7c85330SMatthias Ringwald #endif 4788b29cfc6SMatthias Ringwald } 479f7c85330SMatthias Ringwald } 480