webrtc-audio-processing-sys 0.4.0

A wrapper for WebRTC's AudioProcessing module.
Documentation
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

impl Into<Option<bool>> for OptionalBool {
    fn into(self) -> Option<bool> {
        if self.has_value {
            Some(self.value)
        } else {
            None
        }
    }
}

impl From<Option<bool>> for OptionalBool {
    fn from(other: Option<bool>) -> OptionalBool {
        if let Some(value) = other {
            OptionalBool { has_value: true, value }
        } else {
            OptionalBool { has_value: false, value: false }
        }
    }
}

impl Into<Option<i32>> for OptionalInt {
    fn into(self) -> Option<i32> {
        if self.has_value {
            Some(self.value)
        } else {
            None
        }
    }
}

impl From<Option<i32>> for OptionalInt {
    fn from(other: Option<i32>) -> OptionalInt {
        if let Some(value) = other {
            OptionalInt { has_value: true, value }
        } else {
            OptionalInt { has_value: false, value: 0 }
        }
    }
}

impl Into<Option<f64>> for OptionalDouble {
    fn into(self) -> Option<f64> {
        if self.has_value {
            Some(self.value)
        } else {
            None
        }
    }
}

impl From<Option<f64>> for OptionalDouble {
    fn from(other: Option<f64>) -> OptionalDouble {
        if let Some(value) = other {
            OptionalDouble { has_value: true, value }
        } else {
            OptionalDouble { has_value: false, value: 0.0 }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn init_config_with_all_enabled() -> InitializationConfig {
        InitializationConfig {
            num_capture_channels: 1,
            num_render_channels: 1,
            enable_experimental_agc: true,
            enable_intelligibility_enhancer: true,
        }
    }

    fn config_with_all_enabled() -> Config {
        Config {
            echo_cancellation: EchoCancellation {
                enable: true,
                suppression_level: EchoCancellation_SuppressionLevel::HIGH,
            },
            gain_control: GainControl {
                enable: true,
                target_level_dbfs: 3,
                compression_gain_db: 3,
                enable_limiter: true,
            },
            noise_suppression: NoiseSuppression {
                enable: true,
                suppression_level: NoiseSuppression_SuppressionLevel::HIGH,
            },
            voice_detection: VoiceDetection {
                enable: true,
                detection_likelihood: VoiceDetection_DetectionLikelihood::HIGH,
            },
            enable_extended_filter: true,
            enable_delay_agnostic: true,
            enable_transient_suppressor: true,
            enable_high_pass_filter: true,
        }
    }

    #[test]
    fn test_create_failure() {
        unsafe {
            let config = InitializationConfig::default();
            let mut error = 0;
            let ap = audio_processing_create(&config, &mut error);
            assert!(ap.is_null());
            assert!(!is_success(error));
        }
    }

    #[test]
    fn test_create_delete() {
        unsafe {
            let config = InitializationConfig {
                num_capture_channels: 1,
                num_render_channels: 1,
                ..InitializationConfig::default()
            };
            let mut error = 0;
            let ap = audio_processing_create(&config, &mut error);
            assert!(!ap.is_null());
            assert!(is_success(error));
            audio_processing_delete(ap);
        }
    }

    #[test]
    fn test_config() {
        unsafe {
            let mut error = 0;
            let ap = audio_processing_create(&init_config_with_all_enabled(), &mut error);
            assert!(!ap.is_null());
            assert!(is_success(error));

            let config = Config::default();
            set_config(ap, &config);

            let config = config_with_all_enabled();
            set_config(ap, &config);

            audio_processing_delete(ap);
        }
    }

    #[test]
    fn test_process() {
        unsafe {
            let mut error = 0;
            let ap = audio_processing_create(&init_config_with_all_enabled(), &mut error);
            assert!(!ap.is_null());
            assert!(is_success(error));

            let config = config_with_all_enabled();
            set_config(ap, &config);

            let mut frame = vec![vec![0f32; NUM_SAMPLES_PER_FRAME as usize]; 1];
            let mut frame_ptr = frame.iter_mut().map(|v| v.as_mut_ptr()).collect::<Vec<*mut f32>>();
            assert!(is_success(process_render_frame(ap, frame_ptr.as_mut_ptr())));
            assert!(is_success(process_capture_frame(ap, frame_ptr.as_mut_ptr())));

            audio_processing_delete(ap);
        }
    }

    #[test]
    fn test_empty_stats() {
        unsafe {
            let config = InitializationConfig {
                num_capture_channels: 1,
                num_render_channels: 1,
                ..InitializationConfig::default()
            };
            let mut error = 0;
            let ap = audio_processing_create(&config, &mut error);
            assert!(!ap.is_null());
            assert!(is_success(error));

            let stats = get_stats(ap);
            println!("Stats:\n{:#?}", stats);
            assert!(!stats.has_voice.has_value);
            assert!(!stats.has_echo.has_value);
            assert!(!stats.rms_dbfs.has_value);
            assert!(!stats.speech_probability.has_value);
            assert!(!stats.residual_echo_return_loss.has_value);
            assert!(!stats.echo_return_loss.has_value);
            assert!(!stats.echo_return_loss_enhancement.has_value);
            assert!(!stats.a_nlp.has_value);
            assert!(!stats.delay_median_ms.has_value);
            assert!(!stats.delay_standard_deviation_ms.has_value);
            assert!(!stats.delay_fraction_poor_delays.has_value);

            audio_processing_delete(ap);
        }
    }

    #[test]
    fn test_some_stats() {
        unsafe {
            let mut error = 0;
            let ap = audio_processing_create(&init_config_with_all_enabled(), &mut error);
            assert!(!ap.is_null());
            assert!(is_success(error));

            let config = config_with_all_enabled();
            set_config(ap, &config);

            let mut frame = vec![vec![0f32; NUM_SAMPLES_PER_FRAME as usize]; 1];
            let mut frame_ptr = frame.iter_mut().map(|v| v.as_mut_ptr()).collect::<Vec<*mut f32>>();
            assert!(is_success(process_render_frame(ap, frame_ptr.as_mut_ptr())));
            assert!(is_success(process_capture_frame(ap, frame_ptr.as_mut_ptr())));
            let stats = get_stats(ap);
            println!("Stats:\n{:#?}", stats);
            assert!(stats.has_voice.has_value);
            assert!(stats.has_echo.has_value);
            assert!(stats.rms_dbfs.has_value);
            assert!(stats.speech_probability.has_value);
            assert!(stats.residual_echo_return_loss.has_value);
            assert!(stats.echo_return_loss.has_value);
            assert!(stats.echo_return_loss_enhancement.has_value);
            assert!(stats.a_nlp.has_value);
            assert!(stats.delay_median_ms.has_value);
            assert!(stats.delay_standard_deviation_ms.has_value);
            assert!(stats.delay_fraction_poor_delays.has_value);

            audio_processing_delete(ap);
        }
    }
}