1 /* 2 * Copyright (C) 2016 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 /* 39 * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo 40 */ 41 42 43 #include <stdio.h> 44 45 #include "sco_demo_util.h" 46 #include "btstack_debug.h" 47 #include "btstack_sbc.h" 48 #include "btstack_cvsd_plc.h" 49 #include "hfp_msbc.h" 50 #include "hfp.h" 51 52 // configure test mode 53 #define SCO_DEMO_MODE_SINE 0 54 #define SCO_DEMO_MODE_ASCII 1 55 #define SCO_DEMO_MODE_COUNTER 2 56 57 58 // SCO demo configuration 59 #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE 60 #define SCO_REPORT_PERIOD 100 61 62 #ifdef HAVE_POSIX_FILE_IO 63 #define SCO_WAV_FILENAME "sco_input.wav" 64 #define SCO_MSBC_OUT_FILENAME "sco_output.msbc" 65 #define SCO_MSBC_IN_FILENAME "sco_input.mscb" 66 67 #define SCO_WAV_DURATION_IN_SECONDS 15 68 #endif 69 70 71 #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) 72 #define USE_PORTAUDIO 73 #endif 74 75 #ifdef USE_PORTAUDIO 76 #include <portaudio.h> 77 // portaudio config 78 #define NUM_CHANNELS 1 79 #define SAMPLE_RATE 8000 80 #define FRAMES_PER_BUFFER 24 81 #define PA_SAMPLE_TYPE paInt8 82 // portaudio globals 83 static PaStream * stream; 84 #endif 85 86 typedef struct wav_writer_state { 87 FILE * wav_file; 88 int total_num_samples; 89 int frame_count; 90 } wav_writer_state_t; 91 92 static int dump_data = 1; 93 94 static int phase = 0; 95 static int count_sent = 0; 96 static int count_received = 0; 97 static uint8_t negotiated_codec = 0; 98 static int num_audio_frames = 0; 99 100 FILE * msbc_file_in; 101 FILE * msbc_file_out; 102 103 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 104 105 // input signal: pre-computed sine wave, 160 Hz at 8 kHz 106 static const uint8_t sine[] = { 107 0, 15, 31, 46, 61, 74, 86, 97, 107, 114, 108 120, 124, 126, 126, 124, 120, 114, 107, 97, 86, 109 74, 61, 46, 31, 15, 0, 241, 225, 210, 195, 110 182, 170, 159, 149, 142, 136, 132, 130, 130, 132, 111 136, 142, 149, 159, 170, 182, 195, 210, 225, 241, 112 }; 113 114 // input signal: pre-computed sine wave, 160 Hz at 16000 kHz 115 static const int16_t sine_int16[] = { 116 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 117 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 118 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 119 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 120 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 121 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 122 -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 123 -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 124 -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 125 -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 126 }; 127 128 #ifdef SCO_WAV_FILENAME 129 130 static int num_samples_to_write; 131 static wav_writer_state_t wav_writer_state; 132 133 static btstack_sbc_decoder_state_t decoder_state; 134 static btstack_cvsd_plc_state_t cvsd_plc_state; 135 136 static void little_endian_fstore_16(FILE * file, uint16_t value){ 137 uint8_t buf[2]; 138 little_endian_store_32(buf, 0, value); 139 fwrite(&buf, 1, 2, file); 140 } 141 142 static void little_endian_fstore_32(FILE * file, uint32_t value){ 143 uint8_t buf[4]; 144 little_endian_store_32(buf, 0, value); 145 fwrite(&buf, 1, 4, file); 146 } 147 148 static FILE * wav_init(const char * filename){ 149 FILE * f = fopen(filename, "wb"); 150 printf("SCO Demo: creating wav file %s, %p\n", filename, f); 151 return f; 152 } 153 154 static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){ 155 /* write RIFF header */ 156 fwrite("RIFF", 1, 4, file); 157 // num_samples = blocks * subbands 158 uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels); 159 little_endian_fstore_32(file, data_bytes + 36); 160 fwrite("WAVE", 1, 4, file); 161 162 int byte_rate = sample_rate * num_channels * bytes_per_sample; 163 int bits_per_sample = 8 * bytes_per_sample; 164 int block_align = num_channels * bits_per_sample; 165 int fmt_length = 16; 166 int fmt_format_tag = 1; // PCM 167 168 /* write fmt chunk */ 169 fwrite("fmt ", 1, 4, file); 170 little_endian_fstore_32(file, fmt_length); 171 little_endian_fstore_16(file, fmt_format_tag); 172 little_endian_fstore_16(file, num_channels); 173 little_endian_fstore_32(file, sample_rate); 174 little_endian_fstore_32(file, byte_rate); 175 little_endian_fstore_16(file, block_align); 176 little_endian_fstore_16(file, bits_per_sample); 177 178 /* write data chunk */ 179 fwrite("data", 1, 4, file); 180 little_endian_fstore_32(file, data_bytes); 181 } 182 183 static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){ 184 fwrite(data, num_samples, 1, file); 185 } 186 187 static void write_wav_data_int16(FILE * file, int num_samples, int16_t * data){ 188 fwrite(data, num_samples, 2, file); 189 } 190 191 static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 192 log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write); 193 if (!num_samples_to_write) return; 194 195 wav_writer_state_t * writer_state = (wav_writer_state_t*) context; 196 num_samples = btstack_min(num_samples, num_samples_to_write); 197 num_samples_to_write -= num_samples; 198 199 write_wav_data_int16(writer_state->wav_file, num_samples, data); 200 writer_state->total_num_samples+=num_samples; 201 writer_state->frame_count++; 202 203 if (num_samples_to_write == 0){ 204 sco_demo_close(); 205 } 206 } 207 208 static void sco_demo_fill_audio_frame(void){ 209 if (!hfp_msbc_can_encode_audio_frame_now()) return; 210 int i; 211 int16_t sample_buffer[8*16*2]; 212 for (i=0; i < hfp_msbc_num_audio_samples_per_frame(); i++){ 213 sample_buffer[i] = sine_int16[phase++]; 214 if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){ 215 phase = 0; 216 } 217 } 218 hfp_msbc_encode_audio_frame(sample_buffer); 219 num_audio_frames++; 220 } 221 222 static void sco_demo_init_mSBC(void){ 223 wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME); 224 wav_writer_state.frame_count = 0; 225 wav_writer_state.total_num_samples = 0; 226 227 btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, (void*)&wav_writer_state); 228 229 const int sample_rate = 16000; 230 const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 231 const int bytes_per_sample = 2; 232 const int num_channels = 1; 233 num_samples_to_write = num_samples; 234 235 write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample); 236 237 hfp_msbc_init(); 238 sco_demo_fill_audio_frame(); 239 240 #ifdef SCO_MSBC_IN_FILENAME 241 msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb"); 242 printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in); 243 #endif 244 #ifdef SCO_MSBC_OUT_FILENAME 245 msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb"); 246 printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out); 247 #endif 248 } 249 250 static void sco_demo_init_CVSD(void){ 251 btstack_cvsd_plc_init(&cvsd_plc_state); 252 wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME); 253 wav_writer_state.frame_count = 0; 254 wav_writer_state.total_num_samples = 0; 255 256 const int sample_rate = 8000; 257 const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS; 258 const int num_channels = 1; 259 const int bytes_per_sample = 1; 260 num_samples_to_write = num_samples; 261 write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample); 262 } 263 264 static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 265 if (num_samples_to_write){ 266 if (msbc_file_in){ 267 // log incoming mSBC data for testing 268 fwrite(packet+3, size-3, 1, msbc_file_in); 269 } 270 btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 271 dump_data = 0; 272 } 273 } 274 275 static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 276 if (num_samples_to_write){ 277 const int num_samples = size - 3; 278 const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 279 int8_t audio_frame_out[24]; 280 281 memcpy(audio_frame_out, (int8_t*)(packet+3), 24); 282 // btstack_cvsd_plc_process_data(&cvsd_plc_state, (int8_t *)(packet+3),num_samples,audio_frame_out); 283 284 // convert 8 bit signed to 8 bit unsigned 285 int i; 286 for (i=0;i<samples_to_write;i++){ 287 audio_frame_out[i] += 128; 288 } 289 290 wav_writer_state_t * writer_state = &wav_writer_state; 291 write_wav_data_uint8(writer_state->wav_file, samples_to_write, (uint8_t*)audio_frame_out); 292 num_samples_to_write -= samples_to_write; 293 if (num_samples_to_write == 0){ 294 sco_demo_close(); 295 } 296 dump_data = 0; 297 298 // convert back 299 for (i=0;i<samples_to_write;i++){ 300 audio_frame_out[i] += 128; 301 } 302 } 303 } 304 305 #endif 306 #endif 307 308 void sco_demo_close(void){ 309 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 310 #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 311 printf("SCO demo statistics: "); 312 if (negotiated_codec == HFP_CODEC_MSBC){ 313 printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr); 314 } else { 315 printf("Used CVSD with PLC, number of proccesed frames: \n - %d good frames, \n - %d bad frames.", cvsd_plc_state.good_frames_nr, cvsd_plc_state.bad_frames_nr); 316 } 317 #endif 318 #endif 319 320 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 321 #ifdef SCO_WAV_FILENAME 322 323 #if 0 324 printf("SCO Demo: closing wav file\n"); 325 if (negotiated_codec == HFP_CODEC_MSBC){ 326 wav_writer_state_t * writer_state = &wav_writer_state; 327 if (!writer_state->wav_file) return; 328 rewind(writer_state->wav_file); 329 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); 330 fclose(writer_state->wav_file); 331 writer_state->wav_file = NULL; 332 } 333 #endif 334 #endif 335 #endif 336 } 337 338 void sco_demo_set_codec(uint8_t codec){ 339 if (negotiated_codec == codec) return; 340 negotiated_codec = codec; 341 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 342 #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME) 343 if (negotiated_codec == HFP_CODEC_MSBC){ 344 sco_demo_init_mSBC(); 345 } else { 346 sco_demo_init_CVSD(); 347 } 348 #endif 349 #endif 350 } 351 352 void sco_demo_init(void){ 353 354 // status 355 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 356 #ifdef HAVE_PORTAUDIO 357 printf("SCO Demo: Sending sine wave, audio output via portaudio.\n"); 358 #else 359 printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 360 #endif 361 #endif 362 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 363 printf("SCO Demo: Sending ASCII blocks, print received data.\n"); 364 #endif 365 #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER 366 printf("SCO Demo: Sending counter value, hexdump received data.\n"); 367 #endif 368 369 #ifdef USE_PORTAUDIO 370 int err; 371 PaStreamParameters outputParameters; 372 373 /* -- initialize PortAudio -- */ 374 err = Pa_Initialize(); 375 if( err != paNoError ) return; 376 /* -- setup input and output -- */ 377 outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 378 outputParameters.channelCount = NUM_CHANNELS; 379 outputParameters.sampleFormat = PA_SAMPLE_TYPE; 380 outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; 381 outputParameters.hostApiSpecificStreamInfo = NULL; 382 /* -- setup stream -- */ 383 err = Pa_OpenStream( 384 &stream, 385 NULL, // &inputParameters, 386 &outputParameters, 387 SAMPLE_RATE, 388 FRAMES_PER_BUFFER, 389 paClipOff, /* we won't output out of range samples so don't bother clipping them */ 390 NULL, /* no callback, use blocking API */ 391 NULL ); /* no callback, so no callback userData */ 392 if( err != paNoError ) return; 393 /* -- start stream -- */ 394 err = Pa_StartStream( stream ); 395 if( err != paNoError ) return; 396 #endif 397 398 #if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE 399 hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent 400 #endif 401 402 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 403 phase = 'a'; 404 #endif 405 } 406 407 static void sco_report(void){ 408 printf("SCO: sent %u, received %u\n", count_sent, count_received); 409 } 410 411 void sco_demo_send(hci_con_handle_t sco_handle){ 412 413 if (!sco_handle) return; 414 415 const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length(); 416 const int sco_payload_length = sco_packet_length - 3; 417 418 hci_reserve_packet_buffer(); 419 uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 420 // set handle + flags 421 little_endian_store_16(sco_packet, 0, sco_handle); 422 // set len 423 sco_packet[2] = sco_payload_length; 424 const int audio_samples_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2 425 426 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 427 if (negotiated_codec == HFP_CODEC_MSBC){ 428 429 if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 430 log_error("mSBC stream is empty."); 431 } 432 hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); 433 if (msbc_file_out){ 434 // log outgoing mSBC data for testing 435 fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); 436 } 437 438 sco_demo_fill_audio_frame(); 439 } else { 440 int i; 441 for (i=0;i<audio_samples_per_packet;i++){ 442 sco_packet[3+i] = sine[phase]; 443 phase++; 444 if (phase >= sizeof(sine)) phase = 0; 445 } 446 } 447 #else 448 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 449 memset(&sco_packet[3], phase++, audio_samples_per_packet); 450 if (phase > 'z') phase = 'a'; 451 #else 452 int j; 453 for (j=0;j<audio_samples_per_packet;j++){ 454 sco_packet[3+j] = phase++; 455 } 456 #endif 457 #endif 458 459 hci_send_sco_packet_buffer(sco_packet_length); 460 461 // request another send event 462 hci_request_sco_can_send_now_event(); 463 464 count_sent++; 465 if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); 466 } 467 468 /** 469 * @brief Process received data 470 */ 471 void sco_demo_receive(uint8_t * packet, uint16_t size){ 472 473 dump_data = 1; 474 475 count_received++; 476 // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report(); 477 478 479 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 480 #ifdef SCO_WAV_FILENAME 481 if (negotiated_codec == HFP_CODEC_MSBC){ 482 sco_demo_receive_mSBC(packet, size); 483 } else { 484 sco_demo_receive_CVSD(packet, size); 485 } 486 #endif 487 #endif 488 489 if (packet[1] & 0x30){ 490 printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 491 log_info("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4); 492 printf_hexdump(&packet[3], size-3); 493 494 return; 495 } 496 497 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 498 #ifdef USE_PORTAUDIO 499 uint32_t start = btstack_run_loop_get_time_ms(); 500 Pa_WriteStream( stream, &packet[3], size -3); 501 uint32_t end = btstack_run_loop_get_time_ms(); 502 if (end - start > 5){ 503 printf("Portaudio: write stream took %u ms\n", end - start); 504 } 505 dump_data = 0; 506 #endif 507 #endif 508 509 if (dump_data){ 510 printf("data: "); 511 #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII 512 int i; 513 for (i=3;i<size;i++){ 514 printf("%c", packet[i]); 515 } 516 printf("\n"); 517 dump_data = 0; 518 #else 519 printf_hexdump(&packet[3], size-3); 520 #endif 521 } 522 } 523