void sco_demo_send(hci_con_handle_t sco_handle){ if (!sco_handle) return; const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length(); const int sco_payload_length = sco_packet_length - 3; hci_reserve_packet_buffer(); uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); // set handle + flags little_endian_store_16(sco_packet, 0, sco_handle); // set len sco_packet[2] = sco_payload_length; const int frames_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE int i; for (i=0;i<frames_per_packet;i++){ sco_packet[3+i] = sine[phase]; phase++; if (phase >= sizeof(sine)) phase = 0; } #else #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII memset(&sco_packet[3], phase++, frames_per_packet); if (phase > 'z') phase = 'a'; #else int j; for (j=0;j<frames_per_packet;j++){ sco_packet[3+j] = phase++; } #endif #endif hci_send_sco_packet_buffer(sco_packet_length); // request another send event hci_request_sco_can_send_now_event(); count_sent++; if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); }
void sco_demo_send(hci_con_handle_t sco_handle){ if (!sco_handle) return; int sco_packet_length = hci_get_sco_packet_length(); int sco_payload_length = sco_packet_length - 3; hci_reserve_packet_buffer(); uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE #ifdef ENABLE_HFP_WIDE_BAND_SPEECH if (negotiated_codec == HFP_CODEC_MSBC){ // overwrite sco_payload_length = 24; sco_packet_length = sco_payload_length + 3; if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ log_error("mSBC stream is empty."); } hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); if (msbc_file_out){ // log outgoing mSBC data for testing fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); } sco_demo_msbc_fill_sine_audio_frame(); } else #endif { const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME; sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]); } #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE #ifdef HAVE_PORTAUDIO if (negotiated_codec == HFP_CODEC_MSBC){ // MSBC // overwrite sco_payload_length = 24; sco_packet_length = sco_payload_length + 3; if (pa_input_paused){ if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ // resume sending pa_input_paused = 0; } } if (!pa_input_paused){ int num_samples = hfp_msbc_num_audio_samples_per_frame(); if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){ int16_t sample_buffer[num_samples]; uint32_t bytes_read; btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read); hfp_msbc_encode_audio_frame(sample_buffer); num_audio_frames++; } } if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ log_error("mSBC stream should not be empty."); memset(sco_packet + 3, 0, sco_payload_length); pa_input_paused = 1; } else { hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); if (msbc_file_out){ // log outgoing mSBC data for testing fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); } } } else { // CVSD log_info("send: bytes avail %u, free %u, counter %u", btstack_ring_buffer_bytes_available(&pa_input_ring_buffer), btstack_ring_buffer_bytes_free(&pa_input_ring_buffer), pa_input_counter); // fill with silence while paused int bytes_to_copy = sco_payload_length; if (pa_input_paused){ if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ // resume sending pa_input_paused = 0; } } // get data from ringbuffer uint16_t pos = 0; uint8_t * sample_data = &sco_packet[3]; if (!pa_input_paused){ uint32_t bytes_read = 0; btstack_ring_buffer_read(&pa_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read); // flip 16 on big endian systems // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems if (btstack_is_big_endian()){ int i; for (i=0;i<bytes_read;i+=2){ uint8_t tmp = sample_data[i*2]; sample_data[i*2] = sample_data[i*2+1]; sample_data[i*2+1] = tmp; } } bytes_to_copy -= bytes_read; pos += bytes_read; } // fill with 0 if not enough if (bytes_to_copy){ memset(sample_data + pos, 0, bytes_to_copy); pa_input_paused = 1; } } #else // just send '0's if (negotiated_codec == HFP_CODEC_MSBC){ sco_payload_length = 24; sco_packet_length = sco_payload_length + 3; } memset(sco_packet + 3, 0, sco_payload_length); #endif #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII memset(&sco_packet[3], phase++, sco_payload_length); if (phase > 'z') phase = 'a'; #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER int j; for (j=0;j<sco_payload_length;j++){ sco_packet[3+j] = phase++; } #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 int j; for (j=0;j<sco_payload_length;j++){ // sco_packet[3+j] = j & 1 ? 0x35 : 0x53; sco_packet[3+j] = 0x55; } #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_00 int j; for (j=0;j<sco_payload_length;j++){ sco_packet[3+j] = 0x00; } // additional hack // big_endian_store_16(sco_packet, 5, phase++); (void) phase; #endif // test silence // memset(sco_packet+3, 0, sco_payload_length); // set handle + flags little_endian_store_16(sco_packet, 0, sco_handle); // set len sco_packet[2] = sco_payload_length; // finally send packet hci_send_sco_packet_buffer(sco_packet_length); // request another send event hci_request_sco_can_send_now_event(); count_sent++; #if SCO_DEMO_MODE != SCO_DEMO_MODE_55 if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); #endif }