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