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 BLUEKITCHEN 24 * GMBH 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 #define BTSTACK_FILE__ "sco_demo_util.c" 39 40 /* 41 * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo 42 */ 43 44 #include <stdio.h> 45 46 #include "sco_demo_util.h" 47 48 #include "btstack_audio.h" 49 #include "btstack_debug.h" 50 #include "btstack_ring_buffer.h" 51 #include "classic/btstack_cvsd_plc.h" 52 #include "classic/btstack_sbc.h" 53 #include "classic/hfp.h" 54 #include "classic/hfp_msbc.h" 55 56 #ifdef _MSC_VER 57 // ignore deprecated warning for fopen 58 #pragma warning(disable : 4996) 59 #endif 60 61 #ifdef HAVE_POSIX_FILE_IO 62 #include "wav_util.h" 63 #endif 64 65 // test modes 66 #define SCO_DEMO_MODE_SINE 0 67 #define SCO_DEMO_MODE_MICROPHONE 1 68 69 // SCO demo configuration 70 #define SCO_DEMO_MODE SCO_DEMO_MODE_MICROPHONE 71 72 // number of sco packets until 'report' on console 73 #define SCO_REPORT_PERIOD 100 74 75 76 #ifdef HAVE_POSIX_FILE_IO 77 // length and name of wav file on disk 78 #define SCO_WAV_DURATION_IN_SECONDS 15 79 #define SCO_WAV_FILENAME "sco_input.wav" 80 #endif 81 82 83 // pre-buffer for CVSD and mSBC - also defines latency 84 #define SCO_CVSD_PA_PREBUFFER_MS 50 85 #define SCO_MSBC_PA_PREBUFFER_MS 50 86 87 // constants 88 #define NUM_CHANNELS 1 89 #define CVSD_SAMPLE_RATE 8000 90 #define MSBC_SAMPLE_RATE 16000 91 #define BYTES_PER_FRAME 2 92 93 #define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * BYTES_PER_FRAME) 94 #define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * BYTES_PER_FRAME) 95 96 // output 97 static int audio_output_paused = 0; 98 static uint8_t audio_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES]; 99 static btstack_ring_buffer_t audio_output_ring_buffer; 100 101 // input 102 #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 103 #define USE_AUDIO_INPUT 104 #else 105 #define USE_ADUIO_GENERATOR 106 static void (*sco_demo_audio_generator)(uint16_t num_samples, int16_t * data); 107 #endif 108 static int audio_input_paused = 0; 109 static uint8_t audio_input_ring_buffer_storage[2*8000]; // full second input buffer 110 static btstack_ring_buffer_t audio_input_ring_buffer; 111 112 static int count_sent = 0; 113 static int count_received = 0; 114 static int negotiated_codec = -1; 115 116 #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 117 static btstack_sbc_decoder_state_t decoder_state; 118 #endif 119 120 static btstack_cvsd_plc_state_t cvsd_plc_state; 121 122 #define MAX_NUM_MSBC_SAMPLES (16*8) 123 124 int num_samples_to_write; 125 int num_audio_frames; 126 127 // sine generator 128 129 #ifdef USE_ADUIO_GENERATOR 130 static unsigned int phase; 131 132 // input signal: pre-computed sine wave, 266 Hz at 16000 kHz 133 static const int16_t sine_int16_at_16000hz[] = { 134 0, 3135, 6237, 9270, 12202, 14999, 17633, 20073, 22294, 24270, 135 25980, 27406, 28531, 29344, 29835, 30000, 29835, 29344, 28531, 27406, 136 25980, 24270, 22294, 20073, 17633, 14999, 12202, 9270, 6237, 3135, 137 0, -3135, -6237, -9270, -12202, -14999, -17633, -20073, -22294, -24270, 138 -25980, -27406, -28531, -29344, -29835, -30000, -29835, -29344, -28531, -27406, 139 -25980, -24270, -22294, -20073, -17633, -14999, -12202, -9270, -6237, -3135, 140 }; 141 142 // 8 kHz samples for CVSD/SCO packets in little endian 143 static void sco_demo_sine_wave_int16_at_8000_hz_host_endian(uint16_t num_samples, int16_t * data){ 144 unsigned int i; 145 for (i=0; i < num_samples; i++){ 146 data[i] = sine_int16_at_16000hz[phase]; 147 // ony use every second sample from 16khz table to get 8khz 148 phase += 2; 149 if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 150 phase = 0; 151 } 152 } 153 } 154 155 // 16 kHz samples for mSBC encoder in host endianess 156 #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 157 static void sco_demo_sine_wave_int16_at_16000_hz_host_endian(uint16_t num_samples, int16_t * data){ 158 unsigned int i; 159 for (i=0; i < num_samples; i++){ 160 data[i] = sine_int16_at_16000hz[phase++]; 161 if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ 162 phase = 0; 163 } 164 } 165 } 166 #endif 167 #endif 168 169 // Audio Playback / Recording 170 171 static void audio_playback_callback(int16_t * buffer, uint16_t num_samples){ 172 173 uint32_t prebuffer_bytes; 174 switch (negotiated_codec){ 175 case HFP_CODEC_MSBC: 176 prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES; 177 break; 178 case HFP_CODEC_CVSD: 179 default: 180 prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES; 181 break; 182 } 183 184 // fill with silence while paused 185 if (audio_output_paused){ 186 if (btstack_ring_buffer_bytes_available(&audio_output_ring_buffer) < prebuffer_bytes){ 187 memset(buffer, 0, num_samples * BYTES_PER_FRAME); 188 return; 189 } else { 190 // resume playback 191 audio_output_paused = 0; 192 } 193 } 194 195 // get data from ringbuffer 196 uint32_t bytes_read = 0; 197 btstack_ring_buffer_read(&audio_output_ring_buffer, (uint8_t *) buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 198 num_samples -= bytes_read / BYTES_PER_FRAME; 199 buffer += bytes_read / BYTES_PER_FRAME; 200 201 // fill with 0 if not enough 202 if (num_samples){ 203 memset(buffer, 0, num_samples * BYTES_PER_FRAME); 204 audio_output_paused = 1; 205 } 206 } 207 208 #ifdef USE_AUDIO_INPUT 209 static void audio_recording_callback(const int16_t * buffer, uint16_t num_samples){ 210 btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)buffer, num_samples * 2); 211 } 212 #endif 213 214 // return 1 if ok 215 static int audio_initialize(int sample_rate){ 216 217 // -- output -- // 218 219 // init buffers 220 memset(audio_output_ring_buffer_storage, 0, sizeof(audio_output_ring_buffer_storage)); 221 btstack_ring_buffer_init(&audio_output_ring_buffer, audio_output_ring_buffer_storage, sizeof(audio_output_ring_buffer_storage)); 222 223 // config and setup audio playback 224 const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 225 if (!audio_sink) return 0; 226 227 audio_sink->init(1, sample_rate, &audio_playback_callback); 228 audio_sink->start_stream(); 229 230 audio_output_paused = 1; 231 232 // -- input -- // 233 234 // init buffers 235 memset(audio_input_ring_buffer_storage, 0, sizeof(audio_input_ring_buffer_storage)); 236 btstack_ring_buffer_init(&audio_input_ring_buffer, audio_input_ring_buffer_storage, sizeof(audio_input_ring_buffer_storage)); 237 audio_input_paused = 1; 238 239 #ifdef USE_AUDIO_INPUT 240 // config and setup audio recording 241 const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance(); 242 if (!audio_source) return 0; 243 244 audio_source->init(1, sample_rate, &audio_recording_callback); 245 audio_source->start_stream(); 246 #endif 247 248 return 1; 249 } 250 251 static void audio_terminate(void){ 252 const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance(); 253 if (!audio_sink) return; 254 audio_sink->close(); 255 256 #ifdef USE_AUDIO_INPUT 257 const btstack_audio_source_t * audio_source= btstack_audio_source_get_instance(); 258 if (!audio_source) return; 259 audio_source->close(); 260 #endif 261 } 262 263 264 // CVSD - 8 kHz 265 266 static void sco_demo_init_CVSD(void){ 267 printf("SCO Demo: Init CVSD\n"); 268 269 btstack_cvsd_plc_init(&cvsd_plc_state); 270 271 #ifdef SCO_WAV_FILENAME 272 num_samples_to_write = CVSD_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 273 wav_writer_open(SCO_WAV_FILENAME, 1, CVSD_SAMPLE_RATE); 274 #endif 275 276 audio_initialize(CVSD_SAMPLE_RATE); 277 } 278 279 static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ 280 281 int16_t audio_frame_out[128]; // 282 283 if (size > sizeof(audio_frame_out)){ 284 printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); 285 return; 286 } 287 288 const int audio_bytes_read = size - 3; 289 const int num_samples = audio_bytes_read / BYTES_PER_FRAME; 290 291 // convert into host endian 292 int16_t audio_frame_in[128]; 293 int i; 294 for (i=0;i<num_samples;i++){ 295 audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); 296 } 297 298 // treat packet as bad frame if controller does not report 'all good' 299 bool bad_frame = (packet[1] & 0x30) != 0; 300 301 btstack_cvsd_plc_process_data(&cvsd_plc_state, bad_frame, audio_frame_in, num_samples, audio_frame_out); 302 303 #ifdef SCO_WAV_FILENAME 304 // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) 305 const int samples_to_write = btstack_min(num_samples, num_samples_to_write); 306 wav_writer_write_le_int16(samples_to_write, audio_frame_out); 307 num_samples_to_write -= samples_to_write; 308 if (num_samples_to_write == 0){ 309 wav_writer_close(); 310 } 311 #endif 312 313 btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); 314 } 315 316 void sco_demo_fill_payload_CVSD(uint8_t * payload_buffer, uint16_t sco_payload_length){ 317 318 #ifdef USE_ADUIO_GENERATOR 319 #define REFILL_SAMPLES 16 320 // re-fill with sine 321 uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2; 322 while (samples_free > 0){ 323 int16_t samples_buffer[REFILL_SAMPLES]; 324 uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES); 325 (*sco_demo_audio_generator)(samples_to_add, samples_buffer); 326 btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2); 327 samples_free -= samples_to_add; 328 } 329 #endif 330 331 // resume if pre-buffer is filled 332 if (audio_input_paused){ 333 if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ 334 // resume sending 335 audio_input_paused = 0; 336 } 337 } 338 339 uint16_t bytes_to_copy = sco_payload_length; 340 341 // get data from ringbuffer 342 uint16_t pos = 0; 343 if (!audio_input_paused){ 344 uint16_t samples_to_copy = sco_payload_length / 2; 345 uint32_t bytes_read = 0; 346 btstack_ring_buffer_read(&audio_input_ring_buffer, payload_buffer, bytes_to_copy, &bytes_read); 347 // flip 16 on big endian systems 348 // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems 349 if (btstack_is_big_endian()){ 350 uint16_t i; 351 for (i=0;i<samples_to_copy/2;i+=2){ 352 uint8_t tmp = payload_buffer[i*2]; 353 payload_buffer[i*2] = payload_buffer[i*2+1]; 354 payload_buffer[i*2+1] = tmp; 355 } 356 } 357 bytes_to_copy -= bytes_read; 358 pos += bytes_read; 359 } 360 361 // fill with 0 if not enough 362 if (bytes_to_copy){ 363 memset(payload_buffer + pos, 0, bytes_to_copy); 364 audio_input_paused = 1; 365 } 366 } 367 368 // mSBC - 16 kHz 369 370 #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 371 372 static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 373 UNUSED(context); 374 UNUSED(sample_rate); 375 UNUSED(data); 376 UNUSED(num_samples); 377 UNUSED(num_channels); 378 379 // samples in callback in host endianess, ready for playback 380 btstack_ring_buffer_write(&audio_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); 381 382 #ifdef SCO_WAV_FILENAME 383 if (!num_samples_to_write) return; 384 num_samples = btstack_min(num_samples, num_samples_to_write); 385 num_samples_to_write -= num_samples; 386 wav_writer_write_int16(num_samples, data); 387 if (num_samples_to_write == 0){ 388 wav_writer_close(); 389 } 390 #endif /* SCO_WAV_FILENAME */ 391 } 392 393 static void sco_demo_init_mSBC(void){ 394 printf("SCO Demo: Init mSBC\n"); 395 396 btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL); 397 hfp_msbc_init(); 398 399 #ifdef SCO_WAV_FILENAME 400 num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS; 401 wav_writer_open(SCO_WAV_FILENAME, 1, MSBC_SAMPLE_RATE); 402 #endif 403 404 audio_initialize(MSBC_SAMPLE_RATE); 405 } 406 407 static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){ 408 btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3); 409 } 410 411 void sco_demo_fill_payload_mSBC(uint8_t * payload_buffer, uint16_t sco_payload_length){ 412 413 #ifdef USE_ADUIO_GENERATOR 414 #define REFILL_SAMPLES 16 415 // re-fill with sine 416 uint16_t samples_free = btstack_ring_buffer_bytes_free(&audio_input_ring_buffer) / 2; 417 while (samples_free > 0){ 418 int16_t samples_buffer[REFILL_SAMPLES]; 419 uint16_t samples_to_add = btstack_min(samples_free, REFILL_SAMPLES); 420 (*sco_demo_audio_generator)(samples_to_add, samples_buffer); 421 btstack_ring_buffer_write(&audio_input_ring_buffer, (uint8_t *)samples_buffer, samples_to_add * 2); 422 samples_free -= samples_to_add; 423 } 424 #endif 425 426 // resume if pre-buffer is filled 427 if (audio_input_paused){ 428 if (btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ 429 // resume sending 430 audio_input_paused = 0; 431 } 432 } 433 if (!audio_input_paused){ 434 int num_samples = hfp_msbc_num_audio_samples_per_frame(); 435 btstack_assert(num_samples <= MAX_NUM_MSBC_SAMPLES); 436 if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&audio_input_ring_buffer) >= (unsigned int)(num_samples * BYTES_PER_FRAME)){ 437 int16_t sample_buffer[MAX_NUM_MSBC_SAMPLES]; 438 uint32_t bytes_read; 439 btstack_ring_buffer_read(&audio_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * BYTES_PER_FRAME, &bytes_read); 440 hfp_msbc_encode_audio_frame(sample_buffer); 441 num_audio_frames++; 442 } 443 btstack_assert(hfp_msbc_num_bytes_in_stream() >= sco_payload_length); 444 } 445 446 // get data from encoder, fill with 0 if not enough 447 if (audio_input_paused || hfp_msbc_num_bytes_in_stream() < sco_payload_length){ 448 // just send '0's 449 memset(payload_buffer, 0, sco_payload_length); 450 audio_input_paused = 1; 451 } else { 452 hfp_msbc_read_from_stream(payload_buffer, sco_payload_length); 453 } 454 } 455 456 #endif /* ENABLE_HFP_WIDE_BAND_SPEECH */ 457 458 void sco_demo_init(void){ 459 460 #ifdef ENABLE_CLASSIC_LEGACY_CONNECTIONS_FOR_SCO_DEMOS 461 printf("Disable BR/EDR Secure Connctions due to incompatibilities with SCO connections\n"); 462 gap_secure_connections_enable(false); 463 #endif 464 465 // status 466 #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE 467 printf("SCO Demo: Sending and receiving audio via btstack_audio.\n"); 468 #endif 469 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE 470 if (btstack_audio_sink_get_instance()){ 471 printf("SCO Demo: Sending sine wave, audio output via btstack_audio.\n"); 472 } else { 473 printf("SCO Demo: Sending sine wave, hexdump received data.\n"); 474 } 475 #endif 476 477 // Set SCO for CVSD (mSBC or other codecs automatically use 8-bit transparent mode) 478 hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD 479 } 480 481 void sco_demo_set_codec(uint8_t codec){ 482 if (negotiated_codec == codec) return; 483 negotiated_codec = codec; 484 485 switch (negotiated_codec){ 486 case HFP_CODEC_CVSD: 487 #ifdef USE_ADUIO_GENERATOR 488 sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_8000_hz_host_endian; 489 #endif 490 sco_demo_init_CVSD(); 491 break; 492 #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 493 case HFP_CODEC_MSBC: 494 #ifdef USE_ADUIO_GENERATOR 495 sco_demo_audio_generator = &sco_demo_sine_wave_int16_at_16000_hz_host_endian; 496 #endif 497 sco_demo_init_mSBC(); 498 break; 499 #endif 500 default: 501 btstack_assert(false); 502 break; 503 } 504 } 505 506 void sco_demo_receive(uint8_t * packet, uint16_t size){ 507 static uint32_t packets = 0; 508 static uint32_t crc_errors = 0; 509 static uint32_t data_received = 0; 510 static uint32_t byte_errors = 0; 511 512 count_received++; 513 514 data_received += size - 3; 515 packets++; 516 if (data_received > 100000){ 517 printf("Summary: data %07u, packets %04u, packet with crc errors %0u, byte errors %04u\n", (unsigned int) data_received, (unsigned int) packets, (unsigned int) crc_errors, (unsigned int) byte_errors); 518 crc_errors = 0; 519 byte_errors = 0; 520 data_received = 0; 521 packets = 0; 522 } 523 524 switch (negotiated_codec){ 525 case HFP_CODEC_CVSD: 526 sco_demo_receive_CVSD(packet, size); 527 break; 528 #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 529 case HFP_CODEC_MSBC: 530 sco_demo_receive_mSBC(packet, size); 531 break; 532 #endif 533 default: 534 btstack_assert(false); 535 break; 536 } 537 } 538 539 void sco_demo_send(hci_con_handle_t sco_handle){ 540 541 if (sco_handle == HCI_CON_HANDLE_INVALID) return; 542 543 int sco_packet_length = hci_get_sco_packet_length(); 544 int sco_payload_length = sco_packet_length - 3; 545 546 hci_reserve_packet_buffer(); 547 uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); 548 549 switch (negotiated_codec){ 550 case HFP_CODEC_CVSD: 551 sco_demo_fill_payload_CVSD(&sco_packet[3], sco_payload_length); 552 break; 553 #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 554 case HFP_CODEC_MSBC: 555 sco_demo_fill_payload_mSBC(&sco_packet[3], sco_payload_length); 556 break; 557 #endif 558 default: 559 btstack_assert(false); 560 break; 561 } 562 563 // set handle + flags 564 little_endian_store_16(sco_packet, 0, sco_handle); 565 // set len 566 sco_packet[2] = sco_payload_length; 567 // finally send packet 568 hci_send_sco_packet_buffer(sco_packet_length); 569 570 // request another send event 571 hci_request_sco_can_send_now_event(); 572 573 count_sent++; 574 if ((count_sent % SCO_REPORT_PERIOD) == 0) { 575 printf("SCO: sent %u, received %u\n", count_sent, count_received); 576 } 577 } 578 579 void sco_demo_close(void){ 580 printf("SCO demo close\n"); 581 582 printf("SCO demo statistics: "); 583 switch (negotiated_codec){ 584 case HFP_CODEC_CVSD: 585 printf("Used CVSD with PLC, number of proccesed frames: \n - %d good frames, \n - %d bad frames.\n", cvsd_plc_state.good_frames_nr, cvsd_plc_state.bad_frames_nr); 586 break; 587 #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 588 case HFP_CODEC_MSBC: 589 printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.\n", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr); 590 break; 591 #endif 592 default: 593 btstack_assert(false); 594 break; 595 } 596 597 negotiated_codec = -1; 598 599 #if defined(SCO_WAV_FILENAME) 600 wav_writer_close(); 601 #endif 602 603 audio_terminate(); 604 } 605