sonora-aec3 0.1.0

Echo Canceller 3 (AEC3) — Rust port of WebRTC's modern echo canceller
Documentation
//! ERLE (Echo Return Loss Enhancement) estimator coordinator.
//!
//! Combines fullband, subband, and optionally signal-dependent ERLE estimators.
//!
//! Ported from `modules/audio_processing/aec3/erle_estimator.h/cc`.

use crate::common::FFT_LENGTH_BY_2_PLUS_1;
use crate::config::EchoCanceller3Config;
use crate::fullband_erle_estimator::FullBandErleEstimator;
use crate::render_buffer::RenderBuffer;
use crate::signal_dependent_erle_estimator::{ErleUpdateContext, SignalDependentErleEstimator};
use crate::subband_erle_estimator::SubbandErleEstimator;

/// Estimates the echo return loss enhancement. One estimate is done per subband
/// and another one is done using the aggregation of energy over all subbands.
#[derive(Debug)]
pub(crate) struct ErleEstimator {
    startup_phase_length_blocks: usize,
    fullband_erle_estimator: FullBandErleEstimator,
    subband_erle_estimator: SubbandErleEstimator,
    signal_dependent_erle_estimator: Option<SignalDependentErleEstimator>,
    blocks_since_reset: usize,
}

impl ErleEstimator {
    pub(crate) fn new(
        startup_phase_length_blocks: usize,
        config: &EchoCanceller3Config,
        num_capture_channels: usize,
    ) -> Self {
        let signal_dependent = if config.erle.num_sections > 1 {
            Some(SignalDependentErleEstimator::new(
                config,
                num_capture_channels,
            ))
        } else {
            None
        };

        let mut s = Self {
            startup_phase_length_blocks,
            fullband_erle_estimator: FullBandErleEstimator::new(&config.erle, num_capture_channels),
            subband_erle_estimator: SubbandErleEstimator::new(config, num_capture_channels),
            signal_dependent_erle_estimator: signal_dependent,
            blocks_since_reset: 0,
        };
        s.reset(true);
        s
    }

    /// Resets the fullband ERLE estimator and the subband ERLE estimators.
    pub(crate) fn reset(&mut self, delay_change: bool) {
        self.fullband_erle_estimator.reset();
        self.subband_erle_estimator.reset();
        if let Some(ref mut sd) = self.signal_dependent_erle_estimator {
            sd.reset();
        }
        if delay_change {
            self.blocks_since_reset = 0;
        }
    }

    /// Updates the ERLE estimates.
    pub(crate) fn update(
        &mut self,
        render_buffer: &RenderBuffer<'_>,
        filter_frequency_responses: &[Vec<[f32; FFT_LENGTH_BY_2_PLUS_1]>],
        x2_reverb: &[f32; FFT_LENGTH_BY_2_PLUS_1],
        y2: &[[f32; FFT_LENGTH_BY_2_PLUS_1]],
        e2: &[[f32; FFT_LENGTH_BY_2_PLUS_1]],
        converged_filters: &[bool],
    ) {
        self.blocks_since_reset += 1;
        if self.blocks_since_reset < self.startup_phase_length_blocks {
            return;
        }

        self.subband_erle_estimator
            .update(x2_reverb, y2, e2, converged_filters);

        if let Some(ref mut sd) = self.signal_dependent_erle_estimator {
            sd.update(&ErleUpdateContext {
                render_buffer,
                filter_frequency_responses,
                x2: x2_reverb,
                y2,
                e2,
                average_erle: self.subband_erle_estimator.erle(false),
                average_erle_onset_compensated: self.subband_erle_estimator.erle(true),
                converged_filters,
            });
        }

        self.fullband_erle_estimator
            .update(x2_reverb, y2, e2, converged_filters);
    }

    /// Returns the most recent subband ERLE estimates.
    pub(crate) fn erle(&self, onset_compensated: bool) -> &[[f32; FFT_LENGTH_BY_2_PLUS_1]] {
        if let Some(ref sd) = self.signal_dependent_erle_estimator {
            sd.erle(onset_compensated)
        } else {
            self.subband_erle_estimator.erle(onset_compensated)
        }
    }

    /// Returns the non-capped subband ERLE.
    pub(crate) fn erle_unbounded(&self) -> &[[f32; FFT_LENGTH_BY_2_PLUS_1]] {
        if let Some(ref est) = self.signal_dependent_erle_estimator {
            est.erle(false)
        } else {
            self.subband_erle_estimator.erle_unbounded()
        }
    }

    /// Returns the fullband ERLE estimate in log2 units.
    pub(crate) fn fullband_erle_log2(&self) -> f32 {
        self.fullband_erle_estimator.fullband_erle_log2()
    }

    /// Returns an estimation of the current linear filter quality.
    pub(crate) fn get_inst_linear_quality_estimates(&self) -> &[Option<f32>] {
        self.fullband_erle_estimator
            .get_inst_linear_quality_estimates()
    }
}