#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(deref_nullptr)]
#![allow(clippy::missing_safety_doc)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
pub use root::{webrtc::*, webrtc_audio_processing_wrapper::*};
use std::convert::TryInto;
impl StreamConfig {
pub fn new(sample_rate_hz: u32, num_channels: usize) -> StreamConfig {
unsafe {
create_stream_config(
sample_rate_hz.try_into().expect("sample rate fits i32"),
num_channels,
)
}
}
}
impl From<OptionalInt> for Option<i32> {
fn from(other: OptionalInt) -> Option<i32> {
if other.has_value {
Some(other.value)
} else {
None
}
}
}
impl From<OptionalDouble> for Option<f64> {
fn from(other: OptionalDouble) -> Option<f64> {
if other.has_value {
Some(other.value)
} else {
None
}
}
}
impl From<OptionalBool> for Option<bool> {
fn from(other: OptionalBool) -> Option<bool> {
if other.has_value {
Some(other.value)
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::ptr::null_mut;
const SAMPLE_RATE_HZ: i32 = 48_000;
fn config_with_all_enabled() -> AudioProcessing_Config {
AudioProcessing_Config {
pipeline: AudioProcessing_Config_Pipeline {
maximum_internal_processing_rate: SAMPLE_RATE_HZ,
..Default::default()
},
pre_amplifier: AudioProcessing_Config_PreAmplifier {
enabled: true,
..Default::default()
},
high_pass_filter: AudioProcessing_Config_HighPassFilter {
enabled: true,
..Default::default()
},
echo_canceller: AudioProcessing_Config_EchoCanceller {
enabled: true,
..Default::default()
},
noise_suppression: AudioProcessing_Config_NoiseSuppression {
enabled: true,
..Default::default()
},
transient_suppression: AudioProcessing_Config_TransientSuppression { enabled: true },
gain_controller1: AudioProcessing_Config_GainController1 {
enabled: true,
mode: AudioProcessing_Config_GainController1_Mode_kAdaptiveDigital,
analog_gain_controller:
AudioProcessing_Config_GainController1_AnalogGainController {
enabled: false,
..Default::default()
},
..Default::default()
},
gain_controller2: AudioProcessing_Config_GainController2 {
enabled: false,
..Default::default()
},
capture_level_adjustment: AudioProcessing_Config_CaptureLevelAdjustment {
enabled: false,
..Default::default()
},
}
}
fn assert_success(error: i32) {
assert!(error == 0, "code={}", error);
}
#[test]
fn test_create_delete() {
unsafe {
let mut error = 0;
let ap = create_audio_processing(null_mut(), &mut error);
assert!(!ap.is_null());
assert_success(error);
delete_audio_processing(ap);
}
}
#[test]
fn test_config() {
unsafe {
let mut error = 0;
let ap = create_audio_processing(null_mut(), &mut error);
assert!(!ap.is_null());
assert_success(error);
let config = AudioProcessing_Config::default();
set_config(ap, &config);
let config = config_with_all_enabled();
set_config(ap, &config);
delete_audio_processing(ap);
}
}
#[test]
fn test_process() {
unsafe {
let mut error = 0;
let ap = create_audio_processing(null_mut(), &mut error);
assert!(!ap.is_null());
assert_success(error);
let config = config_with_all_enabled();
set_config(ap, &config);
let stream_config = create_stream_config(SAMPLE_RATE_HZ, 1);
let num_samples = stream_config.num_frames_; let mut frame = vec![vec![0f32; num_samples as usize]; 1];
let frame_ptr = frame.iter_mut().map(|v| v.as_mut_ptr()).collect::<Vec<*mut f32>>();
assert_success(process_render_frame(ap, &stream_config, frame_ptr.as_ptr()));
assert_success(process_capture_frame(ap, &stream_config, frame_ptr.as_ptr()));
delete_audio_processing(ap);
}
}
#[test]
fn test_empty_stats() {
unsafe {
let mut error = 0;
let ap = create_audio_processing(null_mut(), &mut error);
assert!(!ap.is_null());
assert_success(error);
let stats = get_stats(ap);
println!("Stats:\n{:#?}", stats);
assert!(!stats.voice_detected.has_value);
assert!(!stats.echo_return_loss.has_value);
assert!(!stats.echo_return_loss_enhancement.has_value);
assert!(!stats.divergent_filter_fraction.has_value);
assert!(!stats.delay_median_ms.has_value);
assert!(!stats.delay_standard_deviation_ms.has_value);
assert!(!stats.residual_echo_likelihood.has_value);
assert!(!stats.residual_echo_likelihood_recent_max.has_value);
assert!(!stats.delay_ms.has_value);
delete_audio_processing(ap);
}
}
#[test]
fn test_some_stats() {
unsafe {
let mut error = 0;
let ap = create_audio_processing(null_mut(), &mut error);
assert!(!ap.is_null());
assert_success(error);
let config = config_with_all_enabled();
set_config(ap, &config);
let stream_config = create_stream_config(SAMPLE_RATE_HZ, 1);
let num_samples = stream_config.num_frames_; let mut frame = vec![vec![0f32; num_samples as usize]; 1];
let frame_ptr = frame.iter_mut().map(|v| v.as_mut_ptr()).collect::<Vec<*mut f32>>();
assert_success(process_render_frame(ap, &stream_config, frame_ptr.as_ptr()));
assert_success(process_capture_frame(ap, &stream_config, frame_ptr.as_ptr()));
let stats = get_stats(ap);
println!("Stats:\n{:#?}", stats);
assert!(stats.echo_return_loss.has_value);
assert!(stats.echo_return_loss_enhancement.has_value);
assert!(stats.delay_ms.has_value);
assert!(!stats.divergent_filter_fraction.has_value);
assert!(!stats.delay_median_ms.has_value);
assert!(!stats.delay_standard_deviation_ms.has_value);
delete_audio_processing(ap);
}
}
}