webrtc_audio_processing/
config.rs

1use webrtc_audio_processing_sys as ffi;
2
3pub use ffi::InitializationConfig;
4
5#[cfg(feature = "derive_serde")]
6use serde::{Deserialize, Serialize};
7
8/// A level of non-linear suppression during AEC (aka NLP).
9#[derive(Debug, Copy, Clone, PartialEq)]
10#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
11pub enum EchoCancellationSuppressionLevel {
12    /// Lowest suppression level.
13    /// Minimum overdrive exponent = 1.0 (zero suppression).
14    Lowest,
15    /// Lower suppression level.
16    /// Minimum overdrive exponent = 2.0.
17    Lower,
18    /// Low suppression level.
19    /// Minimum overdrive exponent = 3.0.
20    Low,
21    /// Moderate suppression level.
22    /// Minimum overdrive exponent = 6.0.
23    Moderate,
24    /// Higher suppression level.
25    /// Minimum overdrive exponent = 15.0.
26    High,
27}
28
29impl From<EchoCancellationSuppressionLevel> for ffi::EchoCancellation_SuppressionLevel {
30    fn from(other: EchoCancellationSuppressionLevel) -> ffi::EchoCancellation_SuppressionLevel {
31        match other {
32            EchoCancellationSuppressionLevel::Lowest => {
33                ffi::EchoCancellation_SuppressionLevel::LOWEST
34            },
35            EchoCancellationSuppressionLevel::Lower => {
36                ffi::EchoCancellation_SuppressionLevel::LOWER
37            },
38            EchoCancellationSuppressionLevel::Low => ffi::EchoCancellation_SuppressionLevel::LOW,
39            EchoCancellationSuppressionLevel::Moderate => {
40                ffi::EchoCancellation_SuppressionLevel::MODERATE
41            },
42            EchoCancellationSuppressionLevel::High => ffi::EchoCancellation_SuppressionLevel::HIGH,
43        }
44    }
45}
46
47/// Echo cancellation configuration.
48#[derive(Debug, Clone, PartialEq)]
49#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
50pub struct EchoCancellation {
51    /// Determines the aggressiveness of the suppressor. A higher level trades off
52    /// double-talk performance for increased echo suppression.
53    pub suppression_level: EchoCancellationSuppressionLevel,
54
55    /// Use to enable the extended filter mode in the AEC, along with robustness
56    /// measures around the reported system delays. It comes with a significant
57    /// increase in AEC complexity, but is much more robust to unreliable reported
58    /// delays.
59    pub enable_extended_filter: bool,
60
61    /// Enables delay-agnostic echo cancellation. This feature relies on internally
62    /// estimated delays between the process and reverse streams, thus not relying
63    /// on reported system delays.
64    pub enable_delay_agnostic: bool,
65
66    /// Sets the delay in ms between process_render_frame() receiving a far-end
67    /// frame and process_capture_frame() receiving a near-end frame containing
68    /// the corresponding echo. You should set this only if you are certain that
69    /// the delay will be stable and constant. enable_delay_agnostic will be
70    /// ignored when this option is set.
71    pub stream_delay_ms: Option<i32>,
72}
73
74impl From<EchoCancellation> for ffi::EchoCancellation {
75    fn from(other: EchoCancellation) -> ffi::EchoCancellation {
76        ffi::EchoCancellation {
77            enable: true,
78            suppression_level: other.suppression_level.into(),
79            enable_extended_filter: other.enable_extended_filter,
80            enable_delay_agnostic: other.enable_delay_agnostic,
81            stream_delay_ms: other.stream_delay_ms.into(),
82        }
83    }
84}
85
86/// Mode of gain control.
87#[derive(Debug, Copy, Clone, PartialEq)]
88#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
89pub enum GainControlMode {
90    /// Bring the signal to an appropriate range by applying an adaptive gain
91    /// control. The volume is dynamically amplified with a microphone with
92    /// small pickup and vice versa.
93    AdaptiveDigital,
94
95    /// Unlike ADAPTIVE_DIGITAL, it only compresses (i.e. gradually reduces
96    /// gain with increasing level) the input signal when at higher levels.
97    /// Use this where the capture signal level is predictable, so that a
98    /// known gain can be applied.
99    FixedDigital,
100}
101
102impl From<GainControlMode> for ffi::GainControl_Mode {
103    fn from(other: GainControlMode) -> ffi::GainControl_Mode {
104        match other {
105            GainControlMode::AdaptiveDigital => ffi::GainControl_Mode::ADAPTIVE_DIGITAL,
106            GainControlMode::FixedDigital => ffi::GainControl_Mode::FIXED_DIGITAL,
107        }
108    }
109}
110
111/// Gain control configuration.
112#[derive(Debug, Clone, PartialEq)]
113#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
114pub struct GainControl {
115    /// Determines what type of gain control is applied.
116    pub mode: GainControlMode,
117
118    /// Sets the target peak level (or envelope) of the AGC in dBFs (decibels from
119    /// digital full-scale). The convention is to use positive values.
120    /// For instance, passing in a value of 3 corresponds to -3 dBFs, or a target
121    /// level 3 dB below full-scale. Limited to [0, 31].
122    pub target_level_dbfs: i32,
123
124    /// Sets the maximum gain the digital compression stage may apply, in dB. A
125    /// higher number corresponds to greater compression, while a value of 0 will
126    /// leave the signal uncompressed. Limited to [0, 90].
127    pub compression_gain_db: i32,
128
129    /// When enabled, the compression stage will hard limit the signal to the
130    /// target level. Otherwise, the signal will be compressed but not limited
131    /// above the target level.
132    pub enable_limiter: bool,
133}
134
135impl From<GainControl> for ffi::GainControl {
136    fn from(other: GainControl) -> ffi::GainControl {
137        ffi::GainControl {
138            enable: true,
139            mode: other.mode.into(),
140            target_level_dbfs: other.target_level_dbfs,
141            compression_gain_db: other.compression_gain_db,
142            enable_limiter: other.enable_limiter,
143        }
144    }
145}
146
147/// A level of noise suppression.
148#[derive(Debug, Copy, Clone, PartialEq)]
149#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
150pub enum NoiseSuppressionLevel {
151    /// Lower suppression level.
152    Low,
153    /// Moderate suppression level.
154    Moderate,
155    /// Higher suppression level.
156    High,
157    /// Even higher suppression level.
158    VeryHigh,
159}
160
161impl From<NoiseSuppressionLevel> for ffi::NoiseSuppression_SuppressionLevel {
162    fn from(other: NoiseSuppressionLevel) -> ffi::NoiseSuppression_SuppressionLevel {
163        match other {
164            NoiseSuppressionLevel::Low => ffi::NoiseSuppression_SuppressionLevel::LOW,
165            NoiseSuppressionLevel::Moderate => ffi::NoiseSuppression_SuppressionLevel::MODERATE,
166            NoiseSuppressionLevel::High => ffi::NoiseSuppression_SuppressionLevel::HIGH,
167            NoiseSuppressionLevel::VeryHigh => ffi::NoiseSuppression_SuppressionLevel::VERY_HIGH,
168        }
169    }
170}
171
172/// Noise suppression configuration.
173#[derive(Debug, Clone, PartialEq)]
174#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
175pub struct NoiseSuppression {
176    /// Determines the aggressiveness of the suppression. Increasing the level will
177    /// reduce the noise level at the expense of a higher speech distortion.
178    pub suppression_level: NoiseSuppressionLevel,
179}
180
181impl From<NoiseSuppression> for ffi::NoiseSuppression {
182    fn from(other: NoiseSuppression) -> ffi::NoiseSuppression {
183        ffi::NoiseSuppression { enable: true, suppression_level: other.suppression_level.into() }
184    }
185}
186
187/// The sensitivity of the noise detector.
188#[derive(Debug, Copy, Clone, PartialEq)]
189#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
190pub enum VoiceDetectionLikelihood {
191    /// Even lower detection likelihood.
192    VeryLow,
193    /// Lower detection likelihood.
194    Low,
195    /// Moderate detection likelihood.
196    Moderate,
197    /// Higher detection likelihood.
198    High,
199}
200
201impl From<VoiceDetectionLikelihood> for ffi::VoiceDetection_DetectionLikelihood {
202    fn from(other: VoiceDetectionLikelihood) -> ffi::VoiceDetection_DetectionLikelihood {
203        match other {
204            VoiceDetectionLikelihood::VeryLow => ffi::VoiceDetection_DetectionLikelihood::VERY_LOW,
205            VoiceDetectionLikelihood::Low => ffi::VoiceDetection_DetectionLikelihood::LOW,
206            VoiceDetectionLikelihood::Moderate => ffi::VoiceDetection_DetectionLikelihood::MODERATE,
207            VoiceDetectionLikelihood::High => ffi::VoiceDetection_DetectionLikelihood::HIGH,
208        }
209    }
210}
211
212/// Voice detection configuration.
213#[derive(Debug, Clone, PartialEq)]
214#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
215pub struct VoiceDetection {
216    /// Specifies the likelihood that a frame will be declared to contain voice. A
217    /// higher value makes it more likely that speech will not be clipped, at the
218    /// expense of more noise being detected as voice.
219    pub detection_likelihood: VoiceDetectionLikelihood,
220}
221
222impl From<VoiceDetection> for ffi::VoiceDetection {
223    fn from(other: VoiceDetection) -> ffi::VoiceDetection {
224        ffi::VoiceDetection {
225            enable: true,
226            detection_likelihood: other.detection_likelihood.into(),
227        }
228    }
229}
230
231/// Config that can be used mid-processing.
232#[derive(Debug, Default, Clone, PartialEq)]
233#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
234pub struct Config {
235    /// Enable and configure AEC (acoustic echo cancellation).
236    pub echo_cancellation: Option<EchoCancellation>,
237
238    /// Enable and configure AGC (automatic gain control).
239    pub gain_control: Option<GainControl>,
240
241    /// Enable and configure noise suppression.
242    pub noise_suppression: Option<NoiseSuppression>,
243
244    /// Enable and configure voice detection.
245    pub voice_detection: Option<VoiceDetection>,
246
247    /// Use to enable experimental transient noise suppression.
248    #[cfg_attr(feature = "derive_serde", serde(default))]
249    pub enable_transient_suppressor: bool,
250
251    /// Use to enable a filtering component which removes DC offset and
252    /// low-frequency noise.
253    #[cfg_attr(feature = "derive_serde", serde(default))]
254    pub enable_high_pass_filter: bool,
255}
256
257impl From<Config> for ffi::Config {
258    fn from(other: Config) -> ffi::Config {
259        let echo_cancellation = if let Some(enabled_value) = other.echo_cancellation {
260            enabled_value.into()
261        } else {
262            ffi::EchoCancellation { enable: false, ..ffi::EchoCancellation::default() }
263        };
264
265        let gain_control = if let Some(enabled_value) = other.gain_control {
266            enabled_value.into()
267        } else {
268            ffi::GainControl { enable: false, ..ffi::GainControl::default() }
269        };
270
271        let noise_suppression = if let Some(enabled_value) = other.noise_suppression {
272            enabled_value.into()
273        } else {
274            ffi::NoiseSuppression { enable: false, ..ffi::NoiseSuppression::default() }
275        };
276
277        let voice_detection = if let Some(enabled_value) = other.voice_detection {
278            enabled_value.into()
279        } else {
280            ffi::VoiceDetection { enable: false, ..ffi::VoiceDetection::default() }
281        };
282
283        ffi::Config {
284            echo_cancellation,
285            gain_control,
286            noise_suppression,
287            voice_detection,
288            enable_transient_suppressor: other.enable_transient_suppressor,
289            enable_high_pass_filter: other.enable_high_pass_filter,
290        }
291    }
292}
293
294/// Statistics about the processor state.
295#[derive(Debug, Clone)]
296#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
297pub struct Stats {
298    /// True if voice is detected in the current frame.
299    pub has_voice: Option<bool>,
300
301    /// False if the current frame almost certainly contains no echo and true if it
302    /// _might_ contain echo.
303    pub has_echo: Option<bool>,
304
305    /// Root mean square (RMS) level in dBFs (decibels from digital full-scale), or
306    /// alternately dBov. It is computed over all primary stream frames since the
307    /// last call to |get_stats()|. The returned value is constrained to [-127, 0],
308    /// where -127 indicates muted.
309    pub rms_dbfs: Option<i32>,
310
311    /// Prior speech probability of the current frame averaged over output
312    /// channels, internally computed by noise suppressor.
313    pub speech_probability: Option<f64>,
314
315    /// RERL = ERL + ERLE
316    pub residual_echo_return_loss: Option<f64>,
317
318    /// ERL = 10log_10(P_far / P_echo)
319    pub echo_return_loss: Option<f64>,
320
321    /// ERLE = 10log_10(P_echo / P_out)
322    pub echo_return_loss_enhancement: Option<f64>,
323
324    /// (Pre non-linear processing suppression) A_NLP = 10log_10(P_echo / P_a)
325    pub a_nlp: Option<f64>,
326
327    /// Median of the measured delay in ms. The values are aggregated until the
328    /// first call to |get_stats()| and afterwards aggregated and updated every
329    /// second.
330    pub delay_median_ms: Option<i32>,
331
332    /// Standard deviation of the measured delay in ms. The values are aggregated
333    /// until the first call to |get_stats()| and afterwards aggregated and updated
334    /// every second.
335    pub delay_standard_deviation_ms: Option<i32>,
336
337    /// The fraction of delay estimates that can make the echo cancellation perform
338    /// poorly.
339    pub delay_fraction_poor_delays: Option<f64>,
340}
341
342impl From<ffi::Stats> for Stats {
343    fn from(other: ffi::Stats) -> Stats {
344        Stats {
345            has_voice: other.has_voice.into(),
346            has_echo: other.has_echo.into(),
347            rms_dbfs: other.rms_dbfs.into(),
348            speech_probability: other.speech_probability.into(),
349            residual_echo_return_loss: other.residual_echo_return_loss.into(),
350            echo_return_loss: other.echo_return_loss.into(),
351            echo_return_loss_enhancement: other.echo_return_loss_enhancement.into(),
352            a_nlp: other.a_nlp.into(),
353            delay_median_ms: other.delay_median_ms.into(),
354            delay_standard_deviation_ms: other.delay_standard_deviation_ms.into(),
355            delay_fraction_poor_delays: other.delay_fraction_poor_delays.into(),
356        }
357    }
358}