| Index: webrtc/modules/audio_processing/aec/aec_core.cc
|
| diff --git a/webrtc/modules/audio_processing/aec/aec_core.cc b/webrtc/modules/audio_processing/aec/aec_core.cc
|
| index e23a79312b05beb9c7904c103c605a5d454b3e69..138d2f769ee18f8e4fe6a7f352d1e117cd8a949e 100644
|
| --- a/webrtc/modules/audio_processing/aec/aec_core.cc
|
| +++ b/webrtc/modules/audio_processing/aec/aec_core.cc
|
| @@ -18,6 +18,7 @@
|
| #include <stdio.h>
|
| #endif
|
|
|
| +#include <algorithm>
|
| #include <assert.h>
|
| #include <math.h>
|
| #include <stddef.h> // size_t
|
| @@ -50,6 +51,12 @@ static const size_t kSubCountLen = 4;
|
| static const size_t kCountLen = 50;
|
| static const int kDelayMetricsAggregationWindow = 1250; // 5 seconds at 16 kHz.
|
|
|
| +// Divergence metric is based on audio level, which gets updated every
|
| +// |kCountLen + 1| * 10 milliseconds. Divergence metric takes the statistics of
|
| +// |kDivergentFilterFractionAggregationWindowSize| samples. Current value
|
| +// corresponds to 0.5 seconds at 16 kHz.
|
| +static const int kDivergentFilterFractionAggregationWindowSize = 25;
|
| +
|
| // Quantities to control H band scaling for SWB input
|
| static const float cnScaleHband = 0.4f; // scale for comfort noise in H band.
|
| // Initial bin for averaging nlp gain in low band
|
| @@ -150,12 +157,55 @@ __inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
|
| return aRe * bIm + aIm * bRe;
|
| }
|
|
|
| -PowerLevel::PowerLevel()
|
| // TODO(minyue): Due to a legacy bug, |framelevel| and |averagelevel| use a
|
| -// window, of which the length is 1 unit longer than indicated. Remove "+1"
|
| -// when the code is refactored.
|
| -: framelevel(kSubCountLen + 1),
|
| - averagelevel(kCountLen + 1) {
|
| +// window, of which the length is 1 unit longer than indicated. Remove "+1" when
|
| +// the code is refactored.
|
| +PowerLevel::PowerLevel()
|
| + : framelevel(kSubCountLen + 1),
|
| + averagelevel(kCountLen + 1) {
|
| +}
|
| +
|
| +DivergentFilterFraction::DivergentFilterFraction()
|
| + : count_(0),
|
| + occurrence_(0),
|
| + fraction_(-1.0) {
|
| +}
|
| +
|
| +void DivergentFilterFraction::Reset() {
|
| + Clear();
|
| + fraction_ = -1.0;
|
| +}
|
| +
|
| +void DivergentFilterFraction::AddObservation(const PowerLevel& nearlevel,
|
| + const PowerLevel& linoutlevel,
|
| + const PowerLevel& nlpoutlevel) {
|
| + const float near_level = nearlevel.framelevel.GetLatestMean();
|
| + const float level_increase =
|
| + linoutlevel.framelevel.GetLatestMean() - near_level;
|
| + const bool output_signal_active = nlpoutlevel.framelevel.GetLatestMean() >
|
| + 40.0 * nlpoutlevel.minlevel;
|
| + // Level increase should be, in principle, negative, when the filter
|
| + // does not diverge. Here we allow some margin (0.01 * near end level) and
|
| + // numerical error (1.0). We count divergence only when the AEC output
|
| + // signal is active.
|
| + if (output_signal_active &&
|
| + level_increase > std::max(0.01 * near_level, 1.0))
|
| + occurrence_++;
|
| + ++count_;
|
| + if (count_ == kDivergentFilterFractionAggregationWindowSize) {
|
| + fraction_ = static_cast<float>(occurrence_) /
|
| + kDivergentFilterFractionAggregationWindowSize;
|
| + Clear();
|
| + }
|
| +}
|
| +
|
| +float DivergentFilterFraction::GetLatestFraction() const {
|
| + return fraction_;
|
| +}
|
| +
|
| +void DivergentFilterFraction::Clear() {
|
| + count_ = 0;
|
| + occurrence_ = 0;
|
| }
|
|
|
| // TODO(minyue): Moving some initialization from WebRtcAec_CreateAec() to ctor.
|
| @@ -562,6 +612,8 @@ static void InitMetrics(AecCore* self) {
|
| InitStats(&self->erle);
|
| InitStats(&self->aNlp);
|
| InitStats(&self->rerl);
|
| +
|
| + self->divergent_filter_fraction.Reset();
|
| }
|
|
|
| static float CalculatePower(const float* in, size_t num_samples) {
|
| @@ -605,6 +657,12 @@ static void UpdateMetrics(AecCore* aec) {
|
| aec->stateCounter++;
|
| }
|
|
|
| + if (aec->linoutlevel.framelevel.EndOfBlock()) {
|
| + aec->divergent_filter_fraction.AddObservation(aec->nearlevel,
|
| + aec->linoutlevel,
|
| + aec->nlpoutlevel);
|
| + }
|
| +
|
| if (aec->farlevel.averagelevel.EndOfBlock()) {
|
| if (aec->farlevel.minlevel < noisyPower) {
|
| actThreshold = actThresholdClean;
|
|
|