LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_processing/aec - echo_cancellation.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 352 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 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             :  * Contains the API functions for the AEC.
      13             :  */
      14             : #include "webrtc/modules/audio_processing/aec/echo_cancellation.h"
      15             : 
      16             : #include <math.h>
      17             : #include <stdlib.h>
      18             : #include <string.h>
      19             : 
      20             : extern "C" {
      21             : #include "webrtc/common_audio/ring_buffer.h"
      22             : #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
      23             : }
      24             : #include "webrtc/modules/audio_processing/aec/aec_core.h"
      25             : #include "webrtc/modules/audio_processing/aec/aec_resampler.h"
      26             : #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h"
      27             : #include "webrtc/typedefs.h"
      28             : 
      29             : namespace webrtc {
      30             : 
      31             : Aec::Aec() = default;
      32             : Aec::~Aec() = default;
      33             : 
      34             : // Measured delays [ms]
      35             : // Device                Chrome  GTP
      36             : // MacBook Air           10
      37             : // MacBook Retina        10      100
      38             : // MacPro                30?
      39             : //
      40             : // Win7 Desktop          70      80?
      41             : // Win7 T430s            110
      42             : // Win8 T420s            70
      43             : //
      44             : // Daisy                 50
      45             : // Pixel (w/ preproc?)           240
      46             : // Pixel (w/o preproc?)  110     110
      47             : 
      48             : // The extended filter mode gives us the flexibility to ignore the system's
      49             : // reported delays. We do this for platforms which we believe provide results
      50             : // which are incompatible with the AEC's expectations. Based on measurements
      51             : // (some provided above) we set a conservative (i.e. lower than measured)
      52             : // fixed delay.
      53             : //
      54             : // WEBRTC_UNTRUSTED_DELAY will only have an impact when |extended_filter_mode|
      55             : // is enabled. See the note along with |DelayCorrection| in
      56             : // echo_cancellation_impl.h for more details on the mode.
      57             : //
      58             : // Justification:
      59             : // Chromium/Mac: Here, the true latency is so low (~10-20 ms), that it plays
      60             : // havoc with the AEC's buffering. To avoid this, we set a fixed delay of 20 ms
      61             : // and then compensate by rewinding by 10 ms (in wideband) through
      62             : // kDelayDiffOffsetSamples. This trick does not seem to work for larger rewind
      63             : // values, but fortunately this is sufficient.
      64             : //
      65             : // Chromium/Linux(ChromeOS): The values we get on this platform don't correspond
      66             : // well to reality. The variance doesn't match the AEC's buffer changes, and the
      67             : // bulk values tend to be too low. However, the range across different hardware
      68             : // appears to be too large to choose a single value.
      69             : //
      70             : // GTP/Linux(ChromeOS): TBD, but for the moment we will trust the values.
      71             : #if defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_MAC)
      72             : #define WEBRTC_UNTRUSTED_DELAY
      73             : #endif
      74             : 
      75             : #if defined(WEBRTC_UNTRUSTED_DELAY) && defined(WEBRTC_MAC)
      76             : static const int kDelayDiffOffsetSamples = -160;
      77             : #else
      78             : // Not enabled for now.
      79             : static const int kDelayDiffOffsetSamples = 0;
      80             : #endif
      81             : 
      82             : #if defined(WEBRTC_MAC)
      83             : static const int kFixedDelayMs = 20;
      84             : #else
      85             : static const int kFixedDelayMs = 50;
      86             : #endif
      87             : #if !defined(WEBRTC_UNTRUSTED_DELAY)
      88             : static const int kMinTrustedDelayMs = 20;
      89             : #endif
      90             : static const int kMaxTrustedDelayMs = 500;
      91             : 
      92             : // Maximum length of resampled signal. Must be an integer multiple of frames
      93             : // (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
      94             : // The factor of 2 handles wb, and the + 1 is as a safety margin
      95             : // TODO(bjornv): Replace with kResamplerBufferSize
      96             : #define MAX_RESAMP_LEN (5 * FRAME_LEN)
      97             : 
      98             : static const int kMaxBufSizeStart = 62;  // In partitions
      99             : static const int sampMsNb = 8;           // samples per ms in nb
     100             : static const int initCheck = 42;
     101             : 
     102             : int Aec::instance_count = 0;
     103             : 
     104             : // Estimates delay to set the position of the far-end buffer read pointer
     105             : // (controlled by knownDelay)
     106             : static void EstBufDelayNormal(Aec* aecInst);
     107             : static void EstBufDelayExtended(Aec* aecInst);
     108             : static int ProcessNormal(Aec* self,
     109             :                          const float* const* near,
     110             :                          size_t num_bands,
     111             :                          float* const* out,
     112             :                          size_t num_samples,
     113             :                          int16_t reported_delay_ms,
     114             :                          int32_t skew);
     115             : static void ProcessExtended(Aec* self,
     116             :                             const float* const* near,
     117             :                             size_t num_bands,
     118             :                             float* const* out,
     119             :                             size_t num_samples,
     120             :                             int16_t reported_delay_ms,
     121             :                             int32_t skew);
     122             : 
     123           0 : void* WebRtcAec_Create() {
     124           0 :   Aec* aecpc = new Aec();
     125             : 
     126           0 :   if (!aecpc) {
     127           0 :     return NULL;
     128             :   }
     129           0 :   aecpc->data_dumper.reset(new ApmDataDumper(aecpc->instance_count));
     130             : 
     131           0 :   aecpc->aec = WebRtcAec_CreateAec(aecpc->instance_count);
     132           0 :   if (!aecpc->aec) {
     133           0 :     WebRtcAec_Free(aecpc);
     134           0 :     return NULL;
     135             :   }
     136           0 :   aecpc->resampler = WebRtcAec_CreateResampler();
     137           0 :   if (!aecpc->resampler) {
     138           0 :     WebRtcAec_Free(aecpc);
     139           0 :     return NULL;
     140             :   }
     141             :   // Create far-end pre-buffer. The buffer size has to be large enough for
     142             :   // largest possible drift compensation (kResamplerBufferSize) + "almost" an
     143             :   // FFT buffer (PART_LEN2 - 1).
     144           0 :   aecpc->far_pre_buf =
     145           0 :       WebRtc_CreateBuffer(PART_LEN2 + kResamplerBufferSize, sizeof(float));
     146           0 :   if (!aecpc->far_pre_buf) {
     147           0 :     WebRtcAec_Free(aecpc);
     148           0 :     return NULL;
     149             :   }
     150             : 
     151           0 :   aecpc->initFlag = 0;
     152             : 
     153           0 :   aecpc->instance_count++;
     154           0 :   return aecpc;
     155             : }
     156             : 
     157           0 : void WebRtcAec_Free(void* aecInst) {
     158           0 :   Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
     159             : 
     160           0 :   if (aecpc == NULL) {
     161           0 :     return;
     162             :   }
     163             : 
     164           0 :   WebRtc_FreeBuffer(aecpc->far_pre_buf);
     165             : 
     166           0 :   WebRtcAec_FreeAec(aecpc->aec);
     167           0 :   WebRtcAec_FreeResampler(aecpc->resampler);
     168           0 :   delete aecpc;
     169             : }
     170             : 
     171           0 : int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
     172           0 :   Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
     173           0 :   aecpc->data_dumper->InitiateNewSetOfRecordings();
     174             :   AecConfig aecConfig;
     175             : 
     176           0 :   if (sampFreq != 8000 && sampFreq != 16000 && sampFreq != 32000 &&
     177             :       sampFreq != 48000) {
     178           0 :     return AEC_BAD_PARAMETER_ERROR;
     179             :   }
     180           0 :   aecpc->sampFreq = sampFreq;
     181             : 
     182           0 :   if (scSampFreq < 1 || scSampFreq > 96000) {
     183           0 :     return AEC_BAD_PARAMETER_ERROR;
     184             :   }
     185           0 :   aecpc->scSampFreq = scSampFreq;
     186             : 
     187             :   // Initialize echo canceller core
     188           0 :   if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
     189           0 :     return AEC_UNSPECIFIED_ERROR;
     190             :   }
     191             : 
     192           0 :   if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
     193           0 :     return AEC_UNSPECIFIED_ERROR;
     194             :   }
     195             : 
     196           0 :   WebRtc_InitBuffer(aecpc->far_pre_buf);
     197           0 :   WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);  // Start overlap.
     198             : 
     199           0 :   aecpc->initFlag = initCheck;  // indicates that initialization has been done
     200             : 
     201           0 :   if (aecpc->sampFreq == 32000 || aecpc->sampFreq == 48000) {
     202           0 :     aecpc->splitSampFreq = 16000;
     203             :   } else {
     204           0 :     aecpc->splitSampFreq = sampFreq;
     205             :   }
     206             : 
     207           0 :   aecpc->delayCtr = 0;
     208           0 :   aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq;
     209             :   // Sampling frequency multiplier (SWB is processed as 160 frame size).
     210           0 :   aecpc->rate_factor = aecpc->splitSampFreq / 8000;
     211             : 
     212           0 :   aecpc->sum = 0;
     213           0 :   aecpc->counter = 0;
     214           0 :   aecpc->checkBuffSize = 1;
     215           0 :   aecpc->firstVal = 0;
     216             : 
     217             :   // We skip the startup_phase completely (setting to 0) if DA-AEC is enabled,
     218             :   // but not extended_filter mode.
     219           0 :   aecpc->startup_phase = WebRtcAec_extended_filter_enabled(aecpc->aec) ||
     220           0 :                          !WebRtcAec_delay_agnostic_enabled(aecpc->aec);
     221           0 :   aecpc->bufSizeStart = 0;
     222           0 :   aecpc->checkBufSizeCtr = 0;
     223           0 :   aecpc->msInSndCardBuf = 0;
     224           0 :   aecpc->filtDelay = -1;  // -1 indicates an initialized state.
     225           0 :   aecpc->timeForDelayChange = 0;
     226           0 :   aecpc->knownDelay = 0;
     227           0 :   aecpc->lastDelayDiff = 0;
     228             : 
     229           0 :   aecpc->skewFrCtr = 0;
     230           0 :   aecpc->resample = kAecFalse;
     231           0 :   aecpc->highSkewCtr = 0;
     232           0 :   aecpc->skew = 0;
     233             : 
     234           0 :   aecpc->farend_started = 0;
     235             : 
     236             :   // Default settings.
     237           0 :   aecConfig.nlpMode = kAecNlpModerate;
     238           0 :   aecConfig.skewMode = kAecFalse;
     239           0 :   aecConfig.metricsMode = kAecFalse;
     240           0 :   aecConfig.delay_logging = kAecFalse;
     241             : 
     242           0 :   if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
     243           0 :     return AEC_UNSPECIFIED_ERROR;
     244             :   }
     245             : 
     246           0 :   return 0;
     247             : }
     248             : 
     249             : // Returns any error that is caused when buffering the
     250             : // far-end signal.
     251           0 : int32_t WebRtcAec_GetBufferFarendError(void* aecInst,
     252             :                                        const float* farend,
     253             :                                        size_t nrOfSamples) {
     254           0 :   Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
     255             : 
     256           0 :   if (!farend)
     257           0 :     return AEC_NULL_POINTER_ERROR;
     258             : 
     259           0 :   if (aecpc->initFlag != initCheck)
     260           0 :     return AEC_UNINITIALIZED_ERROR;
     261             : 
     262             :   // number of samples == 160 for SWB input
     263           0 :   if (nrOfSamples != 80 && nrOfSamples != 160)
     264           0 :     return AEC_BAD_PARAMETER_ERROR;
     265             : 
     266           0 :   return 0;
     267             : }
     268             : 
     269             : // only buffer L band for farend
     270           0 : int32_t WebRtcAec_BufferFarend(void* aecInst,
     271             :                                const float* farend,
     272             :                                size_t nrOfSamples) {
     273           0 :   Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
     274           0 :   size_t newNrOfSamples = nrOfSamples;
     275             :   float new_farend[MAX_RESAMP_LEN];
     276           0 :   const float* farend_ptr = farend;
     277             : 
     278             :   // Get any error caused by buffering the farend signal.
     279             :   int32_t error_code =
     280           0 :       WebRtcAec_GetBufferFarendError(aecInst, farend, nrOfSamples);
     281             : 
     282           0 :   if (error_code != 0)
     283           0 :     return error_code;
     284             : 
     285           0 :   if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
     286             :     // Resample and get a new number of samples
     287           0 :     WebRtcAec_ResampleLinear(aecpc->resampler, farend, nrOfSamples, aecpc->skew,
     288           0 :                              new_farend, &newNrOfSamples);
     289           0 :     farend_ptr = new_farend;
     290             :   }
     291             : 
     292           0 :   aecpc->farend_started = 1;
     293           0 :   WebRtcAec_SetSystemDelay(aecpc->aec, WebRtcAec_system_delay(aecpc->aec) +
     294           0 :                            static_cast<int>(newNrOfSamples));
     295             : 
     296             :   // Write the time-domain data to |far_pre_buf|.
     297           0 :   WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, newNrOfSamples);
     298             : 
     299             :   // TODO(minyue): reduce to |PART_LEN| samples for each buffering.
     300           0 :   while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
     301             :     // We have enough data to pass to the FFT, hence read PART_LEN2 samples.
     302             :     {
     303           0 :       float* ptmp = NULL;
     304             :       float tmp[PART_LEN2];
     305           0 :       WebRtc_ReadBuffer(aecpc->far_pre_buf,
     306           0 :                         reinterpret_cast<void**>(&ptmp), tmp, PART_LEN2);
     307           0 :       WebRtcAec_BufferFarendBlock(aecpc->aec, &ptmp[PART_LEN]);
     308             :     }
     309             : 
     310             :     // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
     311           0 :     WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
     312             :   }
     313             : 
     314           0 :   return 0;
     315             : }
     316             : 
     317           0 : int32_t WebRtcAec_Process(void* aecInst,
     318             :                           const float* const* nearend,
     319             :                           size_t num_bands,
     320             :                           float* const* out,
     321             :                           size_t nrOfSamples,
     322             :                           int16_t msInSndCardBuf,
     323             :                           int32_t skew) {
     324           0 :   Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
     325           0 :   int32_t retVal = 0;
     326             : 
     327           0 :   if (out == NULL) {
     328           0 :     return AEC_NULL_POINTER_ERROR;
     329             :   }
     330             : 
     331           0 :   if (aecpc->initFlag != initCheck) {
     332           0 :     return AEC_UNINITIALIZED_ERROR;
     333             :   }
     334             : 
     335             :   // number of samples == 160 for SWB input
     336           0 :   if (nrOfSamples != 80 && nrOfSamples != 160) {
     337           0 :     return AEC_BAD_PARAMETER_ERROR;
     338             :   }
     339             : 
     340           0 :   if (msInSndCardBuf < 0) {
     341           0 :     msInSndCardBuf = 0;
     342           0 :     retVal = AEC_BAD_PARAMETER_WARNING;
     343           0 :   } else if (msInSndCardBuf > kMaxTrustedDelayMs) {
     344             :     // The clamping is now done in ProcessExtended/Normal().
     345           0 :     retVal = AEC_BAD_PARAMETER_WARNING;
     346             :   }
     347             : 
     348             :   // This returns the value of aec->extended_filter_enabled.
     349           0 :   if (WebRtcAec_extended_filter_enabled(aecpc->aec)) {
     350           0 :     ProcessExtended(aecpc, nearend, num_bands, out, nrOfSamples, msInSndCardBuf,
     351           0 :                     skew);
     352             :   } else {
     353           0 :     retVal = ProcessNormal(aecpc, nearend, num_bands, out, nrOfSamples,
     354           0 :                            msInSndCardBuf, skew);
     355             :   }
     356             : 
     357           0 :   int far_buf_size_samples = WebRtcAec_system_delay(aecpc->aec);
     358           0 :   aecpc->data_dumper->DumpRaw("aec_system_delay", 1, &far_buf_size_samples);
     359           0 :   aecpc->data_dumper->DumpRaw("aec_known_delay", 1, &aecpc->knownDelay);
     360             : 
     361           0 :   return retVal;
     362             : }
     363             : 
     364           0 : int WebRtcAec_set_config(void* handle, AecConfig config) {
     365           0 :   Aec* self = reinterpret_cast<Aec*>(handle);
     366           0 :   if (self->initFlag != initCheck) {
     367           0 :     return AEC_UNINITIALIZED_ERROR;
     368             :   }
     369             : 
     370           0 :   if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) {
     371           0 :     return AEC_BAD_PARAMETER_ERROR;
     372             :   }
     373           0 :   self->skewMode = config.skewMode;
     374             : 
     375           0 :   if (config.nlpMode != kAecNlpConservative &&
     376           0 :       config.nlpMode != kAecNlpModerate &&
     377           0 :       config.nlpMode != kAecNlpAggressive) {
     378           0 :     return AEC_BAD_PARAMETER_ERROR;
     379             :   }
     380             : 
     381           0 :   if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) {
     382           0 :     return AEC_BAD_PARAMETER_ERROR;
     383             :   }
     384             : 
     385           0 :   if (config.delay_logging != kAecFalse && config.delay_logging != kAecTrue) {
     386           0 :     return AEC_BAD_PARAMETER_ERROR;
     387             :   }
     388             : 
     389           0 :   WebRtcAec_SetConfigCore(self->aec, config.nlpMode, config.metricsMode,
     390           0 :                           config.delay_logging);
     391           0 :   return 0;
     392             : }
     393             : 
     394           0 : int WebRtcAec_get_echo_status(void* handle, int* status) {
     395           0 :   Aec* self = reinterpret_cast<Aec*>(handle);
     396           0 :   if (status == NULL) {
     397           0 :     return AEC_NULL_POINTER_ERROR;
     398             :   }
     399           0 :   if (self->initFlag != initCheck) {
     400           0 :     return AEC_UNINITIALIZED_ERROR;
     401             :   }
     402             : 
     403           0 :   *status = WebRtcAec_echo_state(self->aec);
     404             : 
     405           0 :   return 0;
     406             : }
     407             : 
     408           0 : int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics) {
     409           0 :   const float kUpWeight = 0.7f;
     410             :   float dtmp;
     411             :   int stmp;
     412           0 :   Aec* self = reinterpret_cast<Aec*>(handle);
     413             :   Stats erl;
     414             :   Stats erle;
     415             :   Stats a_nlp;
     416             : 
     417           0 :   if (handle == NULL) {
     418           0 :     return -1;
     419             :   }
     420           0 :   if (metrics == NULL) {
     421           0 :     return AEC_NULL_POINTER_ERROR;
     422             :   }
     423           0 :   if (self->initFlag != initCheck) {
     424           0 :     return AEC_UNINITIALIZED_ERROR;
     425             :   }
     426             : 
     427           0 :   WebRtcAec_GetEchoStats(self->aec, &erl, &erle, &a_nlp,
     428           0 :                          &metrics->divergent_filter_fraction);
     429             : 
     430             :   // ERL
     431           0 :   metrics->erl.instant = static_cast<int>(erl.instant);
     432             : 
     433           0 :   if ((erl.himean > kOffsetLevel) && (erl.average > kOffsetLevel)) {
     434             :     // Use a mix between regular average and upper part average.
     435           0 :     dtmp = kUpWeight * erl.himean + (1 - kUpWeight) * erl.average;
     436           0 :     metrics->erl.average = static_cast<int>(dtmp);
     437             :   } else {
     438           0 :     metrics->erl.average = kOffsetLevel;
     439             :   }
     440             : 
     441           0 :   metrics->erl.max = static_cast<int>(erl.max);
     442             : 
     443           0 :   if (erl.min < (kOffsetLevel * (-1))) {
     444           0 :     metrics->erl.min = static_cast<int>(erl.min);
     445             :   } else {
     446           0 :     metrics->erl.min = kOffsetLevel;
     447             :   }
     448             : 
     449             :   // ERLE
     450           0 :   metrics->erle.instant = static_cast<int>(erle.instant);
     451             : 
     452           0 :   if ((erle.himean > kOffsetLevel) && (erle.average > kOffsetLevel)) {
     453             :     // Use a mix between regular average and upper part average.
     454           0 :     dtmp = kUpWeight * erle.himean + (1 - kUpWeight) * erle.average;
     455           0 :     metrics->erle.average = static_cast<int>(dtmp);
     456             :   } else {
     457           0 :     metrics->erle.average = kOffsetLevel;
     458             :   }
     459             : 
     460           0 :   metrics->erle.max = static_cast<int>(erle.max);
     461             : 
     462           0 :   if (erle.min < (kOffsetLevel * (-1))) {
     463           0 :     metrics->erle.min = static_cast<int>(erle.min);
     464             :   } else {
     465           0 :     metrics->erle.min = kOffsetLevel;
     466             :   }
     467             : 
     468             :   // RERL
     469           0 :   if ((metrics->erl.average > kOffsetLevel) &&
     470           0 :       (metrics->erle.average > kOffsetLevel)) {
     471           0 :     stmp = metrics->erl.average + metrics->erle.average;
     472             :   } else {
     473           0 :     stmp = kOffsetLevel;
     474             :   }
     475           0 :   metrics->rerl.average = stmp;
     476             : 
     477             :   // No other statistics needed, but returned for completeness.
     478           0 :   metrics->rerl.instant = stmp;
     479           0 :   metrics->rerl.max = stmp;
     480           0 :   metrics->rerl.min = stmp;
     481             : 
     482             :   // A_NLP
     483           0 :   metrics->aNlp.instant = static_cast<int>(a_nlp.instant);
     484             : 
     485           0 :   if ((a_nlp.himean > kOffsetLevel) && (a_nlp.average > kOffsetLevel)) {
     486             :     // Use a mix between regular average and upper part average.
     487           0 :     dtmp = kUpWeight * a_nlp.himean + (1 - kUpWeight) * a_nlp.average;
     488           0 :     metrics->aNlp.average = static_cast<int>(dtmp);
     489             :   } else {
     490           0 :     metrics->aNlp.average = kOffsetLevel;
     491             :   }
     492             : 
     493           0 :   metrics->aNlp.max = static_cast<int>(a_nlp.max);
     494             : 
     495           0 :   if (a_nlp.min < (kOffsetLevel * (-1))) {
     496           0 :     metrics->aNlp.min = static_cast<int>(a_nlp.min);
     497             :   } else {
     498           0 :     metrics->aNlp.min = kOffsetLevel;
     499             :   }
     500             : 
     501           0 :   return 0;
     502             : }
     503             : 
     504           0 : int WebRtcAec_GetDelayMetrics(void* handle,
     505             :                               int* median,
     506             :                               int* std,
     507             :                               float* fraction_poor_delays) {
     508           0 :   Aec* self = reinterpret_cast<Aec*>(handle);
     509           0 :   if (median == NULL) {
     510           0 :     return AEC_NULL_POINTER_ERROR;
     511             :   }
     512           0 :   if (std == NULL) {
     513           0 :     return AEC_NULL_POINTER_ERROR;
     514             :   }
     515           0 :   if (self->initFlag != initCheck) {
     516           0 :     return AEC_UNINITIALIZED_ERROR;
     517             :   }
     518           0 :   if (WebRtcAec_GetDelayMetricsCore(self->aec, median, std,
     519             :                                     fraction_poor_delays) == -1) {
     520             :     // Logging disabled.
     521           0 :     return AEC_UNSUPPORTED_FUNCTION_ERROR;
     522             :   }
     523             : 
     524           0 :   return 0;
     525             : }
     526             : 
     527           0 : AecCore* WebRtcAec_aec_core(void* handle) {
     528           0 :   if (!handle) {
     529           0 :     return NULL;
     530             :   }
     531           0 :   return reinterpret_cast<Aec*>(handle)->aec;
     532             : }
     533             : 
     534           0 : static int ProcessNormal(Aec* aecpc,
     535             :                          const float* const* nearend,
     536             :                          size_t num_bands,
     537             :                          float* const* out,
     538             :                          size_t nrOfSamples,
     539             :                          int16_t msInSndCardBuf,
     540             :                          int32_t skew) {
     541           0 :   int retVal = 0;
     542             :   size_t i;
     543             :   size_t nBlocks10ms;
     544             :   // Limit resampling to doubling/halving of signal
     545           0 :   const float minSkewEst = -0.5f;
     546           0 :   const float maxSkewEst = 1.0f;
     547             : 
     548           0 :   msInSndCardBuf =
     549             :       msInSndCardBuf > kMaxTrustedDelayMs ? kMaxTrustedDelayMs : msInSndCardBuf;
     550             :   // TODO(andrew): we need to investigate if this +10 is really wanted.
     551           0 :   msInSndCardBuf += 10;
     552           0 :   aecpc->msInSndCardBuf = msInSndCardBuf;
     553             : 
     554           0 :   if (aecpc->skewMode == kAecTrue) {
     555           0 :     if (aecpc->skewFrCtr < 25) {
     556           0 :       aecpc->skewFrCtr++;
     557             :     } else {
     558           0 :       retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew);
     559           0 :       if (retVal == -1) {
     560           0 :         aecpc->skew = 0;
     561           0 :         retVal = AEC_BAD_PARAMETER_WARNING;
     562             :       }
     563             : 
     564           0 :       aecpc->skew /= aecpc->sampFactor * nrOfSamples;
     565             : 
     566           0 :       if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) {
     567           0 :         aecpc->resample = kAecFalse;
     568             :       } else {
     569           0 :         aecpc->resample = kAecTrue;
     570             :       }
     571             : 
     572           0 :       if (aecpc->skew < minSkewEst) {
     573           0 :         aecpc->skew = minSkewEst;
     574           0 :       } else if (aecpc->skew > maxSkewEst) {
     575           0 :         aecpc->skew = maxSkewEst;
     576             :       }
     577             : 
     578           0 :       aecpc->data_dumper->DumpRaw("aec_skew", 1, &aecpc->skew);
     579             :     }
     580             :   }
     581             : 
     582           0 :   nBlocks10ms = nrOfSamples / (FRAME_LEN * aecpc->rate_factor);
     583             : 
     584           0 :   if (aecpc->startup_phase) {
     585           0 :     for (i = 0; i < num_bands; ++i) {
     586             :       // Only needed if they don't already point to the same place.
     587           0 :       if (nearend[i] != out[i]) {
     588           0 :         memcpy(out[i], nearend[i], sizeof(nearend[i][0]) * nrOfSamples);
     589             :       }
     590             :     }
     591             : 
     592             :     // The AEC is in the start up mode
     593             :     // AEC is disabled until the system delay is OK
     594             : 
     595             :     // Mechanism to ensure that the system delay is reasonably stable.
     596           0 :     if (aecpc->checkBuffSize) {
     597           0 :       aecpc->checkBufSizeCtr++;
     598             :       // Before we fill up the far-end buffer we require the system delay
     599             :       // to be stable (+/-8 ms) compared to the first value. This
     600             :       // comparison is made during the following 6 consecutive 10 ms
     601             :       // blocks. If it seems to be stable then we start to fill up the
     602             :       // far-end buffer.
     603           0 :       if (aecpc->counter == 0) {
     604           0 :         aecpc->firstVal = aecpc->msInSndCardBuf;
     605           0 :         aecpc->sum = 0;
     606             :       }
     607             : 
     608           0 :       if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) <
     609           0 :           WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) {
     610           0 :         aecpc->sum += aecpc->msInSndCardBuf;
     611           0 :         aecpc->counter++;
     612             :       } else {
     613           0 :         aecpc->counter = 0;
     614             :       }
     615             : 
     616           0 :       if (aecpc->counter * nBlocks10ms >= 6) {
     617             :         // The far-end buffer size is determined in partitions of
     618             :         // PART_LEN samples. Use 75% of the average value of the system
     619             :         // delay as buffer size to start with.
     620           0 :         aecpc->bufSizeStart =
     621           0 :             WEBRTC_SPL_MIN((3 * aecpc->sum * aecpc->rate_factor * 8) /
     622             :                                (4 * aecpc->counter * PART_LEN),
     623             :                            kMaxBufSizeStart);
     624             :         // Buffer size has now been determined.
     625           0 :         aecpc->checkBuffSize = 0;
     626             :       }
     627             : 
     628           0 :       if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) {
     629             :         // For really bad systems, don't disable the echo canceller for
     630             :         // more than 0.5 sec.
     631           0 :         aecpc->bufSizeStart = WEBRTC_SPL_MIN(
     632             :             (aecpc->msInSndCardBuf * aecpc->rate_factor * 3) / 40,
     633             :             kMaxBufSizeStart);
     634           0 :         aecpc->checkBuffSize = 0;
     635             :       }
     636             :     }
     637             : 
     638             :     // If |checkBuffSize| changed in the if-statement above.
     639           0 :     if (!aecpc->checkBuffSize) {
     640             :       // The system delay is now reasonably stable (or has been unstable
     641             :       // for too long). When the far-end buffer is filled with
     642             :       // approximately the same amount of data as reported by the system
     643             :       // we end the startup phase.
     644             :       int overhead_elements =
     645           0 :           WebRtcAec_system_delay(aecpc->aec) / PART_LEN - aecpc->bufSizeStart;
     646           0 :       if (overhead_elements == 0) {
     647             :         // Enable the AEC
     648           0 :         aecpc->startup_phase = 0;
     649           0 :       } else if (overhead_elements > 0) {
     650             :         // TODO(bjornv): Do we need a check on how much we actually
     651             :         // moved the read pointer? It should always be possible to move
     652             :         // the pointer |overhead_elements| since we have only added data
     653             :         // to the buffer and no delay compensation nor AEC processing
     654             :         // has been done.
     655           0 :         WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aecpc->aec,
     656           0 :                                                        overhead_elements);
     657             : 
     658             :         // Enable the AEC
     659           0 :         aecpc->startup_phase = 0;
     660             :       }
     661             :     }
     662             :   } else {
     663             :     // AEC is enabled.
     664           0 :     EstBufDelayNormal(aecpc);
     665             : 
     666             :     // Call the AEC.
     667             :     // TODO(bjornv): Re-structure such that we don't have to pass
     668             :     // |aecpc->knownDelay| as input. Change name to something like
     669             :     // |system_buffer_diff|.
     670           0 :     WebRtcAec_ProcessFrames(aecpc->aec, nearend, num_bands, nrOfSamples,
     671           0 :                             aecpc->knownDelay, out);
     672             :   }
     673             : 
     674           0 :   return retVal;
     675             : }
     676             : 
     677           0 : static void ProcessExtended(Aec* self,
     678             :                             const float* const* near,
     679             :                             size_t num_bands,
     680             :                             float* const* out,
     681             :                             size_t num_samples,
     682             :                             int16_t reported_delay_ms,
     683             :                             int32_t skew) {
     684             :   size_t i;
     685           0 :   const int delay_diff_offset = kDelayDiffOffsetSamples;
     686           0 :   RTC_DCHECK(num_samples == 80 || num_samples == 160);
     687             : #if defined(WEBRTC_UNTRUSTED_DELAY)
     688             :   reported_delay_ms = kFixedDelayMs;
     689             : #else
     690             :   // This is the usual mode where we trust the reported system delay values.
     691             :   // Due to the longer filter, we no longer add 10 ms to the reported delay
     692             :   // to reduce chance of non-causality. Instead we apply a minimum here to avoid
     693             :   // issues with the read pointer jumping around needlessly.
     694           0 :   reported_delay_ms = reported_delay_ms < kMinTrustedDelayMs
     695             :                           ? kMinTrustedDelayMs
     696             :                           : reported_delay_ms;
     697             :   // If the reported delay appears to be bogus, we attempt to recover by using
     698             :   // the measured fixed delay values. We use >= here because higher layers
     699             :   // may already clamp to this maximum value, and we would otherwise not
     700             :   // detect it here.
     701           0 :   reported_delay_ms = reported_delay_ms >= kMaxTrustedDelayMs
     702             :                           ? kFixedDelayMs
     703           0 :                           : reported_delay_ms;
     704             : #endif
     705           0 :   self->msInSndCardBuf = reported_delay_ms;
     706             : 
     707           0 :   if (!self->farend_started) {
     708           0 :     for (i = 0; i < num_bands; ++i) {
     709             :       // Only needed if they don't already point to the same place.
     710           0 :       if (near[i] != out[i]) {
     711           0 :         memcpy(out[i], near[i], sizeof(near[i][0]) * num_samples);
     712             :       }
     713             :     }
     714           0 :     return;
     715             :   }
     716           0 :   if (self->startup_phase) {
     717             :     // In the extended mode, there isn't a startup "phase", just a special
     718             :     // action on the first frame. In the trusted delay case, we'll take the
     719             :     // current reported delay, unless it's less then our conservative
     720             :     // measurement.
     721             :     int startup_size_ms =
     722           0 :         reported_delay_ms < kFixedDelayMs ? kFixedDelayMs : reported_delay_ms;
     723             : #if defined(WEBRTC_ANDROID)
     724             :     int target_delay = startup_size_ms * self->rate_factor * 8;
     725             : #else
     726             :     // To avoid putting the AEC in a non-causal state we're being slightly
     727             :     // conservative and scale by 2. On Android we use a fixed delay and
     728             :     // therefore there is no need to scale the target_delay.
     729           0 :     int target_delay = startup_size_ms * self->rate_factor * 8 / 2;
     730             : #endif
     731             :     int overhead_elements =
     732           0 :         (WebRtcAec_system_delay(self->aec) - target_delay) / PART_LEN;
     733           0 :     WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(self->aec,
     734           0 :                                                    overhead_elements);
     735           0 :     self->startup_phase = 0;
     736             :   }
     737             : 
     738           0 :   EstBufDelayExtended(self);
     739             : 
     740             :   {
     741             :     // |delay_diff_offset| gives us the option to manually rewind the delay on
     742             :     // very low delay platforms which can't be expressed purely through
     743             :     // |reported_delay_ms|.
     744             :     const int adjusted_known_delay =
     745           0 :         WEBRTC_SPL_MAX(0, self->knownDelay + delay_diff_offset);
     746             : 
     747           0 :     WebRtcAec_ProcessFrames(self->aec, near, num_bands, num_samples,
     748           0 :                             adjusted_known_delay, out);
     749             :   }
     750             : }
     751             : 
     752           0 : static void EstBufDelayNormal(Aec* aecpc) {
     753           0 :   int nSampSndCard = aecpc->msInSndCardBuf * sampMsNb * aecpc->rate_factor;
     754           0 :   int current_delay = nSampSndCard - WebRtcAec_system_delay(aecpc->aec);
     755           0 :   int delay_difference = 0;
     756             : 
     757             :   // Before we proceed with the delay estimate filtering we:
     758             :   // 1) Compensate for the frame that will be read.
     759             :   // 2) Compensate for drift resampling.
     760             :   // 3) Compensate for non-causality if needed, since the estimated delay can't
     761             :   //    be negative.
     762             : 
     763             :   // 1) Compensating for the frame(s) that will be read/processed.
     764           0 :   current_delay += FRAME_LEN * aecpc->rate_factor;
     765             : 
     766             :   // 2) Account for resampling frame delay.
     767           0 :   if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
     768           0 :     current_delay -= kResamplingDelay;
     769             :   }
     770             : 
     771             :   // 3) Compensate for non-causality, if needed, by flushing one block.
     772           0 :   if (current_delay < PART_LEN) {
     773           0 :     current_delay +=
     774           0 :         WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aecpc->aec, 1) *
     775             :         PART_LEN;
     776             :   }
     777             : 
     778             :   // We use -1 to signal an initialized state in the "extended" implementation;
     779             :   // compensate for that.
     780           0 :   aecpc->filtDelay = aecpc->filtDelay < 0 ? 0 : aecpc->filtDelay;
     781           0 :   aecpc->filtDelay =
     782           0 :       WEBRTC_SPL_MAX(0, static_cast<int16_t>(0.8 *
     783             :                                              aecpc->filtDelay +
     784             :                                              0.2 * current_delay));
     785             : 
     786           0 :   delay_difference = aecpc->filtDelay - aecpc->knownDelay;
     787           0 :   if (delay_difference > 224) {
     788           0 :     if (aecpc->lastDelayDiff < 96) {
     789           0 :       aecpc->timeForDelayChange = 0;
     790             :     } else {
     791           0 :       aecpc->timeForDelayChange++;
     792             :     }
     793           0 :   } else if (delay_difference < 96 && aecpc->knownDelay > 0) {
     794           0 :     if (aecpc->lastDelayDiff > 224) {
     795           0 :       aecpc->timeForDelayChange = 0;
     796             :     } else {
     797           0 :       aecpc->timeForDelayChange++;
     798             :     }
     799             :   } else {
     800           0 :     aecpc->timeForDelayChange = 0;
     801             :   }
     802           0 :   aecpc->lastDelayDiff = delay_difference;
     803             : 
     804           0 :   if (aecpc->timeForDelayChange > 25) {
     805           0 :     aecpc->knownDelay = WEBRTC_SPL_MAX((int)aecpc->filtDelay - 160, 0);
     806             :   }
     807           0 : }
     808             : 
     809           0 : static void EstBufDelayExtended(Aec* self) {
     810           0 :   int reported_delay = self->msInSndCardBuf * sampMsNb * self->rate_factor;
     811           0 :   int current_delay = reported_delay - WebRtcAec_system_delay(self->aec);
     812           0 :   int delay_difference = 0;
     813             : 
     814             :   // Before we proceed with the delay estimate filtering we:
     815             :   // 1) Compensate for the frame that will be read.
     816             :   // 2) Compensate for drift resampling.
     817             :   // 3) Compensate for non-causality if needed, since the estimated delay can't
     818             :   //    be negative.
     819             : 
     820             :   // 1) Compensating for the frame(s) that will be read/processed.
     821           0 :   current_delay += FRAME_LEN * self->rate_factor;
     822             : 
     823             :   // 2) Account for resampling frame delay.
     824           0 :   if (self->skewMode == kAecTrue && self->resample == kAecTrue) {
     825           0 :     current_delay -= kResamplingDelay;
     826             :   }
     827             : 
     828             :   // 3) Compensate for non-causality, if needed, by flushing two blocks.
     829           0 :   if (current_delay < PART_LEN) {
     830           0 :     current_delay +=
     831           0 :         WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(self->aec, 2) * PART_LEN;
     832             :   }
     833             : 
     834           0 :   if (self->filtDelay == -1) {
     835           0 :     self->filtDelay = WEBRTC_SPL_MAX(0, 0.5 * current_delay);
     836             :   } else {
     837           0 :     self->filtDelay = WEBRTC_SPL_MAX(
     838             :         0, static_cast<int16_t>(0.95 * self->filtDelay + 0.05 * current_delay));
     839             :   }
     840             : 
     841           0 :   delay_difference = self->filtDelay - self->knownDelay;
     842           0 :   if (delay_difference > 384) {
     843           0 :     if (self->lastDelayDiff < 128) {
     844           0 :       self->timeForDelayChange = 0;
     845             :     } else {
     846           0 :       self->timeForDelayChange++;
     847             :     }
     848           0 :   } else if (delay_difference < 128 && self->knownDelay > 0) {
     849           0 :     if (self->lastDelayDiff > 384) {
     850           0 :       self->timeForDelayChange = 0;
     851             :     } else {
     852           0 :       self->timeForDelayChange++;
     853             :     }
     854             :   } else {
     855           0 :     self->timeForDelayChange = 0;
     856             :   }
     857           0 :   self->lastDelayDiff = delay_difference;
     858             : 
     859           0 :   if (self->timeForDelayChange > 25) {
     860           0 :     self->knownDelay = WEBRTC_SPL_MAX((int)self->filtDelay - 256, 0);
     861             :   }
     862           0 : }
     863             : }  // namespace webrtc

Generated by: LCOV version 1.13