| 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 1b5f03fec4e7a255f25c681218bbb7470ebc0770..e0d0baef3a732e158b6b73f8438b76c40c3a0c79 100644
 | 
| --- a/webrtc/modules/audio_processing/aec/aec_core.cc
 | 
| +++ b/webrtc/modules/audio_processing/aec/aec_core.cc
 | 
| @@ -46,8 +46,8 @@ namespace webrtc {
 | 
|  static const size_t kBufSizePartitions = 250;  // 1 second of audio in 16 kHz.
 | 
|  
 | 
|  // Metrics
 | 
| -static const int subCountLen = 4;
 | 
| -static const int countLen = 50;
 | 
| +static const size_t kSubCountLen = 4;
 | 
| +static const size_t kCountLen = 50;
 | 
|  static const int kDelayMetricsAggregationWindow = 1250;  // 5 seconds at 16 kHz.
 | 
|  
 | 
|  // Quantities to control H band scaling for SWB input
 | 
| @@ -150,6 +150,17 @@ __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) {
 | 
| +}
 | 
| +
 | 
| +// TODO(minyue): Moving some initialization from WebRtcAec_CreateAec() to ctor.
 | 
| +AecCore::AecCore() = default;
 | 
| +
 | 
|  static int CmpFloat(const void* a, const void* b) {
 | 
|    const float* da = (const float*)a;
 | 
|    const float* db = (const float*)b;
 | 
| @@ -523,14 +534,9 @@ static void ComfortNoise(AecCore* aec,
 | 
|  
 | 
|  static void InitLevel(PowerLevel* level) {
 | 
|    const float kBigFloat = 1E17f;
 | 
| -
 | 
| -  level->averagelevel = 0;
 | 
| -  level->framelevel = 0;
 | 
| +  level->averagelevel.Reset();
 | 
| +  level->framelevel.Reset();
 | 
|    level->minlevel = kBigFloat;
 | 
| -  level->frsum = 0;
 | 
| -  level->sfrsum = 0;
 | 
| -  level->frcounter = 0;
 | 
| -  level->sfrcounter = 0;
 | 
|  }
 | 
|  
 | 
|  static void InitStats(Stats* stats) {
 | 
| @@ -568,28 +574,18 @@ static float CalculatePower(const float* in, size_t num_samples) {
 | 
|    return energy / num_samples;
 | 
|  }
 | 
|  
 | 
| -static void UpdateLevel(PowerLevel* level, float energy) {
 | 
| -  level->sfrsum += energy;
 | 
| -  level->sfrcounter++;
 | 
| -
 | 
| -  if (level->sfrcounter > subCountLen) {
 | 
| -    level->framelevel = level->sfrsum / (subCountLen * PART_LEN);
 | 
| -    level->sfrsum = 0;
 | 
| -    level->sfrcounter = 0;
 | 
| -    if (level->framelevel > 0) {
 | 
| -      if (level->framelevel < level->minlevel) {
 | 
| -        level->minlevel = level->framelevel;  // New minimum.
 | 
| +static void UpdateLevel(PowerLevel* level, float power) {
 | 
| +  level->framelevel.AddSample(power);
 | 
| +  if (level->framelevel.SamplesSinceLastUpdate() == 0) {
 | 
| +    const float new_frame_level = level->framelevel.GetLatestMean();
 | 
| +    if (new_frame_level > 0) {
 | 
| +      if (new_frame_level < level->minlevel) {
 | 
| +        level->minlevel = new_frame_level;  // New minimum.
 | 
|        } else {
 | 
|          level->minlevel *= (1 + 0.001f);  // Small increase.
 | 
|        }
 | 
|      }
 | 
| -    level->frcounter++;
 | 
| -    level->frsum += level->framelevel;
 | 
| -    if (level->frcounter > countLen) {
 | 
| -      level->averagelevel = level->frsum / countLen;
 | 
| -      level->frsum = 0;
 | 
| -      level->frcounter = 0;
 | 
| -    }
 | 
| +    level->averagelevel.AddSample(new_frame_level);
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -600,11 +596,7 @@ static void UpdateMetrics(AecCore* aec) {
 | 
|    const float actThresholdClean = 40.0f;
 | 
|    const float safety = 0.99995f;
 | 
|  
 | 
| -  // To make noisePower consistent with the legacy code, a factor of
 | 
| -  // 2.0f / PART_LEN2 is applied to noisyPower, since the legacy code uses
 | 
| -  // the energy of a frame as the audio levels, while the new code uses a
 | 
| -  // a per-sample energy (i.e., power).
 | 
| -  const float noisyPower = 300000.0f * 2.0f / PART_LEN2;
 | 
| +  const float noisyPower = 300000.0f;
 | 
|  
 | 
|    float actThreshold;
 | 
|    float echo, suppressedEcho;
 | 
| @@ -613,29 +605,34 @@ static void UpdateMetrics(AecCore* aec) {
 | 
|      aec->stateCounter++;
 | 
|    }
 | 
|  
 | 
| -  if (aec->farlevel.frcounter == 0) {
 | 
| +  if (aec->farlevel.averagelevel.SamplesSinceLastUpdate() == 0) {
 | 
| +    const float far_average_level = aec->farlevel.averagelevel.GetLatestMean();
 | 
| +
 | 
|      if (aec->farlevel.minlevel < noisyPower) {
 | 
|        actThreshold = actThresholdClean;
 | 
|      } else {
 | 
|        actThreshold = actThresholdNoisy;
 | 
|      }
 | 
|  
 | 
| -    if ((aec->stateCounter > (0.5f * countLen * subCountLen)) &&
 | 
| -        (aec->farlevel.sfrcounter == 0)
 | 
| -
 | 
| +    if ((aec->stateCounter > (0.5f * kCountLen * kSubCountLen)) &&
 | 
| +        (aec->farlevel.framelevel.SamplesSinceLastUpdate() == 0)
 | 
|          // Estimate in active far-end segments only
 | 
| -        && (aec->farlevel.averagelevel >
 | 
| -            (actThreshold * aec->farlevel.minlevel))) {
 | 
| +        && (far_average_level > (actThreshold * aec->farlevel.minlevel))) {
 | 
| +
 | 
| +      const float near_average_level =
 | 
| +          aec->nearlevel.averagelevel.GetLatestMean();
 | 
| +      const float linout_average_level =
 | 
| +          aec->linoutlevel.averagelevel.GetLatestMean();
 | 
| +      const float nlpout_average_level =
 | 
| +          aec->nlpoutlevel.averagelevel.GetLatestMean();
 | 
| +
 | 
|        // Subtract noise power
 | 
| -      echo = aec->nearlevel.averagelevel - safety * aec->nearlevel.minlevel;
 | 
| +      echo = near_average_level - safety * aec->nearlevel.minlevel;
 | 
|  
 | 
|        // ERL
 | 
| -      dtmp = 10 * static_cast<float>(log10(aec->farlevel.averagelevel /
 | 
| -                                           aec->nearlevel.averagelevel +
 | 
| -                                           1e-10f));
 | 
| -      dtmp2 = 10 * static_cast<float>(log10(aec->farlevel.averagelevel /
 | 
| -                                            echo +
 | 
| -                                            1e-10f));
 | 
| +      dtmp = 10 * static_cast<float>(log10(far_average_level /
 | 
| +                                           near_average_level + 1e-10f));
 | 
| +      dtmp2 = 10 * static_cast<float>(log10(far_average_level / echo + 1e-10f));
 | 
|  
 | 
|        aec->erl.instant = dtmp;
 | 
|        if (dtmp > aec->erl.max) {
 | 
| @@ -658,13 +655,12 @@ static void UpdateMetrics(AecCore* aec) {
 | 
|        }
 | 
|  
 | 
|        // A_NLP
 | 
| -      dtmp = 10 * static_cast<float>(log10(aec->nearlevel.averagelevel /
 | 
| -                                           aec->linoutlevel.averagelevel +
 | 
| -                                           1e-10f));
 | 
| +      dtmp = 10 * static_cast<float>(log10(near_average_level /
 | 
| +                                           linout_average_level + 1e-10f));
 | 
|  
 | 
|        // subtract noise power
 | 
| -      suppressedEcho = aec->linoutlevel.averagelevel -
 | 
| -          safety * aec->linoutlevel.minlevel;
 | 
| +      suppressedEcho =
 | 
| +          linout_average_level - safety * aec->linoutlevel.minlevel;
 | 
|  
 | 
|        dtmp2 = 10 * static_cast<float>(log10(echo / suppressedEcho + 1e-10f));
 | 
|  
 | 
| @@ -691,11 +687,11 @@ static void UpdateMetrics(AecCore* aec) {
 | 
|        // ERLE
 | 
|  
 | 
|        // subtract noise power
 | 
| -      suppressedEcho = aec->nlpoutlevel.averagelevel -
 | 
| -          safety * aec->nlpoutlevel.minlevel;
 | 
| +      suppressedEcho =
 | 
| +          nlpout_average_level - safety * aec->nlpoutlevel.minlevel;
 | 
|  
 | 
| -      dtmp = 10 * static_cast<float>(log10(aec->nearlevel.averagelevel /
 | 
| -          aec->nlpoutlevel.averagelevel + 1e-10f));
 | 
| +      dtmp = 10 * static_cast<float>(log10(near_average_level /
 | 
| +                                           nlpout_average_level + 1e-10f));
 | 
|        dtmp2 = 10 * static_cast<float>(log10(echo / suppressedEcho + 1e-10f));
 | 
|  
 | 
|        dtmp = dtmp2;
 | 
| @@ -1365,7 +1361,7 @@ static void ProcessBlock(AecCore* aec) {
 | 
|  
 | 
|  AecCore* WebRtcAec_CreateAec() {
 | 
|    int i;
 | 
| -  AecCore* aec = reinterpret_cast<AecCore*>(malloc(sizeof(AecCore)));
 | 
| +  AecCore* aec = new AecCore;
 | 
|    if (!aec) {
 | 
|      return NULL;
 | 
|    }
 | 
| 
 |