LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_processing/aec - aec_core.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 988 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 73 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : /*
      12             :  * The core AEC algorithm, which is presented with time-aligned signals.
      13             :  */
      14             : 
      15             : #include "webrtc/modules/audio_processing/aec/aec_core.h"
      16             : 
      17             : #include <algorithm>
      18             : #include <math.h>
      19             : #include <stddef.h>  // size_t
      20             : #include <stdlib.h>
      21             : #include <string.h>
      22             : 
      23             : #include "webrtc/base/checks.h"
      24             : extern "C" {
      25             : #include "webrtc/common_audio/ring_buffer.h"
      26             : }
      27             : #include "webrtc/base/checks.h"
      28             : #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
      29             : #include "webrtc/modules/audio_processing/aec/aec_common.h"
      30             : #include "webrtc/modules/audio_processing/aec/aec_core_optimized_methods.h"
      31             : #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h"
      32             : #include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
      33             : #include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
      34             : #include "webrtc/system_wrappers/include/metrics.h"
      35             : #include "webrtc/typedefs.h"
      36             : 
      37             : namespace webrtc {
      38             : namespace {
      39             : enum class DelaySource {
      40             :   kSystemDelay,    // The delay values come from the OS.
      41             :   kDelayAgnostic,  // The delay values come from the DA-AEC.
      42             : };
      43             : 
      44             : constexpr int kMinDelayLogValue = -200;
      45             : constexpr int kMaxDelayLogValue = 200;
      46             : constexpr int kNumDelayLogBuckets = 100;
      47             : 
      48           0 : void MaybeLogDelayAdjustment(int moved_ms, DelaySource source) {
      49           0 :   if (moved_ms == 0)
      50           0 :     return;
      51           0 :   switch (source) {
      52             :     case DelaySource::kSystemDelay:
      53           0 :       RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AecDelayAdjustmentMsSystemValue",
      54             :                            moved_ms, kMinDelayLogValue, kMaxDelayLogValue,
      55             :                            kNumDelayLogBuckets);
      56           0 :       return;
      57             :     case DelaySource::kDelayAgnostic:
      58           0 :       RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AecDelayAdjustmentMsAgnosticValue",
      59             :                            moved_ms, kMinDelayLogValue, kMaxDelayLogValue,
      60             :                            kNumDelayLogBuckets);
      61           0 :       return;
      62             :   }
      63             : }
      64             : }  // namespace
      65             : 
      66             : // Buffer size (samples)
      67             : static const size_t kBufferSizeBlocks = 250;  // 1 second of audio in 16 kHz.
      68             : 
      69             : // Metrics
      70             : static const size_t kSubCountLen = 4;
      71             : static const size_t kCountLen = 50;
      72             : static const int kDelayMetricsAggregationWindow = 1250;  // 5 seconds at 16 kHz.
      73             : 
      74             : // Divergence metric is based on audio level, which gets updated every
      75             : // |kSubCountLen + 1| * PART_LEN samples. Divergence metric takes the statistics
      76             : // of |kDivergentFilterFractionAggregationWindowSize| audio levels. The
      77             : // following value corresponds to 1 second at 16 kHz.
      78             : static const int kDivergentFilterFractionAggregationWindowSize = 50;
      79             : 
      80             : // Quantities to control H band scaling for SWB input
      81             : static const float cnScaleHband = 0.4f;  // scale for comfort noise in H band.
      82             : // Initial bin for averaging nlp gain in low band
      83             : static const int freqAvgIc = PART_LEN / 2;
      84             : 
      85             : // Matlab code to produce table:
      86             : // win = sqrt(hanning(63)); win = [0 ; win(1:32)];
      87             : // fprintf(1, '\t%.14f, %.14f, %.14f,\n', win);
      88             : ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65] = {
      89             :     0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
      90             :     0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
      91             :     0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
      92             :     0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
      93             :     0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
      94             :     0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
      95             :     0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
      96             :     0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
      97             :     0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
      98             :     0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
      99             :     0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
     100             :     0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
     101             :     0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
     102             :     0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
     103             :     0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
     104             :     0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
     105             :     1.00000000000000f};
     106             : 
     107             : // Matlab code to produce table:
     108             : // weightCurve = [0 ; 0.3 * sqrt(linspace(0,1,64))' + 0.1];
     109             : // fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', weightCurve);
     110             : ALIGN16_BEG const float ALIGN16_END WebRtcAec_weightCurve[65] = {
     111             :     0.0000f, 0.1000f, 0.1378f, 0.1535f, 0.1655f, 0.1756f, 0.1845f, 0.1926f,
     112             :     0.2000f, 0.2069f, 0.2134f, 0.2195f, 0.2254f, 0.2309f, 0.2363f, 0.2414f,
     113             :     0.2464f, 0.2512f, 0.2558f, 0.2604f, 0.2648f, 0.2690f, 0.2732f, 0.2773f,
     114             :     0.2813f, 0.2852f, 0.2890f, 0.2927f, 0.2964f, 0.3000f, 0.3035f, 0.3070f,
     115             :     0.3104f, 0.3138f, 0.3171f, 0.3204f, 0.3236f, 0.3268f, 0.3299f, 0.3330f,
     116             :     0.3360f, 0.3390f, 0.3420f, 0.3449f, 0.3478f, 0.3507f, 0.3535f, 0.3563f,
     117             :     0.3591f, 0.3619f, 0.3646f, 0.3673f, 0.3699f, 0.3726f, 0.3752f, 0.3777f,
     118             :     0.3803f, 0.3828f, 0.3854f, 0.3878f, 0.3903f, 0.3928f, 0.3952f, 0.3976f,
     119             :     0.4000f};
     120             : 
     121             : // Matlab code to produce table:
     122             : // overDriveCurve = [sqrt(linspace(0,1,65))' + 1];
     123             : // fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', overDriveCurve);
     124             : ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65] = {
     125             :     1.0000f, 1.1250f, 1.1768f, 1.2165f, 1.2500f, 1.2795f, 1.3062f, 1.3307f,
     126             :     1.3536f, 1.3750f, 1.3953f, 1.4146f, 1.4330f, 1.4507f, 1.4677f, 1.4841f,
     127             :     1.5000f, 1.5154f, 1.5303f, 1.5449f, 1.5590f, 1.5728f, 1.5863f, 1.5995f,
     128             :     1.6124f, 1.6250f, 1.6374f, 1.6495f, 1.6614f, 1.6731f, 1.6847f, 1.6960f,
     129             :     1.7071f, 1.7181f, 1.7289f, 1.7395f, 1.7500f, 1.7603f, 1.7706f, 1.7806f,
     130             :     1.7906f, 1.8004f, 1.8101f, 1.8197f, 1.8292f, 1.8385f, 1.8478f, 1.8570f,
     131             :     1.8660f, 1.8750f, 1.8839f, 1.8927f, 1.9014f, 1.9100f, 1.9186f, 1.9270f,
     132             :     1.9354f, 1.9437f, 1.9520f, 1.9601f, 1.9682f, 1.9763f, 1.9843f, 1.9922f,
     133             :     2.0000f};
     134             : 
     135             : // Delay Agnostic AEC parameters, still under development and may change.
     136             : static const float kDelayQualityThresholdMax = 0.07f;
     137             : static const float kDelayQualityThresholdMin = 0.01f;
     138             : static const int kInitialShiftOffset = 5;
     139             : #if !defined(WEBRTC_ANDROID)
     140             : static const int kDelayCorrectionStart = 1500;  // 10 ms chunks
     141             : #endif
     142             : 
     143             : // Target suppression levels for nlp modes.
     144             : // log{0.001, 0.00001, 0.00000001}
     145             : static const float kTargetSupp[3] = {-6.9f, -11.5f, -18.4f};
     146             : 
     147             : // Two sets of parameters, one for the extended filter mode.
     148             : static const float kExtendedMinOverDrive[3] = {3.0f, 6.0f, 15.0f};
     149             : static const float kNormalMinOverDrive[3] = {1.0f, 2.0f, 5.0f};
     150             : const float WebRtcAec_kExtendedSmoothingCoefficients[2][2] = {{0.9f, 0.1f},
     151             :                                                               {0.92f, 0.08f}};
     152             : const float WebRtcAec_kNormalSmoothingCoefficients[2][2] = {{0.9f, 0.1f},
     153             :                                                             {0.93f, 0.07f}};
     154             : 
     155             : // Number of partitions forming the NLP's "preferred" bands.
     156             : enum { kPrefBandSize = 24 };
     157             : 
     158             : WebRtcAecFilterFar WebRtcAec_FilterFar;
     159             : WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal;
     160             : WebRtcAecFilterAdaptation WebRtcAec_FilterAdaptation;
     161             : WebRtcAecOverdrive WebRtcAec_Overdrive;
     162             : WebRtcAecSuppress WebRtcAec_Suppress;
     163             : WebRtcAecComputeCoherence WebRtcAec_ComputeCoherence;
     164             : WebRtcAecUpdateCoherenceSpectra WebRtcAec_UpdateCoherenceSpectra;
     165             : WebRtcAecStoreAsComplex WebRtcAec_StoreAsComplex;
     166             : WebRtcAecPartitionDelay WebRtcAec_PartitionDelay;
     167             : WebRtcAecWindowData WebRtcAec_WindowData;
     168             : 
     169           0 : __inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
     170           0 :   return aRe * bRe - aIm * bIm;
     171             : }
     172             : 
     173           0 : __inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
     174           0 :   return aRe * bIm + aIm * bRe;
     175             : }
     176             : 
     177             : // TODO(minyue): Due to a legacy bug, |framelevel| and |averagelevel| use a
     178             : // window, of which the length is 1 unit longer than indicated. Remove "+1" when
     179             : // the code is refactored.
     180           0 : PowerLevel::PowerLevel()
     181             :     : framelevel(kSubCountLen + 1),
     182           0 :       averagelevel(kCountLen + 1) {
     183           0 : }
     184             : 
     185           0 : BlockBuffer::BlockBuffer() {
     186           0 :   buffer_ = WebRtc_CreateBuffer(kBufferSizeBlocks, sizeof(float) * PART_LEN);
     187           0 :   RTC_CHECK(buffer_);
     188           0 :   ReInit();
     189           0 : }
     190             : 
     191           0 : BlockBuffer::~BlockBuffer() {
     192           0 :   WebRtc_FreeBuffer(buffer_);
     193           0 : }
     194             : 
     195           0 : void BlockBuffer::ReInit() {
     196           0 :   WebRtc_InitBuffer(buffer_);
     197           0 : }
     198             : 
     199           0 : void BlockBuffer::Insert(const float block[PART_LEN]) {
     200           0 :   WebRtc_WriteBuffer(buffer_, block, 1);
     201           0 : }
     202             : 
     203           0 : void BlockBuffer::ExtractExtendedBlock(float extended_block[PART_LEN2]) {
     204           0 :   float* block_ptr = NULL;
     205           0 :   RTC_DCHECK_LT(0, AvaliableSpace());
     206             : 
     207             :   // Extract the previous block.
     208           0 :   WebRtc_MoveReadPtr(buffer_, -1);
     209           0 :   WebRtc_ReadBuffer(buffer_, reinterpret_cast<void**>(&block_ptr),
     210           0 :                     &extended_block[0], 1);
     211           0 :   if (block_ptr != &extended_block[0]) {
     212           0 :     memcpy(&extended_block[0], block_ptr, PART_LEN * sizeof(float));
     213             :   }
     214             : 
     215             :   // Extract the current block.
     216           0 :   WebRtc_ReadBuffer(buffer_, reinterpret_cast<void**>(&block_ptr),
     217           0 :                     &extended_block[PART_LEN], 1);
     218           0 :   if (block_ptr != &extended_block[PART_LEN]) {
     219           0 :     memcpy(&extended_block[PART_LEN], block_ptr, PART_LEN * sizeof(float));
     220             :   }
     221           0 : }
     222             : 
     223           0 : int BlockBuffer::AdjustSize(int buffer_size_decrease) {
     224           0 :   return WebRtc_MoveReadPtr(buffer_, buffer_size_decrease);
     225             : }
     226             : 
     227           0 : size_t BlockBuffer::Size() {
     228           0 :   return static_cast<int>(WebRtc_available_read(buffer_));
     229             : }
     230             : 
     231           0 : size_t BlockBuffer::AvaliableSpace() {
     232           0 :   return WebRtc_available_write(buffer_);
     233             : }
     234             : 
     235           0 : DivergentFilterFraction::DivergentFilterFraction()
     236             :     : count_(0),
     237             :       occurrence_(0),
     238           0 :       fraction_(-1.0) {
     239           0 : }
     240             : 
     241           0 : void DivergentFilterFraction::Reset() {
     242           0 :   Clear();
     243           0 :   fraction_ = -1.0;
     244           0 : }
     245             : 
     246           0 : void DivergentFilterFraction::AddObservation(const PowerLevel& nearlevel,
     247             :                                              const PowerLevel& linoutlevel,
     248             :                                              const PowerLevel& nlpoutlevel) {
     249           0 :   const float near_level = nearlevel.framelevel.GetLatestMean();
     250             :   const float level_increase =
     251           0 :       linoutlevel.framelevel.GetLatestMean() - near_level;
     252           0 :   const bool output_signal_active = nlpoutlevel.framelevel.GetLatestMean() >
     253           0 :           40.0 * nlpoutlevel.minlevel;
     254             :   // Level increase should be, in principle, negative, when the filter
     255             :   // does not diverge. Here we allow some margin (0.01 * near end level) and
     256             :   // numerical error (1.0). We count divergence only when the AEC output
     257             :   // signal is active.
     258           0 :   if (output_signal_active &&
     259           0 :       level_increase > std::max(0.01 * near_level, 1.0))
     260           0 :     occurrence_++;
     261           0 :   ++count_;
     262           0 :   if (count_ == kDivergentFilterFractionAggregationWindowSize) {
     263           0 :     fraction_ = static_cast<float>(occurrence_) /
     264             :         kDivergentFilterFractionAggregationWindowSize;
     265           0 :     Clear();
     266             :   }
     267           0 : }
     268             : 
     269           0 : float DivergentFilterFraction::GetLatestFraction() const {
     270           0 :   return fraction_;
     271             : }
     272             : 
     273           0 : void DivergentFilterFraction::Clear() {
     274           0 :   count_ = 0;
     275           0 :   occurrence_ = 0;
     276           0 : }
     277             : 
     278             : // TODO(minyue): Moving some initialization from WebRtcAec_CreateAec() to ctor.
     279           0 : AecCore::AecCore(int instance_index)
     280           0 :     : data_dumper(new ApmDataDumper(instance_index)) {}
     281             : 
     282           0 : AecCore::~AecCore() {}
     283             : 
     284           0 : static int CmpFloat(const void* a, const void* b) {
     285           0 :   const float* da = (const float*)a;
     286           0 :   const float* db = (const float*)b;
     287             : 
     288           0 :   return (*da > *db) - (*da < *db);
     289             : }
     290             : 
     291           0 : static void FilterFar(int num_partitions,
     292             :                       int x_fft_buf_block_pos,
     293             :                       float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
     294             :                       float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
     295             :                       float y_fft[2][PART_LEN1]) {
     296             :   int i;
     297           0 :   for (i = 0; i < num_partitions; i++) {
     298             :     int j;
     299           0 :     int xPos = (i + x_fft_buf_block_pos) * PART_LEN1;
     300           0 :     int pos = i * PART_LEN1;
     301             :     // Check for wrap
     302           0 :     if (i + x_fft_buf_block_pos >= num_partitions) {
     303           0 :       xPos -= num_partitions * (PART_LEN1);
     304             :     }
     305             : 
     306           0 :     for (j = 0; j < PART_LEN1; j++) {
     307           0 :       y_fft[0][j] += MulRe(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
     308           0 :                            h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
     309           0 :       y_fft[1][j] += MulIm(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
     310           0 :                            h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
     311             :     }
     312             :   }
     313           0 : }
     314             : 
     315           0 : static void ScaleErrorSignal(float mu,
     316             :                              float error_threshold,
     317             :                              float x_pow[PART_LEN1],
     318             :                              float ef[2][PART_LEN1]) {
     319             :   int i;
     320             :   float abs_ef;
     321           0 :   for (i = 0; i < (PART_LEN1); i++) {
     322           0 :     ef[0][i] /= (x_pow[i] + 1e-10f);
     323           0 :     ef[1][i] /= (x_pow[i] + 1e-10f);
     324           0 :     abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
     325             : 
     326           0 :     if (abs_ef > error_threshold) {
     327           0 :       abs_ef = error_threshold / (abs_ef + 1e-10f);
     328           0 :       ef[0][i] *= abs_ef;
     329           0 :       ef[1][i] *= abs_ef;
     330             :     }
     331             : 
     332             :     // Stepsize factor
     333           0 :     ef[0][i] *= mu;
     334           0 :     ef[1][i] *= mu;
     335             :   }
     336           0 : }
     337             : 
     338           0 : static void FilterAdaptation(
     339             :     const OouraFft& ooura_fft,
     340             :     int num_partitions,
     341             :     int x_fft_buf_block_pos,
     342             :     float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
     343             :     float e_fft[2][PART_LEN1],
     344             :     float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
     345             :   int i, j;
     346             :   float fft[PART_LEN2];
     347           0 :   for (i = 0; i < num_partitions; i++) {
     348           0 :     int xPos = (i + x_fft_buf_block_pos) * (PART_LEN1);
     349             :     int pos;
     350             :     // Check for wrap
     351           0 :     if (i + x_fft_buf_block_pos >= num_partitions) {
     352           0 :       xPos -= num_partitions * PART_LEN1;
     353             :     }
     354             : 
     355           0 :     pos = i * PART_LEN1;
     356             : 
     357           0 :     for (j = 0; j < PART_LEN; j++) {
     358           0 :       fft[2 * j] = MulRe(x_fft_buf[0][xPos + j], -x_fft_buf[1][xPos + j],
     359           0 :                          e_fft[0][j], e_fft[1][j]);
     360           0 :       fft[2 * j + 1] = MulIm(x_fft_buf[0][xPos + j], -x_fft_buf[1][xPos + j],
     361           0 :                              e_fft[0][j], e_fft[1][j]);
     362             :     }
     363           0 :     fft[1] =
     364           0 :         MulRe(x_fft_buf[0][xPos + PART_LEN], -x_fft_buf[1][xPos + PART_LEN],
     365           0 :               e_fft[0][PART_LEN], e_fft[1][PART_LEN]);
     366             : 
     367           0 :     ooura_fft.InverseFft(fft);
     368           0 :     memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
     369             : 
     370             :     // fft scaling
     371             :     {
     372           0 :       float scale = 2.0f / PART_LEN2;
     373           0 :       for (j = 0; j < PART_LEN; j++) {
     374           0 :         fft[j] *= scale;
     375             :       }
     376             :     }
     377           0 :     ooura_fft.Fft(fft);
     378             : 
     379           0 :     h_fft_buf[0][pos] += fft[0];
     380           0 :     h_fft_buf[0][pos + PART_LEN] += fft[1];
     381             : 
     382           0 :     for (j = 1; j < PART_LEN; j++) {
     383           0 :       h_fft_buf[0][pos + j] += fft[2 * j];
     384           0 :       h_fft_buf[1][pos + j] += fft[2 * j + 1];
     385             :     }
     386             :   }
     387           0 : }
     388             : 
     389           0 : static void Overdrive(float overdrive_scaling,
     390             :                       const float hNlFb,
     391             :                       float hNl[PART_LEN1]) {
     392           0 :   for (int i = 0; i < PART_LEN1; ++i) {
     393             :     // Weight subbands
     394           0 :     if (hNl[i] > hNlFb) {
     395           0 :       hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
     396           0 :                (1 - WebRtcAec_weightCurve[i]) * hNl[i];
     397             :     }
     398           0 :     hNl[i] = powf(hNl[i], overdrive_scaling * WebRtcAec_overDriveCurve[i]);
     399             :   }
     400           0 : }
     401             : 
     402           0 : static void Suppress(const float hNl[PART_LEN1], float efw[2][PART_LEN1]) {
     403           0 :   for (int i = 0; i < PART_LEN1; ++i) {
     404             :     // Suppress error signal
     405           0 :     efw[0][i] *= hNl[i];
     406           0 :     efw[1][i] *= hNl[i];
     407             : 
     408             :     // Ooura fft returns incorrect sign on imaginary component. It matters here
     409             :     // because we are making an additive change with comfort noise.
     410           0 :     efw[1][i] *= -1;
     411             :   }
     412           0 : }
     413             : 
     414           0 : static int PartitionDelay(int num_partitions,
     415             :                           float h_fft_buf[2]
     416             :                                          [kExtendedNumPartitions * PART_LEN1]) {
     417             :   // Measures the energy in each filter partition and returns the partition with
     418             :   // highest energy.
     419             :   // TODO(bjornv): Spread computational cost by computing one partition per
     420             :   // block?
     421           0 :   float wfEnMax = 0;
     422             :   int i;
     423           0 :   int delay = 0;
     424             : 
     425           0 :   for (i = 0; i < num_partitions; i++) {
     426             :     int j;
     427           0 :     int pos = i * PART_LEN1;
     428           0 :     float wfEn = 0;
     429           0 :     for (j = 0; j < PART_LEN1; j++) {
     430           0 :       wfEn += h_fft_buf[0][pos + j] * h_fft_buf[0][pos + j] +
     431           0 :               h_fft_buf[1][pos + j] * h_fft_buf[1][pos + j];
     432             :     }
     433             : 
     434           0 :     if (wfEn > wfEnMax) {
     435           0 :       wfEnMax = wfEn;
     436           0 :       delay = i;
     437             :     }
     438             :   }
     439           0 :   return delay;
     440             : }
     441             : 
     442             : // Update metric with 10 * log10(numerator / denominator).
     443           0 : static void UpdateLogRatioMetric(Stats* metric, float numerator,
     444             :                                  float denominator) {
     445           0 :   RTC_DCHECK(metric);
     446           0 :   RTC_CHECK(numerator >= 0);
     447           0 :   RTC_CHECK(denominator >= 0);
     448             : 
     449           0 :   const float log_numerator = log10(numerator + 1e-10f);
     450           0 :   const float log_denominator = log10(denominator + 1e-10f);
     451           0 :   metric->instant = 10.0f * (log_numerator - log_denominator);
     452             : 
     453             :   // Max.
     454           0 :   if (metric->instant > metric->max)
     455           0 :     metric->max = metric->instant;
     456             : 
     457             :   // Min.
     458           0 :   if (metric->instant < metric->min)
     459           0 :     metric->min = metric->instant;
     460             : 
     461             :   // Average.
     462           0 :   metric->counter++;
     463             :   // This is to protect overflow, which should almost never happen.
     464           0 :   RTC_CHECK_NE(0, metric->counter);
     465           0 :   metric->sum += metric->instant;
     466           0 :   metric->average = metric->sum / metric->counter;
     467             : 
     468             :   // Upper mean.
     469           0 :   if (metric->instant > metric->average) {
     470           0 :     metric->hicounter++;
     471             :     // This is to protect overflow, which should almost never happen.
     472           0 :     RTC_CHECK_NE(0, metric->hicounter);
     473           0 :     metric->hisum += metric->instant;
     474           0 :     metric->himean = metric->hisum / metric->hicounter;
     475             :   }
     476           0 : }
     477             : 
     478             : // Threshold to protect against the ill-effects of a zero far-end.
     479             : const float WebRtcAec_kMinFarendPSD = 15;
     480             : 
     481             : // Updates the following smoothed Power Spectral Densities (PSD):
     482             : //  - sd  : near-end
     483             : //  - se  : residual echo
     484             : //  - sx  : far-end
     485             : //  - sde : cross-PSD of near-end and residual echo
     486             : //  - sxd : cross-PSD of near-end and far-end
     487             : //
     488             : // In addition to updating the PSDs, also the filter diverge state is
     489             : // determined.
     490           0 : static void UpdateCoherenceSpectra(int mult,
     491             :                                    bool extended_filter_enabled,
     492             :                                    float efw[2][PART_LEN1],
     493             :                                    float dfw[2][PART_LEN1],
     494             :                                    float xfw[2][PART_LEN1],
     495             :                                    CoherenceState* coherence_state,
     496             :                                    short* filter_divergence_state,
     497             :                                    int* extreme_filter_divergence) {
     498             :   // Power estimate smoothing coefficients.
     499             :   const float* ptrGCoh =
     500             :       extended_filter_enabled
     501           0 :           ? WebRtcAec_kExtendedSmoothingCoefficients[mult - 1]
     502           0 :           : WebRtcAec_kNormalSmoothingCoefficients[mult - 1];
     503             :   int i;
     504           0 :   float sdSum = 0, seSum = 0;
     505             : 
     506           0 :   for (i = 0; i < PART_LEN1; i++) {
     507           0 :     coherence_state->sd[i] =
     508           0 :         ptrGCoh[0] * coherence_state->sd[i] +
     509           0 :         ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
     510           0 :     coherence_state->se[i] =
     511           0 :         ptrGCoh[0] * coherence_state->se[i] +
     512           0 :         ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
     513             :     // We threshold here to protect against the ill-effects of a zero farend.
     514             :     // The threshold is not arbitrarily chosen, but balances protection and
     515             :     // adverse interaction with the algorithm's tuning.
     516             :     // TODO(bjornv): investigate further why this is so sensitive.
     517           0 :     coherence_state->sx[i] =
     518           0 :         ptrGCoh[0] * coherence_state->sx[i] +
     519           0 :         ptrGCoh[1] *
     520           0 :             WEBRTC_SPL_MAX(xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
     521             :                            WebRtcAec_kMinFarendPSD);
     522             : 
     523           0 :     coherence_state->sde[i][0] =
     524           0 :         ptrGCoh[0] * coherence_state->sde[i][0] +
     525           0 :         ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
     526           0 :     coherence_state->sde[i][1] =
     527           0 :         ptrGCoh[0] * coherence_state->sde[i][1] +
     528           0 :         ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
     529             : 
     530           0 :     coherence_state->sxd[i][0] =
     531           0 :         ptrGCoh[0] * coherence_state->sxd[i][0] +
     532           0 :         ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
     533           0 :     coherence_state->sxd[i][1] =
     534           0 :         ptrGCoh[0] * coherence_state->sxd[i][1] +
     535           0 :         ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
     536             : 
     537           0 :     sdSum += coherence_state->sd[i];
     538           0 :     seSum += coherence_state->se[i];
     539             :   }
     540             : 
     541             :   // Divergent filter safeguard update.
     542           0 :   *filter_divergence_state =
     543           0 :       (*filter_divergence_state ? 1.05f : 1.0f) * seSum > sdSum;
     544             : 
     545             :   // Signal extreme filter divergence if the error is significantly larger
     546             :   // than the nearend (13 dB).
     547           0 :   *extreme_filter_divergence = (seSum > (19.95f * sdSum));
     548           0 : }
     549             : 
     550             : // Window time domain data to be used by the fft.
     551           0 : __inline static void WindowData(float* x_windowed, const float* x) {
     552             :   int i;
     553           0 :   for (i = 0; i < PART_LEN; i++) {
     554           0 :     x_windowed[i] = x[i] * WebRtcAec_sqrtHanning[i];
     555           0 :     x_windowed[PART_LEN + i] =
     556           0 :         x[PART_LEN + i] * WebRtcAec_sqrtHanning[PART_LEN - i];
     557             :   }
     558           0 : }
     559             : 
     560             : // Puts fft output data into a complex valued array.
     561           0 : __inline static void StoreAsComplex(const float* data,
     562             :                                     float data_complex[2][PART_LEN1]) {
     563             :   int i;
     564           0 :   data_complex[0][0] = data[0];
     565           0 :   data_complex[1][0] = 0;
     566           0 :   for (i = 1; i < PART_LEN; i++) {
     567           0 :     data_complex[0][i] = data[2 * i];
     568           0 :     data_complex[1][i] = data[2 * i + 1];
     569             :   }
     570           0 :   data_complex[0][PART_LEN] = data[1];
     571           0 :   data_complex[1][PART_LEN] = 0;
     572           0 : }
     573             : 
     574           0 : static void ComputeCoherence(const CoherenceState* coherence_state,
     575             :                              float* cohde,
     576             :                              float* cohxd) {
     577             :   // Subband coherence
     578           0 :   for (int i = 0; i < PART_LEN1; i++) {
     579           0 :     cohde[i] = (coherence_state->sde[i][0] * coherence_state->sde[i][0] +
     580           0 :                 coherence_state->sde[i][1] * coherence_state->sde[i][1]) /
     581           0 :                (coherence_state->sd[i] * coherence_state->se[i] + 1e-10f);
     582           0 :     cohxd[i] = (coherence_state->sxd[i][0] * coherence_state->sxd[i][0] +
     583           0 :                 coherence_state->sxd[i][1] * coherence_state->sxd[i][1]) /
     584           0 :                (coherence_state->sx[i] * coherence_state->sd[i] + 1e-10f);
     585             :   }
     586           0 : }
     587             : 
     588           0 : static void GetHighbandGain(const float* lambda, float* nlpGainHband) {
     589             :   int i;
     590             : 
     591           0 :   *nlpGainHband = 0.0f;
     592           0 :   for (i = freqAvgIc; i < PART_LEN1 - 1; i++) {
     593           0 :     *nlpGainHband += lambda[i];
     594             :   }
     595           0 :   *nlpGainHband /= static_cast<float>(PART_LEN1 - 1 - freqAvgIc);
     596           0 : }
     597             : 
     598           0 : static void GenerateComplexNoise(uint32_t* seed, float noise[2][PART_LEN1]) {
     599           0 :   const float kPi2 = 6.28318530717959f;
     600             :   int16_t randW16[PART_LEN];
     601           0 :   WebRtcSpl_RandUArray(randW16, PART_LEN, seed);
     602             : 
     603           0 :   noise[0][0] = 0;
     604           0 :   noise[1][0] = 0;
     605           0 :   for (size_t i = 1; i < PART_LEN1; i++) {
     606           0 :     float tmp = kPi2 * randW16[i - 1] / 32768.f;
     607           0 :     noise[0][i] = cosf(tmp);
     608           0 :     noise[1][i] = -sinf(tmp);
     609             :   }
     610           0 :   noise[1][PART_LEN] = 0;
     611           0 : }
     612             : 
     613           0 : static void ComfortNoise(bool generate_high_frequency_noise,
     614             :                          uint32_t* seed,
     615             :                          float e_fft[2][PART_LEN1],
     616             :                          float high_frequency_comfort_noise[2][PART_LEN1],
     617             :                          const float* noise_spectrum,
     618             :                          const float* suppressor_gain) {
     619             :   float complex_noise[2][PART_LEN1];
     620             : 
     621           0 :   GenerateComplexNoise(seed, complex_noise);
     622             : 
     623             :   // Shape, scale and add comfort noise.
     624           0 :   for (int i = 1; i < PART_LEN1; ++i) {
     625             :     float noise_scaling =
     626           0 :         sqrtf(WEBRTC_SPL_MAX(1 - suppressor_gain[i] * suppressor_gain[i], 0)) *
     627           0 :         sqrtf(noise_spectrum[i]);
     628           0 :     e_fft[0][i] += noise_scaling * complex_noise[0][i];
     629           0 :     e_fft[1][i] += noise_scaling * complex_noise[1][i];
     630             :   }
     631             : 
     632             :   // Form comfort noise for higher frequencies.
     633           0 :   if (generate_high_frequency_noise) {
     634             :     // Compute average noise power and nlp gain over the second half of freq
     635             :     // spectrum (i.e., 4->8khz).
     636           0 :     int start_avg_band = PART_LEN1 / 2;
     637           0 :     float upper_bands_noise_power = 0.f;
     638           0 :     float upper_bands_suppressor_gain = 0.f;
     639           0 :     for (int i = start_avg_band; i < PART_LEN1; ++i) {
     640           0 :       upper_bands_noise_power += sqrtf(noise_spectrum[i]);
     641           0 :       upper_bands_suppressor_gain +=
     642           0 :           sqrtf(WEBRTC_SPL_MAX(1 - suppressor_gain[i] * suppressor_gain[i], 0));
     643             :     }
     644           0 :     upper_bands_noise_power /= (PART_LEN1 - start_avg_band);
     645           0 :     upper_bands_suppressor_gain /= (PART_LEN1 - start_avg_band);
     646             : 
     647             :     // Shape, scale and add comfort noise.
     648           0 :     float noise_scaling = upper_bands_suppressor_gain * upper_bands_noise_power;
     649           0 :     high_frequency_comfort_noise[0][0] = 0;
     650           0 :     high_frequency_comfort_noise[1][0] = 0;
     651           0 :     for (int i = 1; i < PART_LEN1; ++i) {
     652           0 :       high_frequency_comfort_noise[0][i] = noise_scaling * complex_noise[0][i];
     653           0 :       high_frequency_comfort_noise[1][i] = noise_scaling * complex_noise[1][i];
     654             :     }
     655           0 :     high_frequency_comfort_noise[1][PART_LEN] = 0;
     656             :   } else {
     657             :     memset(high_frequency_comfort_noise, 0,
     658           0 :            2 * PART_LEN1 * sizeof(high_frequency_comfort_noise[0][0]));
     659             :   }
     660           0 : }
     661             : 
     662           0 : static void InitLevel(PowerLevel* level) {
     663           0 :   const float kBigFloat = 1E17f;
     664           0 :   level->averagelevel.Reset();
     665           0 :   level->framelevel.Reset();
     666           0 :   level->minlevel = kBigFloat;
     667           0 : }
     668             : 
     669           0 : static void InitStats(Stats* stats) {
     670           0 :   stats->instant = kOffsetLevel;
     671           0 :   stats->average = kOffsetLevel;
     672           0 :   stats->max = kOffsetLevel;
     673           0 :   stats->min = kOffsetLevel * (-1);
     674           0 :   stats->sum = 0;
     675           0 :   stats->hisum = 0;
     676           0 :   stats->himean = kOffsetLevel;
     677           0 :   stats->counter = 0;
     678           0 :   stats->hicounter = 0;
     679           0 : }
     680             : 
     681           0 : static void InitMetrics(AecCore* self) {
     682           0 :   self->stateCounter = 0;
     683           0 :   InitLevel(&self->farlevel);
     684           0 :   InitLevel(&self->nearlevel);
     685           0 :   InitLevel(&self->linoutlevel);
     686           0 :   InitLevel(&self->nlpoutlevel);
     687             : 
     688           0 :   InitStats(&self->erl);
     689           0 :   InitStats(&self->erle);
     690           0 :   InitStats(&self->aNlp);
     691           0 :   InitStats(&self->rerl);
     692             : 
     693           0 :   self->divergent_filter_fraction.Reset();
     694           0 : }
     695             : 
     696           0 : static float CalculatePower(const float* in, size_t num_samples) {
     697             :   size_t k;
     698           0 :   float energy = 0.0f;
     699             : 
     700           0 :   for (k = 0; k < num_samples; ++k) {
     701           0 :     energy += in[k] * in[k];
     702             :   }
     703           0 :   return energy / num_samples;
     704             : }
     705             : 
     706           0 : static void UpdateLevel(PowerLevel* level, float power) {
     707           0 :   level->framelevel.AddValue(power);
     708           0 :   if (level->framelevel.EndOfBlock()) {
     709           0 :     const float new_frame_level = level->framelevel.GetLatestMean();
     710           0 :     if (new_frame_level > 0) {
     711           0 :       if (new_frame_level < level->minlevel) {
     712           0 :         level->minlevel = new_frame_level;  // New minimum.
     713             :       } else {
     714           0 :         level->minlevel *= (1 + 0.001f);  // Small increase.
     715             :       }
     716             :     }
     717           0 :     level->averagelevel.AddValue(new_frame_level);
     718             :   }
     719           0 : }
     720             : 
     721           0 : static void UpdateMetrics(AecCore* aec) {
     722           0 :   const float actThresholdNoisy = 8.0f;
     723           0 :   const float actThresholdClean = 40.0f;
     724             : 
     725           0 :   const float noisyPower = 300000.0f;
     726             : 
     727             :   float actThreshold;
     728             : 
     729           0 :   if (aec->echoState) {  // Check if echo is likely present
     730           0 :     aec->stateCounter++;
     731             :   }
     732             : 
     733           0 :   if (aec->linoutlevel.framelevel.EndOfBlock()) {
     734           0 :     aec->divergent_filter_fraction.AddObservation(aec->nearlevel,
     735             :                                                   aec->linoutlevel,
     736           0 :                                                   aec->nlpoutlevel);
     737             :   }
     738             : 
     739           0 :   if (aec->farlevel.averagelevel.EndOfBlock()) {
     740           0 :     if (aec->farlevel.minlevel < noisyPower) {
     741           0 :       actThreshold = actThresholdClean;
     742             :     } else {
     743           0 :       actThreshold = actThresholdNoisy;
     744             :     }
     745             : 
     746           0 :     const float far_average_level = aec->farlevel.averagelevel.GetLatestMean();
     747             : 
     748             :     // The last condition is to let estimation be made in active far-end
     749             :     // segments only.
     750           0 :     if ((aec->stateCounter > (0.5f * kCountLen * kSubCountLen)) &&
     751           0 :         (aec->farlevel.framelevel.EndOfBlock()) &&
     752           0 :         (far_average_level > (actThreshold * aec->farlevel.minlevel))) {
     753             : 
     754             :       // ERL: error return loss.
     755             :       const float near_average_level =
     756           0 :           aec->nearlevel.averagelevel.GetLatestMean();
     757           0 :       UpdateLogRatioMetric(&aec->erl, far_average_level, near_average_level);
     758             : 
     759             :       // A_NLP: error return loss enhanced before the nonlinear suppression.
     760             :       const float linout_average_level =
     761           0 :           aec->linoutlevel.averagelevel.GetLatestMean();
     762           0 :       UpdateLogRatioMetric(&aec->aNlp, near_average_level,
     763           0 :                            linout_average_level);
     764             : 
     765             :       // ERLE: error return loss enhanced.
     766             :       const float nlpout_average_level =
     767           0 :           aec->nlpoutlevel.averagelevel.GetLatestMean();
     768           0 :       UpdateLogRatioMetric(&aec->erle, near_average_level,
     769           0 :                            nlpout_average_level);
     770             :     }
     771             : 
     772           0 :     aec->stateCounter = 0;
     773             :   }
     774           0 : }
     775             : 
     776           0 : static void UpdateDelayMetrics(AecCore* self) {
     777           0 :   int i = 0;
     778           0 :   int delay_values = 0;
     779           0 :   int median = 0;
     780           0 :   int lookahead = WebRtc_lookahead(self->delay_estimator);
     781           0 :   const int kMsPerBlock = PART_LEN / (self->mult * 8);
     782           0 :   int64_t l1_norm = 0;
     783             : 
     784           0 :   if (self->num_delay_values == 0) {
     785             :     // We have no new delay value data. Even though -1 is a valid |median| in
     786             :     // the sense that we allow negative values, it will practically never be
     787             :     // used since multiples of |kMsPerBlock| will always be returned.
     788             :     // We therefore use -1 to indicate in the logs that the delay estimator was
     789             :     // not able to estimate the delay.
     790           0 :     self->delay_median = -1;
     791           0 :     self->delay_std = -1;
     792           0 :     self->fraction_poor_delays = -1;
     793           0 :     return;
     794             :   }
     795             : 
     796             :   // Start value for median count down.
     797           0 :   delay_values = self->num_delay_values >> 1;
     798             :   // Get median of delay values since last update.
     799           0 :   for (i = 0; i < kHistorySizeBlocks; i++) {
     800           0 :     delay_values -= self->delay_histogram[i];
     801           0 :     if (delay_values < 0) {
     802           0 :       median = i;
     803           0 :       break;
     804             :     }
     805             :   }
     806             :   // Account for lookahead.
     807           0 :   self->delay_median = (median - lookahead) * kMsPerBlock;
     808             : 
     809             :   // Calculate the L1 norm, with median value as central moment.
     810           0 :   for (i = 0; i < kHistorySizeBlocks; i++) {
     811           0 :     l1_norm += abs(i - median) * self->delay_histogram[i];
     812             :   }
     813           0 :   self->delay_std =
     814           0 :       static_cast<int>((l1_norm + self->num_delay_values / 2) /
     815           0 :                        self->num_delay_values) * kMsPerBlock;
     816             : 
     817             :   // Determine fraction of delays that are out of bounds, that is, either
     818             :   // negative (anti-causal system) or larger than the AEC filter length.
     819             :   {
     820           0 :     int num_delays_out_of_bounds = self->num_delay_values;
     821             :     const int histogram_length =
     822           0 :         sizeof(self->delay_histogram) / sizeof(self->delay_histogram[0]);
     823           0 :     for (i = lookahead; i < lookahead + self->num_partitions; ++i) {
     824           0 :       if (i < histogram_length)
     825           0 :         num_delays_out_of_bounds -= self->delay_histogram[i];
     826             :     }
     827           0 :     self->fraction_poor_delays =
     828           0 :         static_cast<float>(num_delays_out_of_bounds) / self->num_delay_values;
     829             :   }
     830             : 
     831             :   // Reset histogram.
     832           0 :   memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
     833           0 :   self->num_delay_values = 0;
     834             : 
     835           0 :   return;
     836             : }
     837             : 
     838           0 : static void ScaledInverseFft(const OouraFft& ooura_fft,
     839             :                              float freq_data[2][PART_LEN1],
     840             :                              float time_data[PART_LEN2],
     841             :                              float scale,
     842             :                              int conjugate) {
     843             :   int i;
     844           0 :   const float normalization = scale / static_cast<float>(PART_LEN2);
     845           0 :   const float sign = (conjugate ? -1 : 1);
     846           0 :   time_data[0] = freq_data[0][0] * normalization;
     847           0 :   time_data[1] = freq_data[0][PART_LEN] * normalization;
     848           0 :   for (i = 1; i < PART_LEN; i++) {
     849           0 :     time_data[2 * i] = freq_data[0][i] * normalization;
     850           0 :     time_data[2 * i + 1] = sign * freq_data[1][i] * normalization;
     851             :   }
     852           0 :   ooura_fft.InverseFft(time_data);
     853           0 : }
     854             : 
     855           0 : static void Fft(const OouraFft& ooura_fft,
     856             :                 float time_data[PART_LEN2],
     857             :                 float freq_data[2][PART_LEN1]) {
     858             :   int i;
     859           0 :   ooura_fft.Fft(time_data);
     860             : 
     861             :   // Reorder fft output data.
     862           0 :   freq_data[1][0] = 0;
     863           0 :   freq_data[1][PART_LEN] = 0;
     864           0 :   freq_data[0][0] = time_data[0];
     865           0 :   freq_data[0][PART_LEN] = time_data[1];
     866           0 :   for (i = 1; i < PART_LEN; i++) {
     867           0 :     freq_data[0][i] = time_data[2 * i];
     868           0 :     freq_data[1][i] = time_data[2 * i + 1];
     869             :   }
     870           0 : }
     871             : 
     872           0 : static int SignalBasedDelayCorrection(AecCore* self) {
     873           0 :   int delay_correction = 0;
     874           0 :   int last_delay = -2;
     875           0 :   RTC_DCHECK(self);
     876             : #if !defined(WEBRTC_ANDROID)
     877             :   // On desktops, turn on correction after |kDelayCorrectionStart| frames.  This
     878             :   // is to let the delay estimation get a chance to converge.  Also, if the
     879             :   // playout audio volume is low (or even muted) the delay estimation can return
     880             :   // a very large delay, which will break the AEC if it is applied.
     881           0 :   if (self->frame_count < kDelayCorrectionStart) {
     882           0 :     self->data_dumper->DumpRaw("aec_da_reported_delay", 1, &last_delay);
     883           0 :     return 0;
     884             :   }
     885             : #endif
     886             : 
     887             :   // 1. Check for non-negative delay estimate.  Note that the estimates we get
     888             :   //    from the delay estimation are not compensated for lookahead.  Hence, a
     889             :   //    negative |last_delay| is an invalid one.
     890             :   // 2. Verify that there is a delay change.  In addition, only allow a change
     891             :   //    if the delay is outside a certain region taking the AEC filter length
     892             :   //    into account.
     893             :   // TODO(bjornv): Investigate if we can remove the non-zero delay change check.
     894             :   // 3. Only allow delay correction if the delay estimation quality exceeds
     895             :   //    |delay_quality_threshold|.
     896             :   // 4. Finally, verify that the proposed |delay_correction| is feasible by
     897             :   //    comparing with the size of the far-end buffer.
     898           0 :   last_delay = WebRtc_last_delay(self->delay_estimator);
     899           0 :   self->data_dumper->DumpRaw("aec_da_reported_delay", 1, &last_delay);
     900           0 :   if ((last_delay >= 0) && (last_delay != self->previous_delay) &&
     901           0 :       (WebRtc_last_delay_quality(self->delay_estimator) >
     902           0 :        self->delay_quality_threshold)) {
     903           0 :     int delay = last_delay - WebRtc_lookahead(self->delay_estimator);
     904             :     // Allow for a slack in the actual delay, defined by a |lower_bound| and an
     905             :     // |upper_bound|.  The adaptive echo cancellation filter is currently
     906             :     // |num_partitions| (of 64 samples) long.  If the delay estimate is negative
     907             :     // or at least 3/4 of the filter length we open up for correction.
     908           0 :     const int lower_bound = 0;
     909           0 :     const int upper_bound = self->num_partitions * 3 / 4;
     910           0 :     const int do_correction = delay <= lower_bound || delay > upper_bound;
     911           0 :     if (do_correction == 1) {
     912           0 :       int available_read = self->farend_block_buffer_.Size();
     913             :       // With |shift_offset| we gradually rely on the delay estimates.  For
     914             :       // positive delays we reduce the correction by |shift_offset| to lower the
     915             :       // risk of pushing the AEC into a non causal state.  For negative delays
     916             :       // we rely on the values up to a rounding error, hence compensate by 1
     917             :       // element to make sure to push the delay into the causal region.
     918           0 :       delay_correction = -delay;
     919           0 :       delay_correction += delay > self->shift_offset ? self->shift_offset : 1;
     920           0 :       self->shift_offset--;
     921           0 :       self->shift_offset = (self->shift_offset <= 1 ? 1 : self->shift_offset);
     922           0 :       if (delay_correction > available_read - self->mult - 1) {
     923             :         // There is not enough data in the buffer to perform this shift.  Hence,
     924             :         // we do not rely on the delay estimate and do nothing.
     925           0 :         delay_correction = 0;
     926             :       } else {
     927           0 :         self->previous_delay = last_delay;
     928           0 :         ++self->delay_correction_count;
     929             :       }
     930             :     }
     931             :   }
     932             :   // Update the |delay_quality_threshold| once we have our first delay
     933             :   // correction.
     934           0 :   if (self->delay_correction_count > 0) {
     935           0 :     float delay_quality = WebRtc_last_delay_quality(self->delay_estimator);
     936           0 :     delay_quality =
     937           0 :         (delay_quality > kDelayQualityThresholdMax ? kDelayQualityThresholdMax
     938             :                                                    : delay_quality);
     939           0 :     self->delay_quality_threshold =
     940           0 :         (delay_quality > self->delay_quality_threshold
     941           0 :              ? delay_quality
     942             :              : self->delay_quality_threshold);
     943             :   }
     944           0 :   self->data_dumper->DumpRaw("aec_da_delay_correction", 1, &delay_correction);
     945             : 
     946           0 :   return delay_correction;
     947             : }
     948             : 
     949           0 : static void RegressorPower(int num_partitions,
     950             :                            int latest_added_partition,
     951             :                            float x_fft_buf[2]
     952             :                                           [kExtendedNumPartitions * PART_LEN1],
     953             :                            float x_pow[PART_LEN1]) {
     954           0 :   RTC_DCHECK_LT(latest_added_partition, num_partitions);
     955           0 :   memset(x_pow, 0, PART_LEN1 * sizeof(x_pow[0]));
     956             : 
     957           0 :   int partition = latest_added_partition;
     958           0 :   int x_fft_buf_position = partition * PART_LEN1;
     959           0 :   for (int i = 0; i < num_partitions; ++i) {
     960           0 :     for (int bin = 0; bin < PART_LEN1; ++bin) {
     961           0 :       float re = x_fft_buf[0][x_fft_buf_position];
     962           0 :       float im = x_fft_buf[1][x_fft_buf_position];
     963           0 :       x_pow[bin] += re * re + im * im;
     964           0 :       ++x_fft_buf_position;
     965             :     }
     966             : 
     967           0 :     ++partition;
     968           0 :     if (partition == num_partitions) {
     969           0 :       partition = 0;
     970           0 :       RTC_DCHECK_EQ(num_partitions * PART_LEN1, x_fft_buf_position);
     971           0 :       x_fft_buf_position = 0;
     972             :     }
     973             :   }
     974           0 : }
     975             : 
     976           0 : static void EchoSubtraction(const OouraFft& ooura_fft,
     977             :                             int num_partitions,
     978             :                             int extended_filter_enabled,
     979             :                             int* extreme_filter_divergence,
     980             :                             float filter_step_size,
     981             :                             float error_threshold,
     982             :                             float* x_fft,
     983             :                             int* x_fft_buf_block_pos,
     984             :                             float x_fft_buf[2]
     985             :                                            [kExtendedNumPartitions * PART_LEN1],
     986             :                             float* const y,
     987             :                             float x_pow[PART_LEN1],
     988             :                             float h_fft_buf[2]
     989             :                                            [kExtendedNumPartitions * PART_LEN1],
     990             :                             float echo_subtractor_output[PART_LEN]) {
     991             :   float s_fft[2][PART_LEN1];
     992             :   float e_extended[PART_LEN2];
     993             :   float s_extended[PART_LEN2];
     994             :   float* s;
     995             :   float e[PART_LEN];
     996             :   float e_fft[2][PART_LEN1];
     997             :   int i;
     998             : 
     999             :   // Update the x_fft_buf block position.
    1000           0 :   (*x_fft_buf_block_pos)--;
    1001           0 :   if ((*x_fft_buf_block_pos) == -1) {
    1002           0 :     *x_fft_buf_block_pos = num_partitions - 1;
    1003             :   }
    1004             : 
    1005             :   // Buffer x_fft.
    1006           0 :   memcpy(x_fft_buf[0] + (*x_fft_buf_block_pos) * PART_LEN1, x_fft,
    1007           0 :          sizeof(float) * PART_LEN1);
    1008           0 :   memcpy(x_fft_buf[1] + (*x_fft_buf_block_pos) * PART_LEN1, &x_fft[PART_LEN1],
    1009           0 :          sizeof(float) * PART_LEN1);
    1010             : 
    1011           0 :   memset(s_fft, 0, sizeof(s_fft));
    1012             : 
    1013             :   // Conditionally reset the echo subtraction filter if the filter has diverged
    1014             :   // significantly.
    1015           0 :   if (!extended_filter_enabled && *extreme_filter_divergence) {
    1016             :     memset(h_fft_buf, 0,
    1017           0 :            2 * kExtendedNumPartitions * PART_LEN1 * sizeof(h_fft_buf[0][0]));
    1018           0 :     *extreme_filter_divergence = 0;
    1019             :   }
    1020             : 
    1021             :   // Produce echo estimate s_fft.
    1022           0 :   WebRtcAec_FilterFar(num_partitions, *x_fft_buf_block_pos, x_fft_buf,
    1023           0 :                       h_fft_buf, s_fft);
    1024             : 
    1025             :   // Compute the time-domain echo estimate s.
    1026           0 :   ScaledInverseFft(ooura_fft, s_fft, s_extended, 2.0f, 0);
    1027           0 :   s = &s_extended[PART_LEN];
    1028             : 
    1029             :   // Compute the time-domain echo prediction error.
    1030           0 :   for (i = 0; i < PART_LEN; ++i) {
    1031           0 :     e[i] = y[i] - s[i];
    1032             :   }
    1033             : 
    1034             :   // Compute the frequency domain echo prediction error.
    1035           0 :   memset(e_extended, 0, sizeof(float) * PART_LEN);
    1036           0 :   memcpy(e_extended + PART_LEN, e, sizeof(float) * PART_LEN);
    1037           0 :   Fft(ooura_fft, e_extended, e_fft);
    1038             : 
    1039             :   // Scale error signal inversely with far power.
    1040           0 :   WebRtcAec_ScaleErrorSignal(filter_step_size, error_threshold, x_pow, e_fft);
    1041           0 :   WebRtcAec_FilterAdaptation(ooura_fft, num_partitions, *x_fft_buf_block_pos,
    1042           0 :                              x_fft_buf, e_fft, h_fft_buf);
    1043           0 :   memcpy(echo_subtractor_output, e, sizeof(float) * PART_LEN);
    1044           0 : }
    1045             : 
    1046           0 : static void FormSuppressionGain(AecCore* aec,
    1047             :                                 float cohde[PART_LEN1],
    1048             :                                 float cohxd[PART_LEN1],
    1049             :                                 float hNl[PART_LEN1]) {
    1050             :   float hNlDeAvg, hNlXdAvg;
    1051             :   float hNlPref[kPrefBandSize];
    1052           0 :   float hNlFb = 0, hNlFbLow = 0;
    1053           0 :   const int prefBandSize = kPrefBandSize / aec->mult;
    1054           0 :   const float prefBandQuant = 0.75f, prefBandQuantLow = 0.5f;
    1055           0 :   const int minPrefBand = 4 / aec->mult;
    1056             :   // Power estimate smoothing coefficients.
    1057           0 :   const float* min_overdrive = aec->extended_filter_enabled
    1058             :                                    ? kExtendedMinOverDrive
    1059           0 :                                    : kNormalMinOverDrive;
    1060             : 
    1061           0 :   hNlXdAvg = 0;
    1062           0 :   for (int i = minPrefBand; i < prefBandSize + minPrefBand; ++i) {
    1063           0 :     hNlXdAvg += cohxd[i];
    1064             :   }
    1065           0 :   hNlXdAvg /= prefBandSize;
    1066           0 :   hNlXdAvg = 1 - hNlXdAvg;
    1067             : 
    1068           0 :   hNlDeAvg = 0;
    1069           0 :   for (int i = minPrefBand; i < prefBandSize + minPrefBand; ++i) {
    1070           0 :     hNlDeAvg += cohde[i];
    1071             :   }
    1072           0 :   hNlDeAvg /= prefBandSize;
    1073             : 
    1074           0 :   if (hNlXdAvg < 0.75f && hNlXdAvg < aec->hNlXdAvgMin) {
    1075           0 :     aec->hNlXdAvgMin = hNlXdAvg;
    1076             :   }
    1077             : 
    1078           0 :   if (hNlDeAvg > 0.98f && hNlXdAvg > 0.9f) {
    1079           0 :     aec->stNearState = 1;
    1080           0 :   } else if (hNlDeAvg < 0.95f || hNlXdAvg < 0.8f) {
    1081           0 :     aec->stNearState = 0;
    1082             :   }
    1083             : 
    1084           0 :   if (aec->hNlXdAvgMin == 1) {
    1085           0 :     aec->echoState = 0;
    1086           0 :     aec->overDrive = min_overdrive[aec->nlp_mode];
    1087             : 
    1088           0 :     if (aec->stNearState == 1) {
    1089           0 :       memcpy(hNl, cohde, sizeof(hNl[0]) * PART_LEN1);
    1090           0 :       hNlFb = hNlDeAvg;
    1091           0 :       hNlFbLow = hNlDeAvg;
    1092             :     } else {
    1093           0 :       for (int i = 0; i < PART_LEN1; ++i) {
    1094           0 :         hNl[i] = 1 - cohxd[i];
    1095             :       }
    1096           0 :       hNlFb = hNlXdAvg;
    1097           0 :       hNlFbLow = hNlXdAvg;
    1098             :     }
    1099             :   } else {
    1100           0 :     if (aec->stNearState == 1) {
    1101           0 :       aec->echoState = 0;
    1102           0 :       memcpy(hNl, cohde, sizeof(hNl[0]) * PART_LEN1);
    1103           0 :       hNlFb = hNlDeAvg;
    1104           0 :       hNlFbLow = hNlDeAvg;
    1105             :     } else {
    1106           0 :       aec->echoState = 1;
    1107           0 :       for (int i = 0; i < PART_LEN1; ++i) {
    1108           0 :         hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]);
    1109             :       }
    1110             : 
    1111             :       // Select an order statistic from the preferred bands.
    1112             :       // TODO(peah): Using quicksort now, but a selection algorithm may be
    1113             :       // preferred.
    1114           0 :       memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize);
    1115           0 :       qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat);
    1116           0 :       hNlFb = hNlPref[static_cast<int>(floor(prefBandQuant *
    1117           0 :                                              (prefBandSize - 1)))];
    1118           0 :       hNlFbLow = hNlPref[static_cast<int>(floor(prefBandQuantLow *
    1119           0 :                                                 (prefBandSize - 1)))];
    1120             :     }
    1121             :   }
    1122             : 
    1123             :   // Track the local filter minimum to determine suppression overdrive.
    1124           0 :   if (hNlFbLow < 0.6f && hNlFbLow < aec->hNlFbLocalMin) {
    1125           0 :     aec->hNlFbLocalMin = hNlFbLow;
    1126           0 :     aec->hNlFbMin = hNlFbLow;
    1127           0 :     aec->hNlNewMin = 1;
    1128           0 :     aec->hNlMinCtr = 0;
    1129             :   }
    1130           0 :   aec->hNlFbLocalMin =
    1131           0 :       WEBRTC_SPL_MIN(aec->hNlFbLocalMin + 0.0008f / aec->mult, 1);
    1132           0 :   aec->hNlXdAvgMin = WEBRTC_SPL_MIN(aec->hNlXdAvgMin + 0.0006f / aec->mult, 1);
    1133             : 
    1134           0 :   if (aec->hNlNewMin == 1) {
    1135           0 :     aec->hNlMinCtr++;
    1136             :   }
    1137           0 :   if (aec->hNlMinCtr == 2) {
    1138           0 :     aec->hNlNewMin = 0;
    1139           0 :     aec->hNlMinCtr = 0;
    1140           0 :     aec->overDrive =
    1141           0 :         WEBRTC_SPL_MAX(kTargetSupp[aec->nlp_mode] /
    1142             :                        static_cast<float>(log(aec->hNlFbMin + 1e-10f) + 1e-10f),
    1143             :                        min_overdrive[aec->nlp_mode]);
    1144             :   }
    1145             : 
    1146             :   // Smooth the overdrive.
    1147           0 :   if (aec->overDrive < aec->overdrive_scaling) {
    1148           0 :     aec->overdrive_scaling =
    1149           0 :         0.99f * aec->overdrive_scaling + 0.01f * aec->overDrive;
    1150             :   } else {
    1151           0 :     aec->overdrive_scaling =
    1152           0 :         0.9f * aec->overdrive_scaling + 0.1f * aec->overDrive;
    1153             :   }
    1154             : 
    1155             :   // Apply the overdrive.
    1156           0 :   WebRtcAec_Overdrive(aec->overdrive_scaling, hNlFb, hNl);
    1157           0 : }
    1158             : 
    1159           0 : static void EchoSuppression(const OouraFft& ooura_fft,
    1160             :                             AecCore* aec,
    1161             :                             float* nearend_extended_block_lowest_band,
    1162             :                             float farend_extended_block[PART_LEN2],
    1163             :                             float* echo_subtractor_output,
    1164             :                             float output[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) {
    1165             :   float efw[2][PART_LEN1];
    1166             :   float xfw[2][PART_LEN1];
    1167             :   float dfw[2][PART_LEN1];
    1168             :   float comfortNoiseHband[2][PART_LEN1];
    1169             :   float fft[PART_LEN2];
    1170             :   float nlpGainHband;
    1171             :   int i;
    1172             :   size_t j;
    1173             : 
    1174             :   // Coherence and non-linear filter
    1175             :   float cohde[PART_LEN1], cohxd[PART_LEN1];
    1176             :   float hNl[PART_LEN1];
    1177             : 
    1178             :   // Filter energy
    1179           0 :   const int delayEstInterval = 10 * aec->mult;
    1180             : 
    1181           0 :   float* xfw_ptr = NULL;
    1182             : 
    1183             :   // Update eBuf with echo subtractor output.
    1184           0 :   memcpy(aec->eBuf + PART_LEN, echo_subtractor_output,
    1185           0 :          sizeof(float) * PART_LEN);
    1186             : 
    1187             :   // Analysis filter banks for the echo suppressor.
    1188             :   // Windowed near-end ffts.
    1189           0 :   WindowData(fft, nearend_extended_block_lowest_band);
    1190           0 :   ooura_fft.Fft(fft);
    1191           0 :   StoreAsComplex(fft, dfw);
    1192             : 
    1193             :   // Windowed echo suppressor output ffts.
    1194           0 :   WindowData(fft, aec->eBuf);
    1195           0 :   ooura_fft.Fft(fft);
    1196           0 :   StoreAsComplex(fft, efw);
    1197             : 
    1198             :   // NLP
    1199             : 
    1200             :   // Convert far-end partition to the frequency domain with windowing.
    1201           0 :   WindowData(fft, farend_extended_block);
    1202           0 :   Fft(ooura_fft, fft, xfw);
    1203           0 :   xfw_ptr = &xfw[0][0];
    1204             : 
    1205             :   // Buffer far.
    1206           0 :   memcpy(aec->xfwBuf, xfw_ptr, sizeof(float) * 2 * PART_LEN1);
    1207             : 
    1208           0 :   aec->delayEstCtr++;
    1209           0 :   if (aec->delayEstCtr == delayEstInterval) {
    1210           0 :     aec->delayEstCtr = 0;
    1211           0 :     aec->delayIdx = WebRtcAec_PartitionDelay(aec->num_partitions, aec->wfBuf);
    1212             :   }
    1213             : 
    1214           0 :   aec->data_dumper->DumpRaw("aec_nlp_delay", 1, &aec->delayIdx);
    1215             : 
    1216             :   // Use delayed far.
    1217           0 :   memcpy(xfw, aec->xfwBuf + aec->delayIdx * PART_LEN1,
    1218           0 :          sizeof(xfw[0][0]) * 2 * PART_LEN1);
    1219             : 
    1220           0 :   WebRtcAec_UpdateCoherenceSpectra(aec->mult, aec->extended_filter_enabled == 1,
    1221             :                                    efw, dfw, xfw, &aec->coherence_state,
    1222             :                                    &aec->divergeState,
    1223           0 :                                    &aec->extreme_filter_divergence);
    1224             : 
    1225           0 :   WebRtcAec_ComputeCoherence(&aec->coherence_state, cohde, cohxd);
    1226             : 
    1227             :   // Select the microphone signal as output if the filter is deemed to have
    1228             :   // diverged.
    1229           0 :   if (aec->divergeState) {
    1230           0 :     memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
    1231             :   }
    1232             : 
    1233           0 :   FormSuppressionGain(aec, cohde, cohxd, hNl);
    1234             : 
    1235           0 :   aec->data_dumper->DumpRaw("aec_nlp_gain", PART_LEN1, hNl);
    1236             : 
    1237           0 :   WebRtcAec_Suppress(hNl, efw);
    1238             : 
    1239             :   // Add comfort noise.
    1240           0 :   ComfortNoise(aec->num_bands > 1, &aec->seed, efw, comfortNoiseHband,
    1241           0 :                aec->noisePow, hNl);
    1242             : 
    1243             :   // Inverse error fft.
    1244           0 :   ScaledInverseFft(ooura_fft, efw, fft, 2.0f, 1);
    1245             : 
    1246             :   // Overlap and add to obtain output.
    1247           0 :   for (i = 0; i < PART_LEN; i++) {
    1248           0 :     output[0][i] = (fft[i] * WebRtcAec_sqrtHanning[i] +
    1249           0 :                     aec->outBuf[i] * WebRtcAec_sqrtHanning[PART_LEN - i]);
    1250             : 
    1251             :     // Saturate output to keep it in the allowed range.
    1252           0 :     output[0][i] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, output[0][i],
    1253             :                                   WEBRTC_SPL_WORD16_MIN);
    1254             :   }
    1255           0 :   memcpy(aec->outBuf, &fft[PART_LEN], PART_LEN * sizeof(aec->outBuf[0]));
    1256             : 
    1257             :   // For H band
    1258           0 :   if (aec->num_bands > 1) {
    1259             :     // H band gain
    1260             :     // average nlp over low band: average over second half of freq spectrum
    1261             :     // (4->8khz)
    1262           0 :     GetHighbandGain(hNl, &nlpGainHband);
    1263             : 
    1264             :     // Inverse comfort_noise
    1265           0 :     ScaledInverseFft(ooura_fft, comfortNoiseHband, fft, 2.0f, 0);
    1266             : 
    1267             :     // compute gain factor
    1268           0 :     for (j = 1; j < aec->num_bands; ++j) {
    1269           0 :       for (i = 0; i < PART_LEN; i++) {
    1270           0 :         output[j][i] = aec->previous_nearend_block[j][i] * nlpGainHband;
    1271             :       }
    1272             :     }
    1273             : 
    1274             :     // Add some comfort noise where Hband is attenuated.
    1275           0 :     for (i = 0; i < PART_LEN; i++) {
    1276           0 :       output[1][i] += cnScaleHband * fft[i];
    1277             :     }
    1278             : 
    1279             :     // Saturate output to keep it in the allowed range.
    1280           0 :     for (j = 1; j < aec->num_bands; ++j) {
    1281           0 :       for (i = 0; i < PART_LEN; i++) {
    1282           0 :         output[j][i] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, output[j][i],
    1283             :                                       WEBRTC_SPL_WORD16_MIN);
    1284             :       }
    1285             :     }
    1286             :   }
    1287             : 
    1288             :   // Copy the current block to the old position.
    1289           0 :   memcpy(aec->eBuf, aec->eBuf + PART_LEN, sizeof(float) * PART_LEN);
    1290             : 
    1291           0 :   memmove(aec->xfwBuf + PART_LEN1, aec->xfwBuf,
    1292           0 :           sizeof(aec->xfwBuf) - sizeof(complex_t) * PART_LEN1);
    1293           0 : }
    1294             : 
    1295           0 : static void ProcessNearendBlock(
    1296             :     AecCore* aec,
    1297             :     float farend_extended_block_lowest_band[PART_LEN2],
    1298             :     float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN],
    1299             :     float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) {
    1300             :   size_t i;
    1301             : 
    1302             :   float fft[PART_LEN2];
    1303             :   float nearend_extended_block_lowest_band[PART_LEN2];
    1304             :   float farend_fft[2][PART_LEN1];
    1305             :   float nearend_fft[2][PART_LEN1];
    1306           0 :   float far_spectrum = 0.0f;
    1307           0 :   float near_spectrum = 0.0f;
    1308             :   float abs_far_spectrum[PART_LEN1];
    1309             :   float abs_near_spectrum[PART_LEN1];
    1310             : 
    1311             :   const float gPow[2] = {0.9f, 0.1f};
    1312             : 
    1313             :   // Noise estimate constants.
    1314           0 :   const int noiseInitBlocks = 500 * aec->mult;
    1315           0 :   const float step = 0.1f;
    1316           0 :   const float ramp = 1.0002f;
    1317             :   const float gInitNoise[2] = {0.999f, 0.001f};
    1318             : 
    1319             :   float echo_subtractor_output[PART_LEN];
    1320             : 
    1321           0 :   aec->data_dumper->DumpWav("aec_far", PART_LEN,
    1322           0 :                             &farend_extended_block_lowest_band[PART_LEN],
    1323           0 :                             std::min(aec->sampFreq, 16000), 1);
    1324           0 :   aec->data_dumper->DumpWav("aec_near", PART_LEN, &nearend_block[0][0],
    1325           0 :                             std::min(aec->sampFreq, 16000), 1);
    1326             : 
    1327           0 :   if (aec->metricsMode == 1) {
    1328             :     // Update power levels
    1329           0 :     UpdateLevel(
    1330             :         &aec->farlevel,
    1331           0 :         CalculatePower(&farend_extended_block_lowest_band[PART_LEN], PART_LEN));
    1332           0 :     UpdateLevel(&aec->nearlevel,
    1333           0 :                 CalculatePower(&nearend_block[0][0], PART_LEN));
    1334             :   }
    1335             : 
    1336             :   // Convert far-end signal to the frequency domain.
    1337           0 :   memcpy(fft, farend_extended_block_lowest_band, sizeof(float) * PART_LEN2);
    1338           0 :   Fft(aec->ooura_fft, fft, farend_fft);
    1339             : 
    1340             :   // Form extended nearend frame.
    1341             :   memcpy(&nearend_extended_block_lowest_band[0],
    1342           0 :          &aec->previous_nearend_block[0][0], sizeof(float) * PART_LEN);
    1343           0 :   memcpy(&nearend_extended_block_lowest_band[PART_LEN], &nearend_block[0][0],
    1344           0 :          sizeof(float) * PART_LEN);
    1345             : 
    1346             :   // Convert near-end signal to the frequency domain.
    1347           0 :   memcpy(fft, nearend_extended_block_lowest_band, sizeof(float) * PART_LEN2);
    1348           0 :   Fft(aec->ooura_fft, fft, nearend_fft);
    1349             : 
    1350             :   // Power smoothing.
    1351           0 :   if (aec->refined_adaptive_filter_enabled) {
    1352           0 :     for (i = 0; i < PART_LEN1; ++i) {
    1353           0 :       far_spectrum = farend_fft[0][i] * farend_fft[0][i] +
    1354           0 :                      farend_fft[1][i] * farend_fft[1][i];
    1355             :       // Calculate the magnitude spectrum.
    1356           0 :       abs_far_spectrum[i] = sqrtf(far_spectrum);
    1357             :     }
    1358           0 :     RegressorPower(aec->num_partitions, aec->xfBufBlockPos, aec->xfBuf,
    1359           0 :                    aec->xPow);
    1360             :   } else {
    1361           0 :     for (i = 0; i < PART_LEN1; ++i) {
    1362           0 :       far_spectrum = farend_fft[0][i] * farend_fft[0][i] +
    1363           0 :                      farend_fft[1][i] * farend_fft[1][i];
    1364           0 :       aec->xPow[i] =
    1365           0 :           gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum;
    1366             :       // Calculate the magnitude spectrum.
    1367           0 :       abs_far_spectrum[i] = sqrtf(far_spectrum);
    1368             :     }
    1369             :   }
    1370             : 
    1371           0 :   for (i = 0; i < PART_LEN1; ++i) {
    1372           0 :     near_spectrum = nearend_fft[0][i] * nearend_fft[0][i] +
    1373           0 :                     nearend_fft[1][i] * nearend_fft[1][i];
    1374           0 :     aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum;
    1375             :     // Calculate the magnitude spectrum.
    1376           0 :     abs_near_spectrum[i] = sqrtf(near_spectrum);
    1377             :   }
    1378             : 
    1379             :   // Estimate noise power. Wait until dPow is more stable.
    1380           0 :   if (aec->noiseEstCtr > 50) {
    1381           0 :     for (i = 0; i < PART_LEN1; i++) {
    1382           0 :       if (aec->dPow[i] < aec->dMinPow[i]) {
    1383           0 :         aec->dMinPow[i] =
    1384           0 :             (aec->dPow[i] + step * (aec->dMinPow[i] - aec->dPow[i])) * ramp;
    1385             :       } else {
    1386           0 :         aec->dMinPow[i] *= ramp;
    1387             :       }
    1388             :     }
    1389             :   }
    1390             : 
    1391             :   // Smooth increasing noise power from zero at the start,
    1392             :   // to avoid a sudden burst of comfort noise.
    1393           0 :   if (aec->noiseEstCtr < noiseInitBlocks) {
    1394           0 :     aec->noiseEstCtr++;
    1395           0 :     for (i = 0; i < PART_LEN1; i++) {
    1396           0 :       if (aec->dMinPow[i] > aec->dInitMinPow[i]) {
    1397           0 :         aec->dInitMinPow[i] = gInitNoise[0] * aec->dInitMinPow[i] +
    1398           0 :                               gInitNoise[1] * aec->dMinPow[i];
    1399             :       } else {
    1400           0 :         aec->dInitMinPow[i] = aec->dMinPow[i];
    1401             :       }
    1402             :     }
    1403           0 :     aec->noisePow = aec->dInitMinPow;
    1404             :   } else {
    1405           0 :     aec->noisePow = aec->dMinPow;
    1406             :   }
    1407             : 
    1408             :   // Block wise delay estimation used for logging
    1409           0 :   if (aec->delay_logging_enabled) {
    1410           0 :     if (WebRtc_AddFarSpectrumFloat(aec->delay_estimator_farend,
    1411             :                                    abs_far_spectrum, PART_LEN1) == 0) {
    1412           0 :       int delay_estimate = WebRtc_DelayEstimatorProcessFloat(
    1413           0 :           aec->delay_estimator, abs_near_spectrum, PART_LEN1);
    1414           0 :       if (delay_estimate >= 0) {
    1415             :         // Update delay estimate buffer.
    1416           0 :         aec->delay_histogram[delay_estimate]++;
    1417           0 :         aec->num_delay_values++;
    1418             :       }
    1419           0 :       if (aec->delay_metrics_delivered == 1 &&
    1420           0 :           aec->num_delay_values >= kDelayMetricsAggregationWindow) {
    1421           0 :         UpdateDelayMetrics(aec);
    1422             :       }
    1423             :     }
    1424             :   }
    1425             : 
    1426             :   // Perform echo subtraction.
    1427           0 :   EchoSubtraction(
    1428             :       aec->ooura_fft, aec->num_partitions, aec->extended_filter_enabled,
    1429             :       &aec->extreme_filter_divergence, aec->filter_step_size,
    1430             :       aec->error_threshold, &farend_fft[0][0], &aec->xfBufBlockPos, aec->xfBuf,
    1431           0 :       &nearend_block[0][0], aec->xPow, aec->wfBuf, echo_subtractor_output);
    1432           0 :   aec->data_dumper->DumpRaw("aec_h_fft", PART_LEN1 * aec->num_partitions,
    1433           0 :                             &aec->wfBuf[0][0]);
    1434           0 :   aec->data_dumper->DumpRaw("aec_h_fft", PART_LEN1 * aec->num_partitions,
    1435           0 :                             &aec->wfBuf[1][0]);
    1436             : 
    1437           0 :   aec->data_dumper->DumpWav("aec_out_linear", PART_LEN, echo_subtractor_output,
    1438           0 :                             std::min(aec->sampFreq, 16000), 1);
    1439             : 
    1440           0 :   if (aec->metricsMode == 1) {
    1441           0 :     UpdateLevel(&aec->linoutlevel,
    1442           0 :                 CalculatePower(echo_subtractor_output, PART_LEN));
    1443             :   }
    1444             : 
    1445             :   // Perform echo suppression.
    1446           0 :   EchoSuppression(aec->ooura_fft, aec, nearend_extended_block_lowest_band,
    1447             :                   farend_extended_block_lowest_band, echo_subtractor_output,
    1448           0 :                   output_block);
    1449             : 
    1450           0 :   if (aec->metricsMode == 1) {
    1451           0 :     UpdateLevel(&aec->nlpoutlevel,
    1452           0 :                 CalculatePower(&output_block[0][0], PART_LEN));
    1453           0 :     UpdateMetrics(aec);
    1454             :   }
    1455             : 
    1456             :   // Store the nearend signal until the next frame.
    1457           0 :   for (i = 0; i < aec->num_bands; ++i) {
    1458           0 :     memcpy(&aec->previous_nearend_block[i][0], &nearend_block[i][0],
    1459           0 :            sizeof(float) * PART_LEN);
    1460             :   }
    1461             : 
    1462           0 :   aec->data_dumper->DumpWav("aec_out", PART_LEN, &output_block[0][0],
    1463           0 :                             std::min(aec->sampFreq, 16000), 1);
    1464           0 : }
    1465             : 
    1466           0 : AecCore* WebRtcAec_CreateAec(int instance_count) {
    1467           0 :   AecCore* aec = new AecCore(instance_count);
    1468             : 
    1469           0 :   if (!aec) {
    1470           0 :     return NULL;
    1471             :   }
    1472           0 :   aec->nearend_buffer_size = 0;
    1473           0 :   memset(&aec->nearend_buffer[0], 0, sizeof(aec->nearend_buffer));
    1474             :   // Start the output buffer with zeros to be able to produce
    1475             :   // a full output frame in the first frame.
    1476           0 :   aec->output_buffer_size = PART_LEN - (FRAME_LEN - PART_LEN);
    1477           0 :   memset(&aec->output_buffer[0], 0, sizeof(aec->output_buffer));
    1478             : 
    1479           0 :   aec->delay_estimator_farend =
    1480           0 :       WebRtc_CreateDelayEstimatorFarend(PART_LEN1, kHistorySizeBlocks);
    1481           0 :   if (aec->delay_estimator_farend == NULL) {
    1482           0 :     WebRtcAec_FreeAec(aec);
    1483           0 :     return NULL;
    1484             :   }
    1485             :   // We create the delay_estimator with the same amount of maximum lookahead as
    1486             :   // the delay history size (kHistorySizeBlocks) for symmetry reasons.
    1487           0 :   aec->delay_estimator = WebRtc_CreateDelayEstimator(
    1488             :       aec->delay_estimator_farend, kHistorySizeBlocks);
    1489           0 :   if (aec->delay_estimator == NULL) {
    1490           0 :     WebRtcAec_FreeAec(aec);
    1491           0 :     return NULL;
    1492             :   }
    1493             : #ifdef WEBRTC_ANDROID
    1494             :   aec->delay_agnostic_enabled = 1;  // DA-AEC enabled by default.
    1495             :   // DA-AEC assumes the system is causal from the beginning and will self adjust
    1496             :   // the lookahead when shifting is required.
    1497             :   WebRtc_set_lookahead(aec->delay_estimator, 0);
    1498             : #else
    1499           0 :   aec->delay_agnostic_enabled = 0;
    1500           0 :   WebRtc_set_lookahead(aec->delay_estimator, kLookaheadBlocks);
    1501             : #endif
    1502           0 :   aec->extended_filter_enabled = 0;
    1503           0 :   aec->refined_adaptive_filter_enabled = false;
    1504             : 
    1505             :   // Assembly optimization
    1506           0 :   WebRtcAec_FilterFar = FilterFar;
    1507           0 :   WebRtcAec_ScaleErrorSignal = ScaleErrorSignal;
    1508           0 :   WebRtcAec_FilterAdaptation = FilterAdaptation;
    1509           0 :   WebRtcAec_Overdrive = Overdrive;
    1510           0 :   WebRtcAec_Suppress = Suppress;
    1511           0 :   WebRtcAec_ComputeCoherence = ComputeCoherence;
    1512           0 :   WebRtcAec_UpdateCoherenceSpectra = UpdateCoherenceSpectra;
    1513           0 :   WebRtcAec_StoreAsComplex = StoreAsComplex;
    1514           0 :   WebRtcAec_PartitionDelay = PartitionDelay;
    1515           0 :   WebRtcAec_WindowData = WindowData;
    1516             : 
    1517             : #if defined(WEBRTC_ARCH_X86_FAMILY)
    1518           0 :   if (WebRtc_GetCPUInfo(kSSE2)) {
    1519           0 :     WebRtcAec_InitAec_SSE2();
    1520             :   }
    1521             : #endif
    1522             : 
    1523             : #if defined(MIPS_FPU_LE)
    1524             :   WebRtcAec_InitAec_mips();
    1525             : #endif
    1526             : 
    1527             : #if defined(WEBRTC_HAS_NEON)
    1528             :   WebRtcAec_InitAec_neon();
    1529             : #endif
    1530             : 
    1531           0 :   return aec;
    1532             : }
    1533             : 
    1534           0 : void WebRtcAec_FreeAec(AecCore* aec) {
    1535           0 :   if (aec == NULL) {
    1536           0 :     return;
    1537             :   }
    1538             : 
    1539           0 :   WebRtc_FreeDelayEstimator(aec->delay_estimator);
    1540           0 :   WebRtc_FreeDelayEstimatorFarend(aec->delay_estimator_farend);
    1541             : 
    1542           0 :   delete aec;
    1543             : }
    1544             : 
    1545           0 : static void SetAdaptiveFilterStepSize(AecCore* aec) {
    1546             :   // Extended filter adaptation parameter.
    1547             :   // TODO(ajm): No narrowband tuning yet.
    1548           0 :   const float kExtendedMu = 0.4f;
    1549             : 
    1550           0 :   if (aec->refined_adaptive_filter_enabled) {
    1551           0 :     aec->filter_step_size = 0.05f;
    1552             :   } else {
    1553           0 :     if (aec->extended_filter_enabled) {
    1554           0 :       aec->filter_step_size = kExtendedMu;
    1555             :     } else {
    1556           0 :       if (aec->sampFreq == 8000) {
    1557           0 :         aec->filter_step_size = 0.6f;
    1558             :       } else {
    1559           0 :         aec->filter_step_size = 0.5f;
    1560             :       }
    1561             :     }
    1562             :   }
    1563           0 : }
    1564             : 
    1565           0 : static void SetErrorThreshold(AecCore* aec) {
    1566             :   // Extended filter adaptation parameter.
    1567             :   // TODO(ajm): No narrowband tuning yet.
    1568             :   static const float kExtendedErrorThreshold = 1.0e-6f;
    1569             : 
    1570           0 :   if (aec->extended_filter_enabled) {
    1571           0 :     aec->error_threshold = kExtendedErrorThreshold;
    1572             :   } else {
    1573           0 :     if (aec->sampFreq == 8000) {
    1574           0 :       aec->error_threshold = 2e-6f;
    1575             :     } else {
    1576           0 :       aec->error_threshold = 1.5e-6f;
    1577             :     }
    1578             :   }
    1579           0 : }
    1580             : 
    1581           0 : int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
    1582             :   int i;
    1583           0 :   aec->data_dumper->InitiateNewSetOfRecordings();
    1584             : 
    1585           0 :   aec->sampFreq = sampFreq;
    1586             : 
    1587           0 :   SetAdaptiveFilterStepSize(aec);
    1588           0 :   SetErrorThreshold(aec);
    1589             : 
    1590           0 :   if (sampFreq == 8000) {
    1591           0 :     aec->num_bands = 1;
    1592             :   } else {
    1593           0 :     aec->num_bands = (size_t)(sampFreq / 16000);
    1594             :   }
    1595             : 
    1596             :   // Start the output buffer with zeros to be able to produce
    1597             :   // a full output frame in the first frame.
    1598           0 :   aec->output_buffer_size = PART_LEN - (FRAME_LEN - PART_LEN);
    1599           0 :   memset(&aec->output_buffer[0], 0, sizeof(aec->output_buffer));
    1600           0 :   aec->nearend_buffer_size = 0;
    1601           0 :   memset(&aec->nearend_buffer[0], 0, sizeof(aec->nearend_buffer));
    1602             : 
    1603             :   // Initialize far-end buffer.
    1604           0 :   aec->farend_block_buffer_.ReInit();
    1605             : 
    1606           0 :   aec->system_delay = 0;
    1607             : 
    1608           0 :   if (WebRtc_InitDelayEstimatorFarend(aec->delay_estimator_farend) != 0) {
    1609           0 :     return -1;
    1610             :   }
    1611           0 :   if (WebRtc_InitDelayEstimator(aec->delay_estimator) != 0) {
    1612           0 :     return -1;
    1613             :   }
    1614           0 :   aec->delay_logging_enabled = 0;
    1615           0 :   aec->delay_metrics_delivered = 0;
    1616           0 :   memset(aec->delay_histogram, 0, sizeof(aec->delay_histogram));
    1617           0 :   aec->num_delay_values = 0;
    1618           0 :   aec->delay_median = -1;
    1619           0 :   aec->delay_std = -1;
    1620           0 :   aec->fraction_poor_delays = -1.0f;
    1621             : 
    1622           0 :   aec->previous_delay = -2;  // (-2): Uninitialized.
    1623           0 :   aec->delay_correction_count = 0;
    1624           0 :   aec->shift_offset = kInitialShiftOffset;
    1625           0 :   aec->delay_quality_threshold = kDelayQualityThresholdMin;
    1626             : 
    1627           0 :   aec->num_partitions = kNormalNumPartitions;
    1628             : 
    1629             :   // Update the delay estimator with filter length.  We use half the
    1630             :   // |num_partitions| to take the echo path into account.  In practice we say
    1631             :   // that the echo has a duration of maximum half |num_partitions|, which is not
    1632             :   // true, but serves as a crude measure.
    1633           0 :   WebRtc_set_allowed_offset(aec->delay_estimator, aec->num_partitions / 2);
    1634             :   // TODO(bjornv): I currently hard coded the enable.  Once we've established
    1635             :   // that AECM has no performance regression, robust_validation will be enabled
    1636             :   // all the time and the APIs to turn it on/off will be removed.  Hence, remove
    1637             :   // this line then.
    1638           0 :   WebRtc_enable_robust_validation(aec->delay_estimator, 1);
    1639           0 :   aec->frame_count = 0;
    1640             : 
    1641             :   // Default target suppression mode.
    1642           0 :   aec->nlp_mode = 1;
    1643             : 
    1644             :   // Sampling frequency multiplier w.r.t. 8 kHz.
    1645             :   // In case of multiple bands we process the lower band in 16 kHz, hence the
    1646             :   // multiplier is always 2.
    1647           0 :   if (aec->num_bands > 1) {
    1648           0 :     aec->mult = 2;
    1649             :   } else {
    1650           0 :     aec->mult = static_cast<int16_t>(aec->sampFreq) / 8000;
    1651             :   }
    1652             : 
    1653           0 :   aec->farBufWritePos = 0;
    1654           0 :   aec->farBufReadPos = 0;
    1655             : 
    1656           0 :   aec->inSamples = 0;
    1657           0 :   aec->outSamples = 0;
    1658           0 :   aec->knownDelay = 0;
    1659             : 
    1660             :   // Initialize buffers
    1661           0 :   memset(aec->previous_nearend_block, 0, sizeof(aec->previous_nearend_block));
    1662           0 :   memset(aec->eBuf, 0, sizeof(aec->eBuf));
    1663             : 
    1664           0 :   memset(aec->xPow, 0, sizeof(aec->xPow));
    1665           0 :   memset(aec->dPow, 0, sizeof(aec->dPow));
    1666           0 :   memset(aec->dInitMinPow, 0, sizeof(aec->dInitMinPow));
    1667           0 :   aec->noisePow = aec->dInitMinPow;
    1668           0 :   aec->noiseEstCtr = 0;
    1669             : 
    1670             :   // Initial comfort noise power
    1671           0 :   for (i = 0; i < PART_LEN1; i++) {
    1672           0 :     aec->dMinPow[i] = 1.0e6f;
    1673             :   }
    1674             : 
    1675             :   // Holds the last block written to
    1676           0 :   aec->xfBufBlockPos = 0;
    1677             :   // TODO(peah): Investigate need for these initializations. Deleting them
    1678             :   // doesn't change the output at all and yields 0.4% overall speedup.
    1679           0 :   memset(aec->xfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
    1680           0 :   memset(aec->wfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
    1681           0 :   memset(aec->coherence_state.sde, 0, sizeof(complex_t) * PART_LEN1);
    1682           0 :   memset(aec->coherence_state.sxd, 0, sizeof(complex_t) * PART_LEN1);
    1683           0 :   memset(aec->xfwBuf, 0,
    1684           0 :          sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
    1685           0 :   memset(aec->coherence_state.se, 0, sizeof(float) * PART_LEN1);
    1686             : 
    1687             :   // To prevent numerical instability in the first block.
    1688           0 :   for (i = 0; i < PART_LEN1; i++) {
    1689           0 :     aec->coherence_state.sd[i] = 1;
    1690             :   }
    1691           0 :   for (i = 0; i < PART_LEN1; i++) {
    1692           0 :     aec->coherence_state.sx[i] = 1;
    1693             :   }
    1694             : 
    1695           0 :   memset(aec->hNs, 0, sizeof(aec->hNs));
    1696           0 :   memset(aec->outBuf, 0, sizeof(float) * PART_LEN);
    1697             : 
    1698           0 :   aec->hNlFbMin = 1;
    1699           0 :   aec->hNlFbLocalMin = 1;
    1700           0 :   aec->hNlXdAvgMin = 1;
    1701           0 :   aec->hNlNewMin = 0;
    1702           0 :   aec->hNlMinCtr = 0;
    1703           0 :   aec->overDrive = 2;
    1704           0 :   aec->overdrive_scaling = 2;
    1705           0 :   aec->delayIdx = 0;
    1706           0 :   aec->stNearState = 0;
    1707           0 :   aec->echoState = 0;
    1708           0 :   aec->divergeState = 0;
    1709             : 
    1710           0 :   aec->seed = 777;
    1711           0 :   aec->delayEstCtr = 0;
    1712             : 
    1713           0 :   aec->extreme_filter_divergence = 0;
    1714             : 
    1715             :   // Metrics disabled by default
    1716           0 :   aec->metricsMode = 0;
    1717           0 :   InitMetrics(aec);
    1718             : 
    1719           0 :   return 0;
    1720             : }
    1721             : 
    1722           0 : void WebRtcAec_BufferFarendBlock(AecCore* aec, const float* farend) {
    1723             :   // Check if the buffer is full, and in that case flush the oldest data.
    1724           0 :   if (aec->farend_block_buffer_.AvaliableSpace() < 1) {
    1725           0 :     aec->farend_block_buffer_.AdjustSize(1);
    1726             :   }
    1727           0 :   aec->farend_block_buffer_.Insert(farend);
    1728           0 : }
    1729             : 
    1730           0 : int WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(AecCore* aec,
    1731             :                                                    int buffer_size_decrease) {
    1732             :   int achieved_buffer_size_decrease =
    1733           0 :       aec->farend_block_buffer_.AdjustSize(buffer_size_decrease);
    1734           0 :   aec->system_delay -= achieved_buffer_size_decrease * PART_LEN;
    1735           0 :   return achieved_buffer_size_decrease;
    1736             : }
    1737             : 
    1738           0 : void FormNearendBlock(
    1739             :     size_t nearend_start_index,
    1740             :     size_t num_bands,
    1741             :     const float* const* nearend_frame,
    1742             :     size_t num_samples_from_nearend_frame,
    1743             :     const float nearend_buffer[NUM_HIGH_BANDS_MAX + 1]
    1744             :                               [PART_LEN - (FRAME_LEN - PART_LEN)],
    1745             :     float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) {
    1746           0 :   RTC_DCHECK_LE(num_samples_from_nearend_frame, PART_LEN);
    1747           0 :   const int num_samples_from_buffer = PART_LEN - num_samples_from_nearend_frame;
    1748             : 
    1749           0 :   if (num_samples_from_buffer > 0) {
    1750           0 :     for (size_t i = 0; i < num_bands; ++i) {
    1751           0 :       memcpy(&nearend_block[i][0], &nearend_buffer[i][0],
    1752           0 :              num_samples_from_buffer * sizeof(float));
    1753             :     }
    1754             :   }
    1755             : 
    1756           0 :   for (size_t i = 0; i < num_bands; ++i) {
    1757           0 :     memcpy(&nearend_block[i][num_samples_from_buffer],
    1758           0 :            &nearend_frame[i][nearend_start_index],
    1759           0 :            num_samples_from_nearend_frame * sizeof(float));
    1760             :   }
    1761           0 : }
    1762             : 
    1763           0 : void BufferNearendFrame(
    1764             :     size_t nearend_start_index,
    1765             :     size_t num_bands,
    1766             :     const float* const* nearend_frame,
    1767             :     size_t num_samples_to_buffer,
    1768             :     float nearend_buffer[NUM_HIGH_BANDS_MAX + 1]
    1769             :                         [PART_LEN - (FRAME_LEN - PART_LEN)]) {
    1770           0 :   for (size_t i = 0; i < num_bands; ++i) {
    1771           0 :     memcpy(
    1772           0 :         &nearend_buffer[i][0],
    1773           0 :         &nearend_frame[i]
    1774           0 :                       [nearend_start_index + FRAME_LEN - num_samples_to_buffer],
    1775           0 :         num_samples_to_buffer * sizeof(float));
    1776             :   }
    1777           0 : }
    1778             : 
    1779           0 : void BufferOutputBlock(size_t num_bands,
    1780             :                        const float output_block[NUM_HIGH_BANDS_MAX + 1]
    1781             :                                                [PART_LEN],
    1782             :                        size_t* output_buffer_size,
    1783             :                        float output_buffer[NUM_HIGH_BANDS_MAX + 1]
    1784             :                                           [2 * PART_LEN]) {
    1785           0 :   for (size_t i = 0; i < num_bands; ++i) {
    1786           0 :     memcpy(&output_buffer[i][*output_buffer_size], &output_block[i][0],
    1787           0 :            PART_LEN * sizeof(float));
    1788             :   }
    1789           0 :   (*output_buffer_size) += PART_LEN;
    1790           0 : }
    1791             : 
    1792           0 : void FormOutputFrame(size_t output_start_index,
    1793             :                      size_t num_bands,
    1794             :                      size_t* output_buffer_size,
    1795             :                      float output_buffer[NUM_HIGH_BANDS_MAX + 1][2 * PART_LEN],
    1796             :                      float* const* output_frame) {
    1797           0 :   RTC_DCHECK_LE(FRAME_LEN, *output_buffer_size);
    1798           0 :   for (size_t i = 0; i < num_bands; ++i) {
    1799           0 :     memcpy(&output_frame[i][output_start_index], &output_buffer[i][0],
    1800           0 :            FRAME_LEN * sizeof(float));
    1801             :   }
    1802           0 :   (*output_buffer_size) -= FRAME_LEN;
    1803           0 :   if (*output_buffer_size > 0) {
    1804           0 :     RTC_DCHECK_GE(2 * PART_LEN - FRAME_LEN, (*output_buffer_size));
    1805           0 :     for (size_t i = 0; i < num_bands; ++i) {
    1806           0 :       memcpy(&output_buffer[i][0], &output_buffer[i][FRAME_LEN],
    1807           0 :              (*output_buffer_size) * sizeof(float));
    1808             :     }
    1809             :   }
    1810           0 : }
    1811             : 
    1812           0 : void WebRtcAec_ProcessFrames(AecCore* aec,
    1813             :                              const float* const* nearend,
    1814             :                              size_t num_bands,
    1815             :                              size_t num_samples,
    1816             :                              int knownDelay,
    1817             :                              float* const* out) {
    1818           0 :   RTC_DCHECK(num_samples == 80 || num_samples == 160);
    1819             : 
    1820           0 :   aec->frame_count++;
    1821             :   // For each frame the process is as follows:
    1822             :   // 1) If the system_delay indicates on being too small for processing a
    1823             :   //    frame we stuff the buffer with enough data for 10 ms.
    1824             :   // 2 a) Adjust the buffer to the system delay, by moving the read pointer.
    1825             :   //   b) Apply signal based delay correction, if we have detected poor AEC
    1826             :   //    performance.
    1827             :   // 3) TODO(bjornv): Investigate if we need to add this:
    1828             :   //    If we can't move read pointer due to buffer size limitations we
    1829             :   //    flush/stuff the buffer.
    1830             :   // 4) Process as many partitions as possible.
    1831             :   // 5) Update the |system_delay| with respect to a full frame of FRAME_LEN
    1832             :   //    samples. Even though we will have data left to process (we work with
    1833             :   //    partitions) we consider updating a whole frame, since that's the
    1834             :   //    amount of data we input and output in audio_processing.
    1835             :   // 6) Update the outputs.
    1836             : 
    1837             :   // The AEC has two different delay estimation algorithms built in.  The
    1838             :   // first relies on delay input values from the user and the amount of
    1839             :   // shifted buffer elements is controlled by |knownDelay|.  This delay will
    1840             :   // give a guess on how much we need to shift far-end buffers to align with
    1841             :   // the near-end signal.  The other delay estimation algorithm uses the
    1842             :   // far- and near-end signals to find the offset between them.  This one
    1843             :   // (called "signal delay") is then used to fine tune the alignment, or
    1844             :   // simply compensate for errors in the system based one.
    1845             :   // Note that the two algorithms operate independently.  Currently, we only
    1846             :   // allow one algorithm to be turned on.
    1847             : 
    1848           0 :   RTC_DCHECK_EQ(aec->num_bands, num_bands);
    1849             : 
    1850           0 :   for (size_t j = 0; j < num_samples; j += FRAME_LEN) {
    1851             :     // 1) At most we process |aec->mult|+1 partitions in 10 ms. Make sure we
    1852             :     // have enough far-end data for that by stuffing the buffer if the
    1853             :     // |system_delay| indicates others.
    1854           0 :     if (aec->system_delay < FRAME_LEN) {
    1855             :       // We don't have enough data so we rewind 10 ms.
    1856           0 :       WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aec, -(aec->mult + 1));
    1857             :     }
    1858             : 
    1859           0 :     if (!aec->delay_agnostic_enabled) {
    1860             :       // 2 a) Compensate for a possible change in the system delay.
    1861             : 
    1862             :       // TODO(bjornv): Investigate how we should round the delay difference;
    1863             :       // right now we know that incoming |knownDelay| is underestimated when
    1864             :       // it's less than |aec->knownDelay|. We therefore, round (-32) in that
    1865             :       // direction. In the other direction, we don't have this situation, but
    1866             :       // might flush one partition too little. This can cause non-causality,
    1867             :       // which should be investigated. Maybe, allow for a non-symmetric
    1868             :       // rounding, like -16.
    1869           0 :       int move_elements = (aec->knownDelay - knownDelay - 32) / PART_LEN;
    1870           0 :       int moved_elements = aec->farend_block_buffer_.AdjustSize(move_elements);
    1871           0 :       MaybeLogDelayAdjustment(moved_elements * (aec->sampFreq == 8000 ? 8 : 4),
    1872           0 :                               DelaySource::kSystemDelay);
    1873           0 :       aec->knownDelay -= moved_elements * PART_LEN;
    1874             :     } else {
    1875             :       // 2 b) Apply signal based delay correction.
    1876           0 :       int move_elements = SignalBasedDelayCorrection(aec);
    1877           0 :       int moved_elements = aec->farend_block_buffer_.AdjustSize(move_elements);
    1878           0 :       MaybeLogDelayAdjustment(moved_elements * (aec->sampFreq == 8000 ? 8 : 4),
    1879           0 :                               DelaySource::kDelayAgnostic);
    1880             :       int far_near_buffer_diff =
    1881           0 :           aec->farend_block_buffer_.Size() -
    1882           0 :           (aec->nearend_buffer_size + FRAME_LEN) / PART_LEN;
    1883           0 :       WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements);
    1884           0 :       WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend,
    1885           0 :                                            moved_elements);
    1886             :       // If we rely on reported system delay values only, a buffer underrun here
    1887             :       // can never occur since we've taken care of that in 1) above.  Here, we
    1888             :       // apply signal based delay correction and can therefore end up with
    1889             :       // buffer underruns since the delay estimation can be wrong.  We therefore
    1890             :       // stuff the buffer with enough elements if needed.
    1891           0 :       if (far_near_buffer_diff < 0) {
    1892             :         WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aec,
    1893           0 :                                                        far_near_buffer_diff);
    1894             :       }
    1895             :     }
    1896             : 
    1897             :     static_assert(
    1898             :         16 == (FRAME_LEN - PART_LEN),
    1899             :         "These constants need to be properly related for this code to work");
    1900             :     float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN];
    1901             :     float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN];
    1902             :     float farend_extended_block_lowest_band[PART_LEN2];
    1903             : 
    1904             :     // Form and process a block of nearend samples, buffer the output block of
    1905             :     // samples.
    1906           0 :     aec->farend_block_buffer_.ExtractExtendedBlock(
    1907           0 :         farend_extended_block_lowest_band);
    1908           0 :     FormNearendBlock(j, num_bands, nearend, PART_LEN - aec->nearend_buffer_size,
    1909           0 :                      aec->nearend_buffer, nearend_block);
    1910             :     ProcessNearendBlock(aec, farend_extended_block_lowest_band, nearend_block,
    1911           0 :                         output_block);
    1912           0 :     BufferOutputBlock(num_bands, output_block, &aec->output_buffer_size,
    1913           0 :                       aec->output_buffer);
    1914             : 
    1915           0 :     if ((FRAME_LEN - PART_LEN + aec->nearend_buffer_size) == PART_LEN) {
    1916             :       // When possible (every fourth frame) form and process a second block of
    1917             :       // nearend samples, buffer the output block of samples.
    1918           0 :       aec->farend_block_buffer_.ExtractExtendedBlock(
    1919           0 :           farend_extended_block_lowest_band);
    1920           0 :       FormNearendBlock(j + FRAME_LEN - PART_LEN, num_bands, nearend, PART_LEN,
    1921           0 :                        aec->nearend_buffer, nearend_block);
    1922             :       ProcessNearendBlock(aec, farend_extended_block_lowest_band, nearend_block,
    1923           0 :                           output_block);
    1924           0 :       BufferOutputBlock(num_bands, output_block, &aec->output_buffer_size,
    1925           0 :                         aec->output_buffer);
    1926             : 
    1927             :       // Reset the buffer size as there are no samples left in the nearend input
    1928             :       // to buffer.
    1929           0 :       aec->nearend_buffer_size = 0;
    1930             :     } else {
    1931             :       // Buffer the remaining samples in the nearend input.
    1932           0 :       aec->nearend_buffer_size += FRAME_LEN - PART_LEN;
    1933           0 :       BufferNearendFrame(j, num_bands, nearend, aec->nearend_buffer_size,
    1934           0 :                          aec->nearend_buffer);
    1935             :     }
    1936             : 
    1937             :     // 5) Update system delay with respect to the entire frame.
    1938           0 :     aec->system_delay -= FRAME_LEN;
    1939             : 
    1940             :     // 6) Form the output frame.
    1941           0 :     FormOutputFrame(j, num_bands, &aec->output_buffer_size, aec->output_buffer,
    1942           0 :                     out);
    1943             :   }
    1944           0 : }
    1945             : 
    1946           0 : int WebRtcAec_GetDelayMetricsCore(AecCore* self,
    1947             :                                   int* median,
    1948             :                                   int* std,
    1949             :                                   float* fraction_poor_delays) {
    1950           0 :   RTC_DCHECK(self);
    1951           0 :   RTC_DCHECK(median);
    1952           0 :   RTC_DCHECK(std);
    1953             : 
    1954           0 :   if (self->delay_logging_enabled == 0) {
    1955             :     // Logging disabled.
    1956           0 :     return -1;
    1957             :   }
    1958             : 
    1959           0 :   if (self->delay_metrics_delivered == 0) {
    1960           0 :     UpdateDelayMetrics(self);
    1961           0 :     self->delay_metrics_delivered = 1;
    1962             :   }
    1963           0 :   *median = self->delay_median;
    1964           0 :   *std = self->delay_std;
    1965           0 :   *fraction_poor_delays = self->fraction_poor_delays;
    1966             : 
    1967           0 :   return 0;
    1968             : }
    1969             : 
    1970           0 : int WebRtcAec_echo_state(AecCore* self) {
    1971           0 :   return self->echoState;
    1972             : }
    1973             : 
    1974           0 : void WebRtcAec_GetEchoStats(AecCore* self,
    1975             :                             Stats* erl,
    1976             :                             Stats* erle,
    1977             :                             Stats* a_nlp,
    1978             :                             float* divergent_filter_fraction) {
    1979           0 :   RTC_DCHECK(erl);
    1980           0 :   RTC_DCHECK(erle);
    1981           0 :   RTC_DCHECK(a_nlp);
    1982           0 :   *erl = self->erl;
    1983           0 :   *erle = self->erle;
    1984           0 :   *a_nlp = self->aNlp;
    1985           0 :   *divergent_filter_fraction =
    1986           0 :       self->divergent_filter_fraction.GetLatestFraction();
    1987           0 : }
    1988             : 
    1989           0 : void WebRtcAec_SetConfigCore(AecCore* self,
    1990             :                              int nlp_mode,
    1991             :                              int metrics_mode,
    1992             :                              int delay_logging) {
    1993           0 :   RTC_DCHECK_GE(nlp_mode, 0);
    1994           0 :   RTC_DCHECK_LT(nlp_mode, 3);
    1995           0 :   self->nlp_mode = nlp_mode;
    1996           0 :   self->metricsMode = metrics_mode;
    1997           0 :   if (self->metricsMode) {
    1998           0 :     InitMetrics(self);
    1999             :   }
    2000             :   // Turn on delay logging if it is either set explicitly or if delay agnostic
    2001             :   // AEC is enabled (which requires delay estimates).
    2002           0 :   self->delay_logging_enabled = delay_logging || self->delay_agnostic_enabled;
    2003           0 :   if (self->delay_logging_enabled) {
    2004           0 :     memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
    2005             :   }
    2006           0 : }
    2007             : 
    2008           0 : void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable) {
    2009           0 :   self->delay_agnostic_enabled = enable;
    2010           0 : }
    2011             : 
    2012           0 : int WebRtcAec_delay_agnostic_enabled(AecCore* self) {
    2013           0 :   return self->delay_agnostic_enabled;
    2014             : }
    2015             : 
    2016           0 : void WebRtcAec_enable_refined_adaptive_filter(AecCore* self, bool enable) {
    2017           0 :   self->refined_adaptive_filter_enabled = enable;
    2018           0 :   SetAdaptiveFilterStepSize(self);
    2019           0 :   SetErrorThreshold(self);
    2020           0 : }
    2021             : 
    2022           0 : bool WebRtcAec_refined_adaptive_filter_enabled(const AecCore* self) {
    2023           0 :   return self->refined_adaptive_filter_enabled;
    2024             : }
    2025             : 
    2026           0 : void WebRtcAec_enable_extended_filter(AecCore* self, int enable) {
    2027           0 :   self->extended_filter_enabled = enable;
    2028           0 :   SetAdaptiveFilterStepSize(self);
    2029           0 :   SetErrorThreshold(self);
    2030           0 :   self->num_partitions = enable ? kExtendedNumPartitions : kNormalNumPartitions;
    2031             :   // Update the delay estimator with filter length.  See InitAEC() for details.
    2032           0 :   WebRtc_set_allowed_offset(self->delay_estimator, self->num_partitions / 2);
    2033           0 : }
    2034             : 
    2035           0 : int WebRtcAec_extended_filter_enabled(AecCore* self) {
    2036           0 :   return self->extended_filter_enabled;
    2037             : }
    2038             : 
    2039           0 : int WebRtcAec_system_delay(AecCore* self) {
    2040           0 :   return self->system_delay;
    2041             : }
    2042             : 
    2043           0 : void WebRtcAec_SetSystemDelay(AecCore* self, int delay) {
    2044           0 :   RTC_DCHECK_GE(delay, 0);
    2045           0 :   self->system_delay = delay;
    2046           0 : }
    2047             : }  // namespace webrtc

Generated by: LCOV version 1.13