Remove deprecated legacy AEC code
This CL removes the deprecated legacy AEC code.
Note that this CL should not be landed before the M80 release has been cut.
Bug: webrtc:11165
Change-Id: I59ee94526e62f702bb9fa9fa2d38c4e48f44753c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/161238
Commit-Queue: Per Åhgren <peah@webrtc.org>
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30036}
diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn
index a0f6124..f347b04 100644
--- a/modules/audio_processing/BUILD.gn
+++ b/modules/audio_processing/BUILD.gn
@@ -11,13 +11,6 @@
import("//third_party/protobuf/proto_library.gni")
}
-declare_args() {
- # Disables the usual mode where we trust the reported system delay
- # values the AEC receives. The corresponding define is set appropriately
- # in the code, but it can be force-enabled here for testing.
- aec_untrusted_delay_for_testing = false
-}
-
config("apm_debug_dump") {
if (apm_debug_dump) {
defines = [ "WEBRTC_APM_DEBUG_DUMP=1" ]
@@ -112,8 +105,6 @@
"audio_processing_impl.cc",
"audio_processing_impl.h",
"common.h",
- "echo_cancellation_impl.cc",
- "echo_cancellation_impl.h",
"echo_control_mobile_impl.cc",
"echo_control_mobile_impl.h",
"echo_detector/circular_buffer.cc",
@@ -187,8 +178,6 @@
"../../system_wrappers:cpu_features_api",
"../../system_wrappers:field_trial",
"../../system_wrappers:metrics",
- "aec",
- "aec:aec_core",
"aec3",
"aecm:aecm_core",
"agc",
@@ -202,10 +191,6 @@
"//third_party/abseil-cpp/absl/types:optional",
]
- if (aec_untrusted_delay_for_testing) {
- defines += [ "WEBRTC_UNTRUSTED_DELAY" ]
- }
-
if (rtc_prefer_fixed_point) {
defines += [ "WEBRTC_NS_FIXED" ]
} else {
@@ -400,7 +385,6 @@
"audio_buffer_unittest.cc",
"audio_frame_view_unittest.cc",
"config_unittest.cc",
- "echo_cancellation_impl_unittest.cc",
"echo_control_mobile_unittest.cc",
"gain_controller2_unittest.cc",
"splitting_filter_unittest.cc",
@@ -451,8 +435,6 @@
"../../test:rtc_expect_death",
"../../test:test_support",
"../audio_coding:neteq_input_audio_tools",
- "aec:aec_core",
- "aec:aec_unittests",
"aec_dump:mock_aec_dump_unittests",
"agc:agc_unittests",
"agc2:adaptive_digital_unittests",
@@ -463,7 +445,6 @@
"agc2:test_utils",
"agc2/rnn_vad:unittests",
"test/conversational_speech:unittest",
- "utility:block_mean_calculator_unittest",
"utility:legacy_delay_estimator_unittest",
"utility:pffft_wrapper_unittest",
"vad:vad_unittests",
@@ -499,7 +480,6 @@
"audio_processing_impl_locking_unittest.cc",
"audio_processing_impl_unittest.cc",
"audio_processing_unittest.cc",
- "echo_cancellation_bit_exact_unittest.cc",
"echo_control_mobile_bit_exact_unittest.cc",
"echo_detector/circular_buffer_unittest.cc",
"echo_detector/mean_variance_estimator_unittest.cc",
diff --git a/modules/audio_processing/aec/BUILD.gn b/modules/audio_processing/aec/BUILD.gn
deleted file mode 100644
index 472ed17..0000000
--- a/modules/audio_processing/aec/BUILD.gn
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
-#
-# Use of this source code is governed by a BSD-style license
-# that can be found in the LICENSE file in the root of the source
-# tree. An additional intellectual property rights grant can be found
-# in the file PATENTS. All contributing project authors may
-# be found in the AUTHORS file in the root of the source tree.
-
-import("../../../webrtc.gni")
-
-rtc_library("aec") {
- configs += [ "..:apm_debug_dump" ]
- sources = [
- "aec_resampler.cc",
- "aec_resampler.h",
- "echo_cancellation.cc",
- "echo_cancellation.h",
- ]
- deps = [
- ":aec_core",
- "..:apm_logging",
- "../../../common_audio:common_audio_c",
- "../../../rtc_base:checks",
- "../../../rtc_base:rtc_base_approved",
- ]
-}
-
-rtc_library("aec_core") {
- configs += [ "..:apm_debug_dump" ]
- sources = [
- "aec_common.h",
- "aec_core.cc",
- "aec_core.h",
- "aec_core_optimized_methods.h",
- ]
- deps = [
- "..:apm_logging",
- "../../../common_audio:common_audio_c",
- "../../../rtc_base:checks",
- "../../../rtc_base:rtc_base_approved",
- "../../../rtc_base/system:arch",
- "../../../system_wrappers:cpu_features_api",
- "../../../system_wrappers:metrics",
- "../utility:block_mean_calculator",
- "../utility:legacy_delay_estimator",
- "../utility:ooura_fft",
- ]
- cflags = []
-
- if (current_cpu == "x86" || current_cpu == "x64") {
- sources += [ "aec_core_sse2.cc" ]
- if (is_posix || is_fuchsia) {
- cflags += [ "-msse2" ]
- }
- }
-
- if (rtc_build_with_neon) {
- sources += [ "aec_core_neon.cc" ]
-
- if (current_cpu != "arm64") {
- # Enable compilation for the NEON instruction set.
- suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
- cflags += [ "-mfpu=neon" ]
- }
-
- deps += [ "../../../common_audio" ]
- }
-
- if (current_cpu == "mipsel" && mips_float_abi == "hard") {
- sources += [ "aec_core_mips.cc" ]
- }
-}
-
-if (rtc_include_tests) {
- rtc_library("aec_unittests") {
- testonly = true
-
- sources = [
- "echo_cancellation_unittest.cc",
- "system_delay_unittest.cc",
- ]
- deps = [
- ":aec",
- ":aec_core",
- "../../../rtc_base:checks",
- "../../../rtc_base:rtc_base_approved",
- "../../../test:test_support",
- "//testing/gtest",
- ]
- }
-}
diff --git a/modules/audio_processing/aec/aec_common.h b/modules/audio_processing/aec/aec_common.h
deleted file mode 100644
index ac1f339..0000000
--- a/modules/audio_processing/aec/aec_common.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_AEC_AEC_COMMON_H_
-#define MODULES_AUDIO_PROCESSING_AEC_AEC_COMMON_H_
-
-#ifdef _MSC_VER /* visual c++ */
-#define ALIGN16_BEG __declspec(align(16))
-#define ALIGN16_END
-#else /* gcc or icc */
-#define ALIGN16_BEG
-#define ALIGN16_END __attribute__((aligned(16)))
-#endif
-
-#ifdef __cplusplus
-namespace webrtc {
-#endif
-
-extern ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65];
-extern ALIGN16_BEG const float ALIGN16_END WebRtcAec_weightCurve[65];
-extern ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65];
-extern const float WebRtcAec_kExtendedSmoothingCoefficients[2][2];
-extern const float WebRtcAec_kNormalSmoothingCoefficients[2][2];
-extern const float WebRtcAec_kMinFarendPSD;
-
-#ifdef __cplusplus
-} // namespace webrtc
-#endif
-
-#endif // MODULES_AUDIO_PROCESSING_AEC_AEC_COMMON_H_
diff --git a/modules/audio_processing/aec/aec_core.cc b/modules/audio_processing/aec/aec_core.cc
deleted file mode 100644
index d8ba926..0000000
--- a/modules/audio_processing/aec/aec_core.cc
+++ /dev/null
@@ -1,2012 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * The core AEC algorithm, which is presented with time-aligned signals.
- */
-
-#include "modules/audio_processing/aec/aec_core.h"
-
-#include <math.h>
-#include <stddef.h> // size_t
-#include <stdlib.h>
-#include <string.h>
-
-#include <algorithm>
-#include <cmath>
-
-#include "rtc_base/checks.h"
-
-extern "C" {
-#include "common_audio/ring_buffer.h"
-}
-#include "common_audio/signal_processing/include/signal_processing_library.h"
-#include "modules/audio_processing/aec/aec_common.h"
-#include "modules/audio_processing/aec/aec_core_optimized_methods.h"
-#include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "modules/audio_processing/utility/delay_estimator_wrapper.h"
-#include "rtc_base/system/arch.h"
-#include "system_wrappers/include/cpu_features_wrapper.h"
-#include "system_wrappers/include/metrics.h"
-
-namespace webrtc {
-// Buffer size (samples)
-static const size_t kBufferSizeBlocks = 250; // 1 second of audio in 16 kHz.
-
-// Metrics
-static const size_t kSubCountLen = 4;
-static const size_t kCountLen = 50;
-static const int kDelayMetricsAggregationWindow = 1250; // 5 seconds at 16 kHz.
-
-// Divergence metric is based on audio level, which gets updated every
-// |kSubCountLen + 1| * PART_LEN samples. Divergence metric takes the statistics
-// of |kDivergentFilterFractionAggregationWindowSize| audio levels. The
-// following value corresponds to 1 second at 16 kHz.
-static const int kDivergentFilterFractionAggregationWindowSize = 50;
-
-// Quantities to control H band scaling for SWB input
-static const float cnScaleHband = 0.4f; // scale for comfort noise in H band.
-// Initial bin for averaging nlp gain in low band
-static const int freqAvgIc = PART_LEN / 2;
-
-// Matlab code to produce table:
-// win = sqrt(hanning(63)); win = [0 ; win(1:32)];
-// fprintf(1, '\t%.14f, %.14f, %.14f,\n', win);
-ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65] = {
- 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
- 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
- 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
- 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
- 0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
- 0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
- 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
- 0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
- 0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
- 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
- 0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
- 0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
- 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
- 0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
- 0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
- 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
- 1.00000000000000f};
-
-// Matlab code to produce table:
-// weightCurve = [0 ; 0.3 * sqrt(linspace(0,1,64))' + 0.1];
-// fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', weightCurve);
-ALIGN16_BEG const float ALIGN16_END WebRtcAec_weightCurve[65] = {
- 0.0000f, 0.1000f, 0.1378f, 0.1535f, 0.1655f, 0.1756f, 0.1845f, 0.1926f,
- 0.2000f, 0.2069f, 0.2134f, 0.2195f, 0.2254f, 0.2309f, 0.2363f, 0.2414f,
- 0.2464f, 0.2512f, 0.2558f, 0.2604f, 0.2648f, 0.2690f, 0.2732f, 0.2773f,
- 0.2813f, 0.2852f, 0.2890f, 0.2927f, 0.2964f, 0.3000f, 0.3035f, 0.3070f,
- 0.3104f, 0.3138f, 0.3171f, 0.3204f, 0.3236f, 0.3268f, 0.3299f, 0.3330f,
- 0.3360f, 0.3390f, 0.3420f, 0.3449f, 0.3478f, 0.3507f, 0.3535f, 0.3563f,
- 0.3591f, 0.3619f, 0.3646f, 0.3673f, 0.3699f, 0.3726f, 0.3752f, 0.3777f,
- 0.3803f, 0.3828f, 0.3854f, 0.3878f, 0.3903f, 0.3928f, 0.3952f, 0.3976f,
- 0.4000f};
-
-// Matlab code to produce table:
-// overDriveCurve = [sqrt(linspace(0,1,65))' + 1];
-// fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', overDriveCurve);
-ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65] = {
- 1.0000f, 1.1250f, 1.1768f, 1.2165f, 1.2500f, 1.2795f, 1.3062f, 1.3307f,
- 1.3536f, 1.3750f, 1.3953f, 1.4146f, 1.4330f, 1.4507f, 1.4677f, 1.4841f,
- 1.5000f, 1.5154f, 1.5303f, 1.5449f, 1.5590f, 1.5728f, 1.5863f, 1.5995f,
- 1.6124f, 1.6250f, 1.6374f, 1.6495f, 1.6614f, 1.6731f, 1.6847f, 1.6960f,
- 1.7071f, 1.7181f, 1.7289f, 1.7395f, 1.7500f, 1.7603f, 1.7706f, 1.7806f,
- 1.7906f, 1.8004f, 1.8101f, 1.8197f, 1.8292f, 1.8385f, 1.8478f, 1.8570f,
- 1.8660f, 1.8750f, 1.8839f, 1.8927f, 1.9014f, 1.9100f, 1.9186f, 1.9270f,
- 1.9354f, 1.9437f, 1.9520f, 1.9601f, 1.9682f, 1.9763f, 1.9843f, 1.9922f,
- 2.0000f};
-
-// Delay Agnostic AEC parameters, still under development and may change.
-static const float kDelayQualityThresholdMax = 0.07f;
-static const float kDelayQualityThresholdMin = 0.01f;
-static const int kInitialShiftOffset = 5;
-#if !defined(WEBRTC_ANDROID)
-static const int kDelayCorrectionStart = 1500; // 10 ms chunks
-#endif
-
-// Target suppression levels for nlp modes.
-// log{0.001, 0.00001, 0.00000001}
-static const float kTargetSupp[3] = {-6.9f, -11.5f, -18.4f};
-
-// Two sets of parameters, one for the extended filter mode.
-static const float kExtendedMinOverDrive[3] = {3.0f, 6.0f, 15.0f};
-static const float kNormalMinOverDrive[3] = {1.0f, 2.0f, 5.0f};
-const float WebRtcAec_kExtendedSmoothingCoefficients[2][2] = {{0.9f, 0.1f},
- {0.92f, 0.08f}};
-const float WebRtcAec_kNormalSmoothingCoefficients[2][2] = {{0.9f, 0.1f},
- {0.93f, 0.07f}};
-
-// Number of partitions forming the NLP's "preferred" bands.
-enum { kPrefBandSize = 24 };
-
-WebRtcAecFilterFar WebRtcAec_FilterFar;
-WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal;
-WebRtcAecFilterAdaptation WebRtcAec_FilterAdaptation;
-WebRtcAecOverdrive WebRtcAec_Overdrive;
-WebRtcAecSuppress WebRtcAec_Suppress;
-WebRtcAecComputeCoherence WebRtcAec_ComputeCoherence;
-WebRtcAecUpdateCoherenceSpectra WebRtcAec_UpdateCoherenceSpectra;
-WebRtcAecStoreAsComplex WebRtcAec_StoreAsComplex;
-WebRtcAecPartitionDelay WebRtcAec_PartitionDelay;
-WebRtcAecWindowData WebRtcAec_WindowData;
-
-__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bRe - aIm * bIm;
-}
-
-__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bIm + aIm * bRe;
-}
-
-// TODO(minyue): Due to a legacy bug, |framelevel| and |averagelevel| use a
-// window, of which the length is 1 unit longer than indicated. Remove "+1" when
-// the code is refactored.
-PowerLevel::PowerLevel()
- : framelevel(kSubCountLen + 1), averagelevel(kCountLen + 1) {}
-
-Aec2BlockBuffer::Aec2BlockBuffer() {
- buffer_ = WebRtc_CreateBuffer(kBufferSizeBlocks, sizeof(float) * PART_LEN);
- RTC_CHECK(buffer_);
- ReInit();
-}
-
-Aec2BlockBuffer::~Aec2BlockBuffer() {
- WebRtc_FreeBuffer(buffer_);
-}
-
-void Aec2BlockBuffer::ReInit() {
- WebRtc_InitBuffer(buffer_);
-}
-
-void Aec2BlockBuffer::Insert(const float block[PART_LEN]) {
- WebRtc_WriteBuffer(buffer_, block, 1);
-}
-
-void Aec2BlockBuffer::ExtractExtendedBlock(float extended_block[PART_LEN2]) {
- float* block_ptr = NULL;
- RTC_DCHECK_LT(0, AvaliableSpace());
-
- // Extract the previous block.
- WebRtc_MoveReadPtr(buffer_, -1);
- size_t read_elements = WebRtc_ReadBuffer(
- buffer_, reinterpret_cast<void**>(&block_ptr), &extended_block[0], 1);
- if (read_elements == 0u) {
- std::fill_n(&extended_block[0], PART_LEN, 0.0f);
- } else if (block_ptr != &extended_block[0]) {
- memcpy(&extended_block[0], block_ptr, PART_LEN * sizeof(float));
- }
-
- // Extract the current block.
- read_elements =
- WebRtc_ReadBuffer(buffer_, reinterpret_cast<void**>(&block_ptr),
- &extended_block[PART_LEN], 1);
- if (read_elements == 0u) {
- std::fill_n(&extended_block[PART_LEN], PART_LEN, 0.0f);
- } else if (block_ptr != &extended_block[PART_LEN]) {
- memcpy(&extended_block[PART_LEN], block_ptr, PART_LEN * sizeof(float));
- }
-}
-
-int Aec2BlockBuffer::AdjustSize(int buffer_size_decrease) {
- return WebRtc_MoveReadPtr(buffer_, buffer_size_decrease);
-}
-
-size_t Aec2BlockBuffer::Size() {
- return static_cast<int>(WebRtc_available_read(buffer_));
-}
-
-size_t Aec2BlockBuffer::AvaliableSpace() {
- return WebRtc_available_write(buffer_);
-}
-
-DivergentFilterFraction::DivergentFilterFraction()
- : count_(0), occurrence_(0), fraction_(-1.0) {}
-
-void DivergentFilterFraction::Reset() {
- Clear();
- fraction_ = -1.0;
-}
-
-void DivergentFilterFraction::AddObservation(const PowerLevel& nearlevel,
- const PowerLevel& linoutlevel,
- const PowerLevel& nlpoutlevel) {
- const float near_level = nearlevel.framelevel.GetLatestMean();
- const float level_increase =
- linoutlevel.framelevel.GetLatestMean() - near_level;
- const bool output_signal_active =
- nlpoutlevel.framelevel.GetLatestMean() > 40.0 * nlpoutlevel.minlevel;
- // Level increase should be, in principle, negative, when the filter
- // does not diverge. Here we allow some margin (0.01 * near end level) and
- // numerical error (1.0). We count divergence only when the AEC output
- // signal is active.
- if (output_signal_active && level_increase > std::max(0.01 * near_level, 1.0))
- occurrence_++;
- ++count_;
- if (count_ == kDivergentFilterFractionAggregationWindowSize) {
- fraction_ = static_cast<float>(occurrence_) /
- kDivergentFilterFractionAggregationWindowSize;
- Clear();
- }
-}
-
-float DivergentFilterFraction::GetLatestFraction() const {
- return fraction_;
-}
-
-void DivergentFilterFraction::Clear() {
- count_ = 0;
- occurrence_ = 0;
-}
-
-// TODO(minyue): Moving some initialization from WebRtcAec_CreateAec() to ctor.
-AecCore::AecCore(int instance_index)
- : data_dumper(new ApmDataDumper(instance_index)) {}
-
-AecCore::~AecCore() {}
-
-static int CmpFloat(const void* a, const void* b) {
- const float* da = (const float*)a;
- const float* db = (const float*)b;
-
- return (*da > *db) - (*da < *db);
-}
-
-static void FilterFar(int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float y_fft[2][PART_LEN1]) {
- int i;
- for (i = 0; i < num_partitions; i++) {
- int j;
- int xPos = (i + x_fft_buf_block_pos) * PART_LEN1;
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + x_fft_buf_block_pos >= num_partitions) {
- xPos -= num_partitions * (PART_LEN1);
- }
-
- for (j = 0; j < PART_LEN1; j++) {
- y_fft[0][j] += MulRe(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
- h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
- y_fft[1][j] += MulIm(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
- h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
- }
- }
-}
-
-static void ScaleErrorSignal(float mu,
- float error_threshold,
- float x_pow[PART_LEN1],
- float ef[2][PART_LEN1]) {
- int i;
- float abs_ef;
- for (i = 0; i < (PART_LEN1); i++) {
- ef[0][i] /= (x_pow[i] + 1e-10f);
- ef[1][i] /= (x_pow[i] + 1e-10f);
- abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
-
- if (abs_ef > error_threshold) {
- abs_ef = error_threshold / (abs_ef + 1e-10f);
- ef[0][i] *= abs_ef;
- ef[1][i] *= abs_ef;
- }
-
- // Stepsize factor
- ef[0][i] *= mu;
- ef[1][i] *= mu;
- }
-}
-
-static void FilterAdaptation(
- const OouraFft& ooura_fft,
- int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float e_fft[2][PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
- int i, j;
- float fft[PART_LEN2];
- for (i = 0; i < num_partitions; i++) {
- int xPos = (i + x_fft_buf_block_pos) * (PART_LEN1);
- int pos;
- // Check for wrap
- if (i + x_fft_buf_block_pos >= num_partitions) {
- xPos -= num_partitions * PART_LEN1;
- }
-
- pos = i * PART_LEN1;
-
- for (j = 0; j < PART_LEN; j++) {
- fft[2 * j] = MulRe(x_fft_buf[0][xPos + j], -x_fft_buf[1][xPos + j],
- e_fft[0][j], e_fft[1][j]);
- fft[2 * j + 1] = MulIm(x_fft_buf[0][xPos + j], -x_fft_buf[1][xPos + j],
- e_fft[0][j], e_fft[1][j]);
- }
- fft[1] =
- MulRe(x_fft_buf[0][xPos + PART_LEN], -x_fft_buf[1][xPos + PART_LEN],
- e_fft[0][PART_LEN], e_fft[1][PART_LEN]);
-
- ooura_fft.InverseFft(fft);
- memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
-
- // fft scaling
- {
- float scale = 2.0f / PART_LEN2;
- for (j = 0; j < PART_LEN; j++) {
- fft[j] *= scale;
- }
- }
- ooura_fft.Fft(fft);
-
- h_fft_buf[0][pos] += fft[0];
- h_fft_buf[0][pos + PART_LEN] += fft[1];
-
- for (j = 1; j < PART_LEN; j++) {
- h_fft_buf[0][pos + j] += fft[2 * j];
- h_fft_buf[1][pos + j] += fft[2 * j + 1];
- }
- }
-}
-
-static void Overdrive(float overdrive_scaling,
- const float hNlFb,
- float hNl[PART_LEN1]) {
- for (int i = 0; i < PART_LEN1; ++i) {
- // Weight subbands
- if (hNl[i] > hNlFb) {
- hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
- (1 - WebRtcAec_weightCurve[i]) * hNl[i];
- }
- hNl[i] = powf(hNl[i], overdrive_scaling * WebRtcAec_overDriveCurve[i]);
- }
-}
-
-static void Suppress(const float hNl[PART_LEN1], float efw[2][PART_LEN1]) {
- for (int i = 0; i < PART_LEN1; ++i) {
- // Suppress error signal
- efw[0][i] *= hNl[i];
- efw[1][i] *= hNl[i];
-
- // Ooura fft returns incorrect sign on imaginary component. It matters here
- // because we are making an additive change with comfort noise.
- efw[1][i] *= -1;
- }
-}
-
-static int PartitionDelay(
- int num_partitions,
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
- // Measures the energy in each filter partition and returns the partition with
- // highest energy.
- // TODO(bjornv): Spread computational cost by computing one partition per
- // block?
- float wfEnMax = 0;
- int i;
- int delay = 0;
-
- for (i = 0; i < num_partitions; i++) {
- int j;
- int pos = i * PART_LEN1;
- float wfEn = 0;
- for (j = 0; j < PART_LEN1; j++) {
- wfEn += h_fft_buf[0][pos + j] * h_fft_buf[0][pos + j] +
- h_fft_buf[1][pos + j] * h_fft_buf[1][pos + j];
- }
-
- if (wfEn > wfEnMax) {
- wfEnMax = wfEn;
- delay = i;
- }
- }
- return delay;
-}
-
-// Update metric with 10 * log10(numerator / denominator).
-static void UpdateLogRatioMetric(Stats* metric,
- float numerator,
- float denominator) {
- RTC_DCHECK(metric);
- RTC_CHECK(numerator >= 0);
- RTC_CHECK(denominator >= 0);
-
- const float log_numerator = std::log10(numerator + 1e-10f);
- const float log_denominator = std::log10(denominator + 1e-10f);
- metric->instant = 10.0f * (log_numerator - log_denominator);
-
- // Max.
- if (metric->instant > metric->max)
- metric->max = metric->instant;
-
- // Min.
- if (metric->instant < metric->min)
- metric->min = metric->instant;
-
- // Average.
- metric->counter++;
- // This is to protect overflow, which should almost never happen.
- RTC_CHECK_NE(0, metric->counter);
- metric->sum += metric->instant;
- metric->average = metric->sum / metric->counter;
-
- // Upper mean.
- if (metric->instant > metric->average) {
- metric->hicounter++;
- // This is to protect overflow, which should almost never happen.
- RTC_CHECK_NE(0, metric->hicounter);
- metric->hisum += metric->instant;
- metric->himean = metric->hisum / metric->hicounter;
- }
-}
-
-// Threshold to protect against the ill-effects of a zero far-end.
-const float WebRtcAec_kMinFarendPSD = 15;
-
-// Updates the following smoothed Power Spectral Densities (PSD):
-// - sd : near-end
-// - se : residual echo
-// - sx : far-end
-// - sde : cross-PSD of near-end and residual echo
-// - sxd : cross-PSD of near-end and far-end
-//
-// In addition to updating the PSDs, also the filter diverge state is
-// determined.
-static void UpdateCoherenceSpectra(int mult,
- bool extended_filter_enabled,
- float efw[2][PART_LEN1],
- float dfw[2][PART_LEN1],
- float xfw[2][PART_LEN1],
- CoherenceState* coherence_state,
- short* filter_divergence_state,
- int* extreme_filter_divergence) {
- // Power estimate smoothing coefficients.
- const float* ptrGCoh =
- extended_filter_enabled
- ? WebRtcAec_kExtendedSmoothingCoefficients[mult - 1]
- : WebRtcAec_kNormalSmoothingCoefficients[mult - 1];
- int i;
- float sdSum = 0, seSum = 0;
-
- for (i = 0; i < PART_LEN1; i++) {
- coherence_state->sd[i] =
- ptrGCoh[0] * coherence_state->sd[i] +
- ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
- coherence_state->se[i] =
- ptrGCoh[0] * coherence_state->se[i] +
- ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
- // We threshold here to protect against the ill-effects of a zero farend.
- // The threshold is not arbitrarily chosen, but balances protection and
- // adverse interaction with the algorithm's tuning.
- // TODO(bjornv): investigate further why this is so sensitive.
- coherence_state->sx[i] =
- ptrGCoh[0] * coherence_state->sx[i] +
- ptrGCoh[1] *
- WEBRTC_SPL_MAX(xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
- WebRtcAec_kMinFarendPSD);
-
- coherence_state->sde[i][0] =
- ptrGCoh[0] * coherence_state->sde[i][0] +
- ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
- coherence_state->sde[i][1] =
- ptrGCoh[0] * coherence_state->sde[i][1] +
- ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
-
- coherence_state->sxd[i][0] =
- ptrGCoh[0] * coherence_state->sxd[i][0] +
- ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
- coherence_state->sxd[i][1] =
- ptrGCoh[0] * coherence_state->sxd[i][1] +
- ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
-
- sdSum += coherence_state->sd[i];
- seSum += coherence_state->se[i];
- }
-
- // Divergent filter safeguard update.
- *filter_divergence_state =
- (*filter_divergence_state ? 1.05f : 1.0f) * seSum > sdSum;
-
- // Signal extreme filter divergence if the error is significantly larger
- // than the nearend (13 dB).
- *extreme_filter_divergence = (seSum > (19.95f * sdSum));
-}
-
-// Window time domain data to be used by the fft.
-__inline static void WindowData(float* x_windowed, const float* x) {
- int i;
- for (i = 0; i < PART_LEN; i++) {
- x_windowed[i] = x[i] * WebRtcAec_sqrtHanning[i];
- x_windowed[PART_LEN + i] =
- x[PART_LEN + i] * WebRtcAec_sqrtHanning[PART_LEN - i];
- }
-}
-
-// Puts fft output data into a complex valued array.
-__inline static void StoreAsComplex(const float* data,
- float data_complex[2][PART_LEN1]) {
- int i;
- data_complex[0][0] = data[0];
- data_complex[1][0] = 0;
- for (i = 1; i < PART_LEN; i++) {
- data_complex[0][i] = data[2 * i];
- data_complex[1][i] = data[2 * i + 1];
- }
- data_complex[0][PART_LEN] = data[1];
- data_complex[1][PART_LEN] = 0;
-}
-
-static void ComputeCoherence(const CoherenceState* coherence_state,
- float* cohde,
- float* cohxd) {
- // Subband coherence
- for (int i = 0; i < PART_LEN1; i++) {
- cohde[i] = (coherence_state->sde[i][0] * coherence_state->sde[i][0] +
- coherence_state->sde[i][1] * coherence_state->sde[i][1]) /
- (coherence_state->sd[i] * coherence_state->se[i] + 1e-10f);
- cohxd[i] = (coherence_state->sxd[i][0] * coherence_state->sxd[i][0] +
- coherence_state->sxd[i][1] * coherence_state->sxd[i][1]) /
- (coherence_state->sx[i] * coherence_state->sd[i] + 1e-10f);
- }
-}
-
-static void GetHighbandGain(const float* lambda, float* nlpGainHband) {
- int i;
-
- *nlpGainHband = 0.0f;
- for (i = freqAvgIc; i < PART_LEN1 - 1; i++) {
- *nlpGainHband += lambda[i];
- }
- *nlpGainHband /= static_cast<float>(PART_LEN1 - 1 - freqAvgIc);
-}
-
-static void GenerateComplexNoise(uint32_t* seed, float noise[2][PART_LEN1]) {
- const float kPi2 = 6.28318530717959f;
- int16_t randW16[PART_LEN];
- WebRtcSpl_RandUArray(randW16, PART_LEN, seed);
-
- noise[0][0] = 0;
- noise[1][0] = 0;
- for (size_t i = 1; i < PART_LEN1; i++) {
- float tmp = kPi2 * randW16[i - 1] / 32768.f;
- noise[0][i] = cosf(tmp);
- noise[1][i] = -sinf(tmp);
- }
- noise[1][PART_LEN] = 0;
-}
-
-static void ComfortNoise(bool generate_high_frequency_noise,
- uint32_t* seed,
- float e_fft[2][PART_LEN1],
- float high_frequency_comfort_noise[2][PART_LEN1],
- const float* noise_spectrum,
- const float* suppressor_gain) {
- float complex_noise[2][PART_LEN1];
-
- GenerateComplexNoise(seed, complex_noise);
-
- // Shape, scale and add comfort noise.
- for (int i = 1; i < PART_LEN1; ++i) {
- float noise_scaling =
- sqrtf(WEBRTC_SPL_MAX(1 - suppressor_gain[i] * suppressor_gain[i], 0)) *
- sqrtf(noise_spectrum[i]);
- e_fft[0][i] += noise_scaling * complex_noise[0][i];
- e_fft[1][i] += noise_scaling * complex_noise[1][i];
- }
-
- // Form comfort noise for higher frequencies.
- if (generate_high_frequency_noise) {
- // Compute average noise power and nlp gain over the second half of freq
- // spectrum (i.e., 4->8khz).
- int start_avg_band = PART_LEN1 / 2;
- float upper_bands_noise_power = 0.f;
- float upper_bands_suppressor_gain = 0.f;
- for (int i = start_avg_band; i < PART_LEN1; ++i) {
- upper_bands_noise_power += sqrtf(noise_spectrum[i]);
- upper_bands_suppressor_gain +=
- sqrtf(WEBRTC_SPL_MAX(1 - suppressor_gain[i] * suppressor_gain[i], 0));
- }
- upper_bands_noise_power /= (PART_LEN1 - start_avg_band);
- upper_bands_suppressor_gain /= (PART_LEN1 - start_avg_band);
-
- // Shape, scale and add comfort noise.
- float noise_scaling = upper_bands_suppressor_gain * upper_bands_noise_power;
- high_frequency_comfort_noise[0][0] = 0;
- high_frequency_comfort_noise[1][0] = 0;
- for (int i = 1; i < PART_LEN1; ++i) {
- high_frequency_comfort_noise[0][i] = noise_scaling * complex_noise[0][i];
- high_frequency_comfort_noise[1][i] = noise_scaling * complex_noise[1][i];
- }
- high_frequency_comfort_noise[1][PART_LEN] = 0;
- } else {
- memset(high_frequency_comfort_noise, 0,
- 2 * PART_LEN1 * sizeof(high_frequency_comfort_noise[0][0]));
- }
-}
-
-static void InitLevel(PowerLevel* level) {
- const float kBigFloat = 1E17f;
- level->averagelevel.Reset();
- level->framelevel.Reset();
- level->minlevel = kBigFloat;
-}
-
-static void InitStats(Stats* stats) {
- stats->instant = kOffsetLevel;
- stats->average = kOffsetLevel;
- stats->max = kOffsetLevel;
- stats->min = kOffsetLevel * (-1);
- stats->sum = 0;
- stats->hisum = 0;
- stats->himean = kOffsetLevel;
- stats->counter = 0;
- stats->hicounter = 0;
-}
-
-static void InitMetrics(AecCore* self) {
- self->stateCounter = 0;
- InitLevel(&self->farlevel);
- InitLevel(&self->nearlevel);
- InitLevel(&self->linoutlevel);
- InitLevel(&self->nlpoutlevel);
-
- InitStats(&self->erl);
- InitStats(&self->erle);
- InitStats(&self->aNlp);
- InitStats(&self->rerl);
-
- self->divergent_filter_fraction.Reset();
-}
-
-static float CalculatePower(const float* in, size_t num_samples) {
- size_t k;
- float energy = 0.0f;
-
- for (k = 0; k < num_samples; ++k) {
- energy += in[k] * in[k];
- }
- return energy / num_samples;
-}
-
-static void UpdateLevel(PowerLevel* level, float power) {
- level->framelevel.AddValue(power);
- if (level->framelevel.EndOfBlock()) {
- const float new_frame_level = level->framelevel.GetLatestMean();
- if (new_frame_level > 0) {
- if (new_frame_level < level->minlevel) {
- level->minlevel = new_frame_level; // New minimum.
- } else {
- level->minlevel *= (1 + 0.001f); // Small increase.
- }
- }
- level->averagelevel.AddValue(new_frame_level);
- }
-}
-
-static void UpdateMetrics(AecCore* aec) {
- const float actThresholdNoisy = 8.0f;
- const float actThresholdClean = 40.0f;
-
- const float noisyPower = 300000.0f;
-
- float actThreshold;
-
- if (aec->echoState) { // Check if echo is likely present
- aec->stateCounter++;
- }
-
- if (aec->linoutlevel.framelevel.EndOfBlock()) {
- aec->divergent_filter_fraction.AddObservation(
- aec->nearlevel, aec->linoutlevel, aec->nlpoutlevel);
- }
-
- if (aec->farlevel.averagelevel.EndOfBlock()) {
- if (aec->farlevel.minlevel < noisyPower) {
- actThreshold = actThresholdClean;
- } else {
- actThreshold = actThresholdNoisy;
- }
-
- const float far_average_level = aec->farlevel.averagelevel.GetLatestMean();
-
- // The last condition is to let estimation be made in active far-end
- // segments only.
- if ((aec->stateCounter > (0.5f * kCountLen * kSubCountLen)) &&
- (aec->farlevel.framelevel.EndOfBlock()) &&
- (far_average_level > (actThreshold * aec->farlevel.minlevel))) {
- // ERL: error return loss.
- const float near_average_level =
- aec->nearlevel.averagelevel.GetLatestMean();
- UpdateLogRatioMetric(&aec->erl, far_average_level, near_average_level);
-
- // A_NLP: error return loss enhanced before the nonlinear suppression.
- const float linout_average_level =
- aec->linoutlevel.averagelevel.GetLatestMean();
- UpdateLogRatioMetric(&aec->aNlp, near_average_level,
- linout_average_level);
-
- // ERLE: error return loss enhanced.
- const float nlpout_average_level =
- aec->nlpoutlevel.averagelevel.GetLatestMean();
- UpdateLogRatioMetric(&aec->erle, near_average_level,
- nlpout_average_level);
- }
-
- aec->stateCounter = 0;
- }
-}
-
-static void UpdateDelayMetrics(AecCore* self) {
- int i = 0;
- int delay_values = 0;
- int median = 0;
- int lookahead = WebRtc_lookahead(self->delay_estimator);
- const int kMsPerBlock = PART_LEN / (self->mult * 8);
- int64_t l1_norm = 0;
-
- if (self->num_delay_values == 0) {
- // We have no new delay value data. Even though -1 is a valid |median| in
- // the sense that we allow negative values, it will practically never be
- // used since multiples of |kMsPerBlock| will always be returned.
- // We therefore use -1 to indicate in the logs that the delay estimator was
- // not able to estimate the delay.
- self->delay_median = -1;
- self->delay_std = -1;
- self->fraction_poor_delays = -1;
- return;
- }
-
- // Start value for median count down.
- delay_values = self->num_delay_values >> 1;
- // Get median of delay values since last update.
- for (i = 0; i < kHistorySizeBlocks; i++) {
- delay_values -= self->delay_histogram[i];
- if (delay_values < 0) {
- median = i;
- break;
- }
- }
- // Account for lookahead.
- self->delay_median = (median - lookahead) * kMsPerBlock;
-
- // Calculate the L1 norm, with median value as central moment.
- for (i = 0; i < kHistorySizeBlocks; i++) {
- l1_norm += abs(i - median) * self->delay_histogram[i];
- }
- self->delay_std = static_cast<int>((l1_norm + self->num_delay_values / 2) /
- self->num_delay_values) *
- kMsPerBlock;
-
- // Determine fraction of delays that are out of bounds, that is, either
- // negative (anti-causal system) or larger than the AEC filter length.
- {
- int num_delays_out_of_bounds = self->num_delay_values;
- const int histogram_length =
- sizeof(self->delay_histogram) / sizeof(self->delay_histogram[0]);
- for (i = lookahead; i < lookahead + self->num_partitions; ++i) {
- if (i < histogram_length)
- num_delays_out_of_bounds -= self->delay_histogram[i];
- }
- self->fraction_poor_delays =
- static_cast<float>(num_delays_out_of_bounds) / self->num_delay_values;
- }
-
- // Reset histogram.
- memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
- self->num_delay_values = 0;
-}
-
-static void ScaledInverseFft(const OouraFft& ooura_fft,
- float freq_data[2][PART_LEN1],
- float time_data[PART_LEN2],
- float scale,
- int conjugate) {
- int i;
- const float normalization = scale / static_cast<float>(PART_LEN2);
- const float sign = (conjugate ? -1 : 1);
- time_data[0] = freq_data[0][0] * normalization;
- time_data[1] = freq_data[0][PART_LEN] * normalization;
- for (i = 1; i < PART_LEN; i++) {
- time_data[2 * i] = freq_data[0][i] * normalization;
- time_data[2 * i + 1] = sign * freq_data[1][i] * normalization;
- }
- ooura_fft.InverseFft(time_data);
-}
-
-static void Fft(const OouraFft& ooura_fft,
- float time_data[PART_LEN2],
- float freq_data[2][PART_LEN1]) {
- int i;
- ooura_fft.Fft(time_data);
-
- // Reorder fft output data.
- freq_data[1][0] = 0;
- freq_data[1][PART_LEN] = 0;
- freq_data[0][0] = time_data[0];
- freq_data[0][PART_LEN] = time_data[1];
- for (i = 1; i < PART_LEN; i++) {
- freq_data[0][i] = time_data[2 * i];
- freq_data[1][i] = time_data[2 * i + 1];
- }
-}
-
-static int SignalBasedDelayCorrection(AecCore* self) {
- int delay_correction = 0;
- int last_delay = -2;
- RTC_DCHECK(self);
-#if !defined(WEBRTC_ANDROID)
- // On desktops, turn on correction after |kDelayCorrectionStart| frames. This
- // is to let the delay estimation get a chance to converge. Also, if the
- // playout audio volume is low (or even muted) the delay estimation can return
- // a very large delay, which will break the AEC if it is applied.
- if (self->frame_count < kDelayCorrectionStart) {
- self->data_dumper->DumpRaw("aec_da_reported_delay", 1, &last_delay);
- return 0;
- }
-#endif
-
- // 1. Check for non-negative delay estimate. Note that the estimates we get
- // from the delay estimation are not compensated for lookahead. Hence, a
- // negative |last_delay| is an invalid one.
- // 2. Verify that there is a delay change. In addition, only allow a change
- // if the delay is outside a certain region taking the AEC filter length
- // into account.
- // TODO(bjornv): Investigate if we can remove the non-zero delay change check.
- // 3. Only allow delay correction if the delay estimation quality exceeds
- // |delay_quality_threshold|.
- // 4. Finally, verify that the proposed |delay_correction| is feasible by
- // comparing with the size of the far-end buffer.
- last_delay = WebRtc_last_delay(self->delay_estimator);
- self->data_dumper->DumpRaw("aec_da_reported_delay", 1, &last_delay);
- if ((last_delay >= 0) && (last_delay != self->previous_delay) &&
- (WebRtc_last_delay_quality(self->delay_estimator) >
- self->delay_quality_threshold)) {
- int delay = last_delay - WebRtc_lookahead(self->delay_estimator);
- // Allow for a slack in the actual delay, defined by a |lower_bound| and an
- // |upper_bound|. The adaptive echo cancellation filter is currently
- // |num_partitions| (of 64 samples) long. If the delay estimate is negative
- // or at least 3/4 of the filter length we open up for correction.
- const int lower_bound = 0;
- const int upper_bound = self->num_partitions * 3 / 4;
- const int do_correction = delay <= lower_bound || delay > upper_bound;
- if (do_correction == 1) {
- int available_read = self->farend_block_buffer_.Size();
- // With |shift_offset| we gradually rely on the delay estimates. For
- // positive delays we reduce the correction by |shift_offset| to lower the
- // risk of pushing the AEC into a non causal state. For negative delays
- // we rely on the values up to a rounding error, hence compensate by 1
- // element to make sure to push the delay into the causal region.
- delay_correction = -delay;
- delay_correction += delay > self->shift_offset ? self->shift_offset : 1;
- self->shift_offset--;
- self->shift_offset = (self->shift_offset <= 1 ? 1 : self->shift_offset);
- if (delay_correction > available_read - self->mult - 1) {
- // There is not enough data in the buffer to perform this shift. Hence,
- // we do not rely on the delay estimate and do nothing.
- delay_correction = 0;
- } else {
- self->previous_delay = last_delay;
- ++self->delay_correction_count;
- }
- }
- }
- // Update the |delay_quality_threshold| once we have our first delay
- // correction.
- if (self->delay_correction_count > 0) {
- float delay_quality = WebRtc_last_delay_quality(self->delay_estimator);
- delay_quality =
- (delay_quality > kDelayQualityThresholdMax ? kDelayQualityThresholdMax
- : delay_quality);
- self->delay_quality_threshold =
- (delay_quality > self->delay_quality_threshold
- ? delay_quality
- : self->delay_quality_threshold);
- }
- self->data_dumper->DumpRaw("aec_da_delay_correction", 1, &delay_correction);
-
- return delay_correction;
-}
-
-static void RegressorPower(
- int num_partitions,
- int latest_added_partition,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float x_pow[PART_LEN1]) {
- RTC_DCHECK_LT(latest_added_partition, num_partitions);
- memset(x_pow, 0, PART_LEN1 * sizeof(x_pow[0]));
-
- int partition = latest_added_partition;
- int x_fft_buf_position = partition * PART_LEN1;
- for (int i = 0; i < num_partitions; ++i) {
- for (int bin = 0; bin < PART_LEN1; ++bin) {
- float re = x_fft_buf[0][x_fft_buf_position];
- float im = x_fft_buf[1][x_fft_buf_position];
- x_pow[bin] += re * re + im * im;
- ++x_fft_buf_position;
- }
-
- ++partition;
- if (partition == num_partitions) {
- partition = 0;
- RTC_DCHECK_EQ(num_partitions * PART_LEN1, x_fft_buf_position);
- x_fft_buf_position = 0;
- }
- }
-}
-
-static void EchoSubtraction(
- const OouraFft& ooura_fft,
- int num_partitions,
- int extended_filter_enabled,
- int* extreme_filter_divergence,
- float filter_step_size,
- float error_threshold,
- float* x_fft,
- int* x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float* const y,
- float x_pow[PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float echo_subtractor_output[PART_LEN]) {
- float s_fft[2][PART_LEN1];
- float e_extended[PART_LEN2];
- float s_extended[PART_LEN2];
- float* s;
- float e[PART_LEN];
- float e_fft[2][PART_LEN1];
- int i;
-
- // Update the x_fft_buf block position.
- (*x_fft_buf_block_pos)--;
- if ((*x_fft_buf_block_pos) == -1) {
- *x_fft_buf_block_pos = num_partitions - 1;
- }
-
- // Buffer x_fft.
- memcpy(x_fft_buf[0] + (*x_fft_buf_block_pos) * PART_LEN1, x_fft,
- sizeof(float) * PART_LEN1);
- memcpy(x_fft_buf[1] + (*x_fft_buf_block_pos) * PART_LEN1, &x_fft[PART_LEN1],
- sizeof(float) * PART_LEN1);
-
- memset(s_fft, 0, sizeof(s_fft));
-
- // Conditionally reset the echo subtraction filter if the filter has diverged
- // significantly.
- if (!extended_filter_enabled && *extreme_filter_divergence) {
- memset(h_fft_buf, 0,
- 2 * kExtendedNumPartitions * PART_LEN1 * sizeof(h_fft_buf[0][0]));
- *extreme_filter_divergence = 0;
- }
-
- // Produce echo estimate s_fft.
- WebRtcAec_FilterFar(num_partitions, *x_fft_buf_block_pos, x_fft_buf,
- h_fft_buf, s_fft);
-
- // Compute the time-domain echo estimate s.
- ScaledInverseFft(ooura_fft, s_fft, s_extended, 2.0f, 0);
- s = &s_extended[PART_LEN];
-
- // Compute the time-domain echo prediction error.
- for (i = 0; i < PART_LEN; ++i) {
- e[i] = y[i] - s[i];
- }
-
- // Compute the frequency domain echo prediction error.
- memset(e_extended, 0, sizeof(float) * PART_LEN);
- memcpy(e_extended + PART_LEN, e, sizeof(float) * PART_LEN);
- Fft(ooura_fft, e_extended, e_fft);
-
- // Scale error signal inversely with far power.
- WebRtcAec_ScaleErrorSignal(filter_step_size, error_threshold, x_pow, e_fft);
- WebRtcAec_FilterAdaptation(ooura_fft, num_partitions, *x_fft_buf_block_pos,
- x_fft_buf, e_fft, h_fft_buf);
- memcpy(echo_subtractor_output, e, sizeof(float) * PART_LEN);
-}
-
-static void FormSuppressionGain(AecCore* aec,
- float cohde[PART_LEN1],
- float cohxd[PART_LEN1],
- float hNl[PART_LEN1]) {
- float hNlDeAvg, hNlXdAvg;
- float hNlPref[kPrefBandSize];
- float hNlFb = 0, hNlFbLow = 0;
- const int prefBandSize = kPrefBandSize / aec->mult;
- const float prefBandQuant = 0.75f, prefBandQuantLow = 0.5f;
- const int minPrefBand = 4 / aec->mult;
- // Power estimate smoothing coefficients.
- const float* min_overdrive = aec->extended_filter_enabled
- ? kExtendedMinOverDrive
- : kNormalMinOverDrive;
-
- hNlXdAvg = 0;
- for (int i = minPrefBand; i < prefBandSize + minPrefBand; ++i) {
- hNlXdAvg += cohxd[i];
- }
- hNlXdAvg /= prefBandSize;
- hNlXdAvg = 1 - hNlXdAvg;
-
- hNlDeAvg = 0;
- for (int i = minPrefBand; i < prefBandSize + minPrefBand; ++i) {
- hNlDeAvg += cohde[i];
- }
- hNlDeAvg /= prefBandSize;
-
- if (hNlXdAvg < 0.75f && hNlXdAvg < aec->hNlXdAvgMin) {
- aec->hNlXdAvgMin = hNlXdAvg;
- }
-
- if (hNlDeAvg > 0.98f && hNlXdAvg > 0.9f) {
- aec->stNearState = 1;
- } else if (hNlDeAvg < 0.95f || hNlXdAvg < 0.8f) {
- aec->stNearState = 0;
- }
-
- if (aec->hNlXdAvgMin == 1) {
- aec->echoState = 0;
- aec->overDrive = min_overdrive[aec->nlp_mode];
-
- if (aec->stNearState == 1) {
- memcpy(hNl, cohde, sizeof(hNl[0]) * PART_LEN1);
- hNlFb = hNlDeAvg;
- hNlFbLow = hNlDeAvg;
- } else {
- for (int i = 0; i < PART_LEN1; ++i) {
- hNl[i] = 1 - cohxd[i];
- hNl[i] = std::max(hNl[i], 0.f);
- }
- hNlFb = hNlXdAvg;
- hNlFbLow = hNlXdAvg;
- }
- } else {
- if (aec->stNearState == 1) {
- aec->echoState = 0;
- memcpy(hNl, cohde, sizeof(hNl[0]) * PART_LEN1);
- hNlFb = hNlDeAvg;
- hNlFbLow = hNlDeAvg;
- } else {
- aec->echoState = 1;
- for (int i = 0; i < PART_LEN1; ++i) {
- hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]);
- hNl[i] = std::max(hNl[i], 0.f);
- }
-
- // Select an order statistic from the preferred bands.
- // TODO(peah): Using quicksort now, but a selection algorithm may be
- // preferred.
- memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize);
- qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat);
- hNlFb = hNlPref[static_cast<int>(
- std::floor(prefBandQuant * (prefBandSize - 1)))];
- hNlFbLow = hNlPref[static_cast<int>(
- std::floor(prefBandQuantLow * (prefBandSize - 1)))];
- }
- }
-
- // Track the local filter minimum to determine suppression overdrive.
- if (hNlFbLow < 0.6f && hNlFbLow < aec->hNlFbLocalMin) {
- aec->hNlFbLocalMin = hNlFbLow;
- aec->hNlFbMin = hNlFbLow;
- aec->hNlNewMin = 1;
- aec->hNlMinCtr = 0;
- }
- aec->hNlFbLocalMin =
- WEBRTC_SPL_MIN(aec->hNlFbLocalMin + 0.0008f / aec->mult, 1);
- aec->hNlXdAvgMin = WEBRTC_SPL_MIN(aec->hNlXdAvgMin + 0.0006f / aec->mult, 1);
-
- if (aec->hNlNewMin == 1) {
- aec->hNlMinCtr++;
- }
- if (aec->hNlMinCtr == 2) {
- aec->hNlNewMin = 0;
- aec->hNlMinCtr = 0;
- aec->overDrive = WEBRTC_SPL_MAX(
- kTargetSupp[aec->nlp_mode] /
- static_cast<float>(std::log(aec->hNlFbMin + 1e-10f) + 1e-10f),
- min_overdrive[aec->nlp_mode]);
- }
-
- // Smooth the overdrive.
- if (aec->overDrive < aec->overdrive_scaling) {
- aec->overdrive_scaling =
- 0.99f * aec->overdrive_scaling + 0.01f * aec->overDrive;
- } else {
- aec->overdrive_scaling =
- 0.9f * aec->overdrive_scaling + 0.1f * aec->overDrive;
- }
-
- // Apply the overdrive.
- WebRtcAec_Overdrive(aec->overdrive_scaling, hNlFb, hNl);
-}
-
-static void EchoSuppression(const OouraFft& ooura_fft,
- AecCore* aec,
- float* nearend_extended_block_lowest_band,
- float farend_extended_block[PART_LEN2],
- float* echo_subtractor_output,
- float output[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) {
- float efw[2][PART_LEN1];
- float xfw[2][PART_LEN1];
- float dfw[2][PART_LEN1];
- float comfortNoiseHband[2][PART_LEN1];
- float fft[PART_LEN2];
- float nlpGainHband;
- int i;
- size_t j;
-
- // Coherence and non-linear filter
- float cohde[PART_LEN1], cohxd[PART_LEN1];
- float hNl[PART_LEN1];
-
- // Filter energy
- const int delayEstInterval = 10 * aec->mult;
-
- float* xfw_ptr = NULL;
-
- // Update eBuf with echo subtractor output.
- memcpy(aec->eBuf + PART_LEN, echo_subtractor_output,
- sizeof(float) * PART_LEN);
-
- // Analysis filter banks for the echo suppressor.
- // Windowed near-end ffts.
- WindowData(fft, nearend_extended_block_lowest_band);
- ooura_fft.Fft(fft);
- StoreAsComplex(fft, dfw);
-
- // Windowed echo suppressor output ffts.
- WindowData(fft, aec->eBuf);
- ooura_fft.Fft(fft);
- StoreAsComplex(fft, efw);
-
- // NLP
-
- // Convert far-end partition to the frequency domain with windowing.
- WindowData(fft, farend_extended_block);
- Fft(ooura_fft, fft, xfw);
- xfw_ptr = &xfw[0][0];
-
- // Buffer far.
- memcpy(aec->xfwBuf, xfw_ptr, sizeof(float) * 2 * PART_LEN1);
-
- aec->delayEstCtr++;
- if (aec->delayEstCtr == delayEstInterval) {
- aec->delayEstCtr = 0;
- aec->delayIdx = WebRtcAec_PartitionDelay(aec->num_partitions, aec->wfBuf);
- }
-
- aec->data_dumper->DumpRaw("aec_nlp_delay", 1, &aec->delayIdx);
-
- // Use delayed far.
- memcpy(xfw, aec->xfwBuf + aec->delayIdx * PART_LEN1,
- sizeof(xfw[0][0]) * 2 * PART_LEN1);
-
- WebRtcAec_UpdateCoherenceSpectra(aec->mult, aec->extended_filter_enabled == 1,
- efw, dfw, xfw, &aec->coherence_state,
- &aec->divergeState,
- &aec->extreme_filter_divergence);
-
- WebRtcAec_ComputeCoherence(&aec->coherence_state, cohde, cohxd);
-
- // Select the microphone signal as output if the filter is deemed to have
- // diverged.
- if (aec->divergeState) {
- memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
- }
-
- FormSuppressionGain(aec, cohde, cohxd, hNl);
-
- aec->data_dumper->DumpRaw("aec_nlp_gain", PART_LEN1, hNl);
-
- WebRtcAec_Suppress(hNl, efw);
-
- // Add comfort noise.
- ComfortNoise(aec->num_bands > 1, &aec->seed, efw, comfortNoiseHband,
- aec->noisePow, hNl);
-
- // Inverse error fft.
- ScaledInverseFft(ooura_fft, efw, fft, 2.0f, 1);
-
- // Overlap and add to obtain output.
- for (i = 0; i < PART_LEN; i++) {
- output[0][i] = (fft[i] * WebRtcAec_sqrtHanning[i] +
- aec->outBuf[i] * WebRtcAec_sqrtHanning[PART_LEN - i]);
-
- // Saturate output to keep it in the allowed range.
- output[0][i] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, output[0][i],
- WEBRTC_SPL_WORD16_MIN);
- }
- memcpy(aec->outBuf, &fft[PART_LEN], PART_LEN * sizeof(aec->outBuf[0]));
-
- // For H band
- if (aec->num_bands > 1) {
- // H band gain
- // average nlp over low band: average over second half of freq spectrum
- // (4->8khz)
- GetHighbandGain(hNl, &nlpGainHband);
-
- // Inverse comfort_noise
- ScaledInverseFft(ooura_fft, comfortNoiseHband, fft, 2.0f, 0);
-
- // compute gain factor
- for (j = 1; j < aec->num_bands; ++j) {
- for (i = 0; i < PART_LEN; i++) {
- output[j][i] = aec->previous_nearend_block[j][i] * nlpGainHband;
- }
- }
-
- // Add some comfort noise where Hband is attenuated.
- for (i = 0; i < PART_LEN; i++) {
- output[1][i] += cnScaleHband * fft[i];
- }
-
- // Saturate output to keep it in the allowed range.
- for (j = 1; j < aec->num_bands; ++j) {
- for (i = 0; i < PART_LEN; i++) {
- output[j][i] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, output[j][i],
- WEBRTC_SPL_WORD16_MIN);
- }
- }
- }
-
- // Copy the current block to the old position.
- memcpy(aec->eBuf, aec->eBuf + PART_LEN, sizeof(float) * PART_LEN);
-
- memmove(aec->xfwBuf + PART_LEN1, aec->xfwBuf,
- sizeof(aec->xfwBuf) - sizeof(complex_t) * PART_LEN1);
-}
-
-static void ProcessNearendBlock(
- AecCore* aec,
- float farend_extended_block_lowest_band[PART_LEN2],
- float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN],
- float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) {
- size_t i;
-
- float fft[PART_LEN2];
- float nearend_extended_block_lowest_band[PART_LEN2];
- float farend_fft[2][PART_LEN1];
- float nearend_fft[2][PART_LEN1];
- float far_spectrum = 0.0f;
- float near_spectrum = 0.0f;
- float abs_far_spectrum[PART_LEN1];
- float abs_near_spectrum[PART_LEN1];
-
- const float gPow[2] = {0.9f, 0.1f};
-
- // Noise estimate constants.
- const int noiseInitBlocks = 500 * aec->mult;
- const float step = 0.1f;
- const float ramp = 1.0002f;
- const float gInitNoise[2] = {0.999f, 0.001f};
-
- float echo_subtractor_output[PART_LEN];
-
- aec->data_dumper->DumpWav("aec_far", PART_LEN,
- &farend_extended_block_lowest_band[PART_LEN],
- std::min(aec->sampFreq, 16000), 1);
- aec->data_dumper->DumpWav("aec_near", PART_LEN, &nearend_block[0][0],
- std::min(aec->sampFreq, 16000), 1);
-
- if (aec->metricsMode == 1) {
- // Update power levels
- UpdateLevel(
- &aec->farlevel,
- CalculatePower(&farend_extended_block_lowest_band[PART_LEN], PART_LEN));
- UpdateLevel(&aec->nearlevel,
- CalculatePower(&nearend_block[0][0], PART_LEN));
- }
-
- // Convert far-end signal to the frequency domain.
- memcpy(fft, farend_extended_block_lowest_band, sizeof(float) * PART_LEN2);
- Fft(aec->ooura_fft, fft, farend_fft);
-
- // Form extended nearend frame.
- memcpy(&nearend_extended_block_lowest_band[0],
- &aec->previous_nearend_block[0][0], sizeof(float) * PART_LEN);
- memcpy(&nearend_extended_block_lowest_band[PART_LEN], &nearend_block[0][0],
- sizeof(float) * PART_LEN);
-
- // Convert near-end signal to the frequency domain.
- memcpy(fft, nearend_extended_block_lowest_band, sizeof(float) * PART_LEN2);
- Fft(aec->ooura_fft, fft, nearend_fft);
-
- // Power smoothing.
- if (aec->refined_adaptive_filter_enabled) {
- for (i = 0; i < PART_LEN1; ++i) {
- far_spectrum = farend_fft[0][i] * farend_fft[0][i] +
- farend_fft[1][i] * farend_fft[1][i];
- // Calculate the magnitude spectrum.
- abs_far_spectrum[i] = sqrtf(far_spectrum);
- }
- RegressorPower(aec->num_partitions, aec->xfBufBlockPos, aec->xfBuf,
- aec->xPow);
- } else {
- for (i = 0; i < PART_LEN1; ++i) {
- far_spectrum = farend_fft[0][i] * farend_fft[0][i] +
- farend_fft[1][i] * farend_fft[1][i];
- aec->xPow[i] =
- gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum;
- // Calculate the magnitude spectrum.
- abs_far_spectrum[i] = sqrtf(far_spectrum);
- }
- }
-
- for (i = 0; i < PART_LEN1; ++i) {
- near_spectrum = nearend_fft[0][i] * nearend_fft[0][i] +
- nearend_fft[1][i] * nearend_fft[1][i];
- aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum;
- // Calculate the magnitude spectrum.
- abs_near_spectrum[i] = sqrtf(near_spectrum);
- }
-
- // Estimate noise power. Wait until dPow is more stable.
- if (aec->noiseEstCtr > 50) {
- for (i = 0; i < PART_LEN1; i++) {
- if (aec->dPow[i] < aec->dMinPow[i]) {
- aec->dMinPow[i] =
- (aec->dPow[i] + step * (aec->dMinPow[i] - aec->dPow[i])) * ramp;
- } else {
- aec->dMinPow[i] *= ramp;
- }
- }
- }
-
- // Smooth increasing noise power from zero at the start,
- // to avoid a sudden burst of comfort noise.
- if (aec->noiseEstCtr < noiseInitBlocks) {
- aec->noiseEstCtr++;
- for (i = 0; i < PART_LEN1; i++) {
- if (aec->dMinPow[i] > aec->dInitMinPow[i]) {
- aec->dInitMinPow[i] = gInitNoise[0] * aec->dInitMinPow[i] +
- gInitNoise[1] * aec->dMinPow[i];
- } else {
- aec->dInitMinPow[i] = aec->dMinPow[i];
- }
- }
- aec->noisePow = aec->dInitMinPow;
- } else {
- aec->noisePow = aec->dMinPow;
- }
-
- // Block wise delay estimation used for logging
- if (aec->delay_logging_enabled) {
- if (WebRtc_AddFarSpectrumFloat(aec->delay_estimator_farend,
- abs_far_spectrum, PART_LEN1) == 0) {
- int delay_estimate = WebRtc_DelayEstimatorProcessFloat(
- aec->delay_estimator, abs_near_spectrum, PART_LEN1);
- if (delay_estimate >= 0) {
- // Update delay estimate buffer.
- aec->delay_histogram[delay_estimate]++;
- aec->num_delay_values++;
- }
- if (aec->delay_metrics_delivered == 1 &&
- aec->num_delay_values >= kDelayMetricsAggregationWindow) {
- UpdateDelayMetrics(aec);
- }
- }
- }
-
- // Perform echo subtraction.
- EchoSubtraction(
- aec->ooura_fft, aec->num_partitions, aec->extended_filter_enabled,
- &aec->extreme_filter_divergence, aec->filter_step_size,
- aec->error_threshold, &farend_fft[0][0], &aec->xfBufBlockPos, aec->xfBuf,
- &nearend_block[0][0], aec->xPow, aec->wfBuf, echo_subtractor_output);
- aec->data_dumper->DumpRaw("aec_h_fft", PART_LEN1 * aec->num_partitions,
- &aec->wfBuf[0][0]);
- aec->data_dumper->DumpRaw("aec_h_fft", PART_LEN1 * aec->num_partitions,
- &aec->wfBuf[1][0]);
-
- aec->data_dumper->DumpWav("aec_out_linear", PART_LEN, echo_subtractor_output,
- std::min(aec->sampFreq, 16000), 1);
-
- if (aec->metricsMode == 1) {
- UpdateLevel(&aec->linoutlevel,
- CalculatePower(echo_subtractor_output, PART_LEN));
- }
-
- // Perform echo suppression.
- EchoSuppression(aec->ooura_fft, aec, nearend_extended_block_lowest_band,
- farend_extended_block_lowest_band, echo_subtractor_output,
- output_block);
-
- if (aec->metricsMode == 1) {
- UpdateLevel(&aec->nlpoutlevel,
- CalculatePower(&output_block[0][0], PART_LEN));
- UpdateMetrics(aec);
- }
-
- // Store the nearend signal until the next frame.
- for (i = 0; i < aec->num_bands; ++i) {
- memcpy(&aec->previous_nearend_block[i][0], &nearend_block[i][0],
- sizeof(float) * PART_LEN);
- }
-
- aec->data_dumper->DumpWav("aec_out", PART_LEN, &output_block[0][0],
- std::min(aec->sampFreq, 16000), 1);
-}
-
-AecCore* WebRtcAec_CreateAec(int instance_count) {
- AecCore* aec = new AecCore(instance_count);
-
- if (!aec) {
- return NULL;
- }
- aec->nearend_buffer_size = 0;
- memset(&aec->nearend_buffer[0], 0, sizeof(aec->nearend_buffer));
- // Start the output buffer with zeros to be able to produce
- // a full output frame in the first frame.
- aec->output_buffer_size = PART_LEN - (FRAME_LEN - PART_LEN);
- memset(&aec->output_buffer[0], 0, sizeof(aec->output_buffer));
-
- aec->delay_estimator_farend =
- WebRtc_CreateDelayEstimatorFarend(PART_LEN1, kHistorySizeBlocks);
- if (aec->delay_estimator_farend == NULL) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
- // We create the delay_estimator with the same amount of maximum lookahead as
- // the delay history size (kHistorySizeBlocks) for symmetry reasons.
- aec->delay_estimator = WebRtc_CreateDelayEstimator(
- aec->delay_estimator_farend, kHistorySizeBlocks);
- if (aec->delay_estimator == NULL) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
-#ifdef WEBRTC_ANDROID
- aec->delay_agnostic_enabled = 1; // DA-AEC enabled by default.
- // DA-AEC assumes the system is causal from the beginning and will self adjust
- // the lookahead when shifting is required.
- WebRtc_set_lookahead(aec->delay_estimator, 0);
-#else
- aec->delay_agnostic_enabled = 0;
- WebRtc_set_lookahead(aec->delay_estimator, kLookaheadBlocks);
-#endif
- aec->extended_filter_enabled = 0;
- aec->refined_adaptive_filter_enabled = false;
-
- // Assembly optimization
- WebRtcAec_FilterFar = FilterFar;
- WebRtcAec_ScaleErrorSignal = ScaleErrorSignal;
- WebRtcAec_FilterAdaptation = FilterAdaptation;
- WebRtcAec_Overdrive = Overdrive;
- WebRtcAec_Suppress = Suppress;
- WebRtcAec_ComputeCoherence = ComputeCoherence;
- WebRtcAec_UpdateCoherenceSpectra = UpdateCoherenceSpectra;
- WebRtcAec_StoreAsComplex = StoreAsComplex;
- WebRtcAec_PartitionDelay = PartitionDelay;
- WebRtcAec_WindowData = WindowData;
-
-#if defined(WEBRTC_ARCH_X86_FAMILY)
- if (WebRtc_GetCPUInfo(kSSE2)) {
- WebRtcAec_InitAec_SSE2();
- }
-#endif
-
-#if defined(MIPS_FPU_LE)
- WebRtcAec_InitAec_mips();
-#endif
-
-#if defined(WEBRTC_HAS_NEON)
- WebRtcAec_InitAec_neon();
-#endif
-
- return aec;
-}
-
-void WebRtcAec_FreeAec(AecCore* aec) {
- if (aec == NULL) {
- return;
- }
-
- WebRtc_FreeDelayEstimator(aec->delay_estimator);
- WebRtc_FreeDelayEstimatorFarend(aec->delay_estimator_farend);
-
- delete aec;
-}
-
-static void SetAdaptiveFilterStepSize(AecCore* aec) {
- // Extended filter adaptation parameter.
- // TODO(ajm): No narrowband tuning yet.
- const float kExtendedMu = 0.4f;
-
- if (aec->refined_adaptive_filter_enabled) {
- aec->filter_step_size = 0.05f;
- } else {
- if (aec->extended_filter_enabled) {
- aec->filter_step_size = kExtendedMu;
- } else {
- if (aec->sampFreq == 8000) {
- aec->filter_step_size = 0.6f;
- } else {
- aec->filter_step_size = 0.5f;
- }
- }
- }
-}
-
-static void SetErrorThreshold(AecCore* aec) {
- // Extended filter adaptation parameter.
- // TODO(ajm): No narrowband tuning yet.
- static const float kExtendedErrorThreshold = 1.0e-6f;
-
- if (aec->extended_filter_enabled) {
- aec->error_threshold = kExtendedErrorThreshold;
- } else {
- if (aec->sampFreq == 8000) {
- aec->error_threshold = 2e-6f;
- } else {
- aec->error_threshold = 1.5e-6f;
- }
- }
-}
-
-int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
- int i;
- aec->data_dumper->InitiateNewSetOfRecordings();
-
- aec->sampFreq = sampFreq;
-
- SetAdaptiveFilterStepSize(aec);
- SetErrorThreshold(aec);
-
- if (sampFreq == 8000) {
- aec->num_bands = 1;
- } else {
- aec->num_bands = (size_t)(sampFreq / 16000);
- }
-
- // Start the output buffer with zeros to be able to produce
- // a full output frame in the first frame.
- aec->output_buffer_size = PART_LEN - (FRAME_LEN - PART_LEN);
- memset(&aec->output_buffer[0], 0, sizeof(aec->output_buffer));
- aec->nearend_buffer_size = 0;
- memset(&aec->nearend_buffer[0], 0, sizeof(aec->nearend_buffer));
-
- // Initialize far-end buffer.
- aec->farend_block_buffer_.ReInit();
-
- aec->system_delay = 0;
-
- if (WebRtc_InitDelayEstimatorFarend(aec->delay_estimator_farend) != 0) {
- return -1;
- }
- if (WebRtc_InitDelayEstimator(aec->delay_estimator) != 0) {
- return -1;
- }
- aec->delay_logging_enabled = 0;
- aec->delay_metrics_delivered = 0;
- memset(aec->delay_histogram, 0, sizeof(aec->delay_histogram));
- aec->num_delay_values = 0;
- aec->delay_median = -1;
- aec->delay_std = -1;
- aec->fraction_poor_delays = -1.0f;
-
- aec->previous_delay = -2; // (-2): Uninitialized.
- aec->delay_correction_count = 0;
- aec->shift_offset = kInitialShiftOffset;
- aec->delay_quality_threshold = kDelayQualityThresholdMin;
-
- aec->num_partitions = kNormalNumPartitions;
-
- // Update the delay estimator with filter length. We use half the
- // |num_partitions| to take the echo path into account. In practice we say
- // that the echo has a duration of maximum half |num_partitions|, which is not
- // true, but serves as a crude measure.
- WebRtc_set_allowed_offset(aec->delay_estimator, aec->num_partitions / 2);
- // TODO(bjornv): I currently hard coded the enable. Once we've established
- // that AECM has no performance regression, robust_validation will be enabled
- // all the time and the APIs to turn it on/off will be removed. Hence, remove
- // this line then.
- WebRtc_enable_robust_validation(aec->delay_estimator, 1);
- aec->frame_count = 0;
-
- // Default target suppression mode.
- aec->nlp_mode = 1;
-
- // Sampling frequency multiplier w.r.t. 8 kHz.
- // In case of multiple bands we process the lower band in 16 kHz, hence the
- // multiplier is always 2.
- if (aec->num_bands > 1) {
- aec->mult = 2;
- } else {
- aec->mult = static_cast<int16_t>(aec->sampFreq) / 8000;
- }
-
- aec->farBufWritePos = 0;
- aec->farBufReadPos = 0;
-
- aec->inSamples = 0;
- aec->outSamples = 0;
- aec->knownDelay = 0;
-
- // Initialize buffers
- memset(aec->previous_nearend_block, 0, sizeof(aec->previous_nearend_block));
- memset(aec->eBuf, 0, sizeof(aec->eBuf));
-
- memset(aec->xPow, 0, sizeof(aec->xPow));
- memset(aec->dPow, 0, sizeof(aec->dPow));
- memset(aec->dInitMinPow, 0, sizeof(aec->dInitMinPow));
- aec->noisePow = aec->dInitMinPow;
- aec->noiseEstCtr = 0;
-
- // Initial comfort noise power
- for (i = 0; i < PART_LEN1; i++) {
- aec->dMinPow[i] = 1.0e6f;
- }
-
- // Holds the last block written to
- aec->xfBufBlockPos = 0;
- // TODO(peah): Investigate need for these initializations. Deleting them
- // doesn't change the output at all and yields 0.4% overall speedup.
- memset(aec->xfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
- memset(aec->wfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
- memset(aec->coherence_state.sde, 0, sizeof(complex_t) * PART_LEN1);
- memset(aec->coherence_state.sxd, 0, sizeof(complex_t) * PART_LEN1);
- memset(aec->xfwBuf, 0,
- sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
- memset(aec->coherence_state.se, 0, sizeof(float) * PART_LEN1);
-
- // To prevent numerical instability in the first block.
- for (i = 0; i < PART_LEN1; i++) {
- aec->coherence_state.sd[i] = 1;
- }
- for (i = 0; i < PART_LEN1; i++) {
- aec->coherence_state.sx[i] = 1;
- }
-
- memset(aec->hNs, 0, sizeof(aec->hNs));
- memset(aec->outBuf, 0, sizeof(float) * PART_LEN);
-
- aec->hNlFbMin = 1;
- aec->hNlFbLocalMin = 1;
- aec->hNlXdAvgMin = 1;
- aec->hNlNewMin = 0;
- aec->hNlMinCtr = 0;
- aec->overDrive = 2;
- aec->overdrive_scaling = 2;
- aec->delayIdx = 0;
- aec->stNearState = 0;
- aec->echoState = 0;
- aec->divergeState = 0;
-
- aec->seed = 777;
- aec->delayEstCtr = 0;
-
- aec->extreme_filter_divergence = 0;
-
- // Metrics disabled by default
- aec->metricsMode = 0;
- InitMetrics(aec);
-
- return 0;
-}
-
-void WebRtcAec_BufferFarendBlock(AecCore* aec, const float* farend) {
- // Check if the buffer is full, and in that case flush the oldest data.
- if (aec->farend_block_buffer_.AvaliableSpace() < 1) {
- aec->farend_block_buffer_.AdjustSize(1);
- }
- aec->farend_block_buffer_.Insert(farend);
-}
-
-int WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(AecCore* aec,
- int buffer_size_decrease) {
- int achieved_buffer_size_decrease =
- aec->farend_block_buffer_.AdjustSize(buffer_size_decrease);
- aec->system_delay -= achieved_buffer_size_decrease * PART_LEN;
- return achieved_buffer_size_decrease;
-}
-
-void FormNearendBlock(
- size_t nearend_start_index,
- size_t num_bands,
- const float* const* nearend_frame,
- size_t num_samples_from_nearend_frame,
- const float nearend_buffer[NUM_HIGH_BANDS_MAX + 1]
- [PART_LEN - (FRAME_LEN - PART_LEN)],
- float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) {
- RTC_DCHECK_LE(num_samples_from_nearend_frame, PART_LEN);
- const int num_samples_from_buffer = PART_LEN - num_samples_from_nearend_frame;
-
- if (num_samples_from_buffer > 0) {
- for (size_t i = 0; i < num_bands; ++i) {
- memcpy(&nearend_block[i][0], &nearend_buffer[i][0],
- num_samples_from_buffer * sizeof(float));
- }
- }
-
- for (size_t i = 0; i < num_bands; ++i) {
- memcpy(&nearend_block[i][num_samples_from_buffer],
- &nearend_frame[i][nearend_start_index],
- num_samples_from_nearend_frame * sizeof(float));
- }
-}
-
-void BufferNearendFrame(
- size_t nearend_start_index,
- size_t num_bands,
- const float* const* nearend_frame,
- size_t num_samples_to_buffer,
- float nearend_buffer[NUM_HIGH_BANDS_MAX + 1]
- [PART_LEN - (FRAME_LEN - PART_LEN)]) {
- for (size_t i = 0; i < num_bands; ++i) {
- memcpy(&nearend_buffer[i][0],
- &nearend_frame[i][nearend_start_index + FRAME_LEN -
- num_samples_to_buffer],
- num_samples_to_buffer * sizeof(float));
- }
-}
-
-void BufferOutputBlock(
- size_t num_bands,
- const float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN],
- size_t* output_buffer_size,
- float output_buffer[NUM_HIGH_BANDS_MAX + 1][2 * PART_LEN]) {
- for (size_t i = 0; i < num_bands; ++i) {
- memcpy(&output_buffer[i][*output_buffer_size], &output_block[i][0],
- PART_LEN * sizeof(float));
- }
- (*output_buffer_size) += PART_LEN;
-}
-
-void FormOutputFrame(size_t output_start_index,
- size_t num_bands,
- size_t* output_buffer_size,
- float output_buffer[NUM_HIGH_BANDS_MAX + 1][2 * PART_LEN],
- float* const* output_frame) {
- RTC_DCHECK_LE(FRAME_LEN, *output_buffer_size);
- for (size_t i = 0; i < num_bands; ++i) {
- memcpy(&output_frame[i][output_start_index], &output_buffer[i][0],
- FRAME_LEN * sizeof(float));
- }
- (*output_buffer_size) -= FRAME_LEN;
- if (*output_buffer_size > 0) {
- RTC_DCHECK_GE(2 * PART_LEN - FRAME_LEN, (*output_buffer_size));
- for (size_t i = 0; i < num_bands; ++i) {
- memcpy(&output_buffer[i][0], &output_buffer[i][FRAME_LEN],
- (*output_buffer_size) * sizeof(float));
- }
- }
-}
-
-void WebRtcAec_ProcessFrames(AecCore* aec,
- const float* const* nearend,
- size_t num_bands,
- size_t num_samples,
- int knownDelay,
- float* const* out) {
- RTC_DCHECK(num_samples == 80 || num_samples == 160);
-
- aec->frame_count++;
- // For each frame the process is as follows:
- // 1) If the system_delay indicates on being too small for processing a
- // frame we stuff the buffer with enough data for 10 ms.
- // 2 a) Adjust the buffer to the system delay, by moving the read pointer.
- // b) Apply signal based delay correction, if we have detected poor AEC
- // performance.
- // 3) TODO(bjornv): Investigate if we need to add this:
- // If we can't move read pointer due to buffer size limitations we
- // flush/stuff the buffer.
- // 4) Process as many partitions as possible.
- // 5) Update the |system_delay| with respect to a full frame of FRAME_LEN
- // samples. Even though we will have data left to process (we work with
- // partitions) we consider updating a whole frame, since that's the
- // amount of data we input and output in audio_processing.
- // 6) Update the outputs.
-
- // The AEC has two different delay estimation algorithms built in. The
- // first relies on delay input values from the user and the amount of
- // shifted buffer elements is controlled by |knownDelay|. This delay will
- // give a guess on how much we need to shift far-end buffers to align with
- // the near-end signal. The other delay estimation algorithm uses the
- // far- and near-end signals to find the offset between them. This one
- // (called "signal delay") is then used to fine tune the alignment, or
- // simply compensate for errors in the system based one.
- // Note that the two algorithms operate independently. Currently, we only
- // allow one algorithm to be turned on.
-
- RTC_DCHECK_EQ(aec->num_bands, num_bands);
-
- for (size_t j = 0; j < num_samples; j += FRAME_LEN) {
- // 1) At most we process |aec->mult|+1 partitions in 10 ms. Make sure we
- // have enough far-end data for that by stuffing the buffer if the
- // |system_delay| indicates others.
- if (aec->system_delay < FRAME_LEN) {
- // We don't have enough data so we rewind 10 ms.
- WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aec, -(aec->mult + 1));
- }
-
- if (!aec->delay_agnostic_enabled) {
- // 2 a) Compensate for a possible change in the system delay.
-
- // TODO(bjornv): Investigate how we should round the delay difference;
- // right now we know that incoming |knownDelay| is underestimated when
- // it's less than |aec->knownDelay|. We therefore, round (-32) in that
- // direction. In the other direction, we don't have this situation, but
- // might flush one partition too little. This can cause non-causality,
- // which should be investigated. Maybe, allow for a non-symmetric
- // rounding, like -16.
- int move_elements = (aec->knownDelay - knownDelay - 32) / PART_LEN;
- int moved_elements = aec->farend_block_buffer_.AdjustSize(move_elements);
- aec->knownDelay -= moved_elements * PART_LEN;
- } else {
- // 2 b) Apply signal based delay correction.
- int move_elements = SignalBasedDelayCorrection(aec);
- int moved_elements = aec->farend_block_buffer_.AdjustSize(move_elements);
- int far_near_buffer_diff =
- aec->farend_block_buffer_.Size() -
- (aec->nearend_buffer_size + FRAME_LEN) / PART_LEN;
- WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements);
- WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend,
- moved_elements);
- // If we rely on reported system delay values only, a buffer underrun here
- // can never occur since we've taken care of that in 1) above. Here, we
- // apply signal based delay correction and can therefore end up with
- // buffer underruns since the delay estimation can be wrong. We therefore
- // stuff the buffer with enough elements if needed.
- if (far_near_buffer_diff < 0) {
- WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aec,
- far_near_buffer_diff);
- }
- }
-
- static_assert(
- 16 == (FRAME_LEN - PART_LEN),
- "These constants need to be properly related for this code to work");
- float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN];
- float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN];
- float farend_extended_block_lowest_band[PART_LEN2];
-
- // Form and process a block of nearend samples, buffer the output block of
- // samples.
- aec->farend_block_buffer_.ExtractExtendedBlock(
- farend_extended_block_lowest_band);
- FormNearendBlock(j, num_bands, nearend, PART_LEN - aec->nearend_buffer_size,
- aec->nearend_buffer, nearend_block);
- ProcessNearendBlock(aec, farend_extended_block_lowest_band, nearend_block,
- output_block);
- BufferOutputBlock(num_bands, output_block, &aec->output_buffer_size,
- aec->output_buffer);
-
- if ((FRAME_LEN - PART_LEN + aec->nearend_buffer_size) == PART_LEN) {
- // When possible (every fourth frame) form and process a second block of
- // nearend samples, buffer the output block of samples.
- aec->farend_block_buffer_.ExtractExtendedBlock(
- farend_extended_block_lowest_band);
- FormNearendBlock(j + FRAME_LEN - PART_LEN, num_bands, nearend, PART_LEN,
- aec->nearend_buffer, nearend_block);
- ProcessNearendBlock(aec, farend_extended_block_lowest_band, nearend_block,
- output_block);
- BufferOutputBlock(num_bands, output_block, &aec->output_buffer_size,
- aec->output_buffer);
-
- // Reset the buffer size as there are no samples left in the nearend input
- // to buffer.
- aec->nearend_buffer_size = 0;
- } else {
- // Buffer the remaining samples in the nearend input.
- aec->nearend_buffer_size += FRAME_LEN - PART_LEN;
- BufferNearendFrame(j, num_bands, nearend, aec->nearend_buffer_size,
- aec->nearend_buffer);
- }
-
- // 5) Update system delay with respect to the entire frame.
- aec->system_delay -= FRAME_LEN;
-
- // 6) Form the output frame.
- FormOutputFrame(j, num_bands, &aec->output_buffer_size, aec->output_buffer,
- out);
- }
-}
-
-int WebRtcAec_GetDelayMetricsCore(AecCore* self,
- int* median,
- int* std,
- float* fraction_poor_delays) {
- RTC_DCHECK(self);
- RTC_DCHECK(median);
- RTC_DCHECK(std);
-
- if (self->delay_logging_enabled == 0) {
- // Logging disabled.
- return -1;
- }
-
- if (self->delay_metrics_delivered == 0) {
- UpdateDelayMetrics(self);
- self->delay_metrics_delivered = 1;
- }
- *median = self->delay_median;
- *std = self->delay_std;
- *fraction_poor_delays = self->fraction_poor_delays;
-
- return 0;
-}
-
-int WebRtcAec_echo_state(AecCore* self) {
- return self->echoState;
-}
-
-void WebRtcAec_GetEchoStats(AecCore* self,
- Stats* erl,
- Stats* erle,
- Stats* a_nlp,
- float* divergent_filter_fraction) {
- RTC_DCHECK(erl);
- RTC_DCHECK(erle);
- RTC_DCHECK(a_nlp);
- *erl = self->erl;
- *erle = self->erle;
- *a_nlp = self->aNlp;
- *divergent_filter_fraction =
- self->divergent_filter_fraction.GetLatestFraction();
-}
-
-void WebRtcAec_SetConfigCore(AecCore* self,
- int nlp_mode,
- int metrics_mode,
- int delay_logging) {
- RTC_DCHECK_GE(nlp_mode, 0);
- RTC_DCHECK_LT(nlp_mode, 3);
- self->nlp_mode = nlp_mode;
- self->metricsMode = metrics_mode;
- if (self->metricsMode) {
- InitMetrics(self);
- }
- // Turn on delay logging if it is either set explicitly or if delay agnostic
- // AEC is enabled (which requires delay estimates).
- self->delay_logging_enabled = delay_logging || self->delay_agnostic_enabled;
- if (self->delay_logging_enabled) {
- memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
- }
-}
-
-void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable) {
- self->delay_agnostic_enabled = enable;
-}
-
-int WebRtcAec_delay_agnostic_enabled(AecCore* self) {
- return self->delay_agnostic_enabled;
-}
-
-void WebRtcAec_enable_refined_adaptive_filter(AecCore* self, bool enable) {
- self->refined_adaptive_filter_enabled = enable;
- SetAdaptiveFilterStepSize(self);
- SetErrorThreshold(self);
-}
-
-bool WebRtcAec_refined_adaptive_filter_enabled(const AecCore* self) {
- return self->refined_adaptive_filter_enabled;
-}
-
-void WebRtcAec_enable_extended_filter(AecCore* self, int enable) {
- self->extended_filter_enabled = enable;
- SetAdaptiveFilterStepSize(self);
- SetErrorThreshold(self);
- self->num_partitions = enable ? kExtendedNumPartitions : kNormalNumPartitions;
- // Update the delay estimator with filter length. See InitAEC() for details.
- WebRtc_set_allowed_offset(self->delay_estimator, self->num_partitions / 2);
-}
-
-int WebRtcAec_extended_filter_enabled(AecCore* self) {
- return self->extended_filter_enabled;
-}
-
-int WebRtcAec_system_delay(AecCore* self) {
- return self->system_delay;
-}
-
-void WebRtcAec_SetSystemDelay(AecCore* self, int delay) {
- RTC_DCHECK_GE(delay, 0);
- self->system_delay = delay;
-}
-} // namespace webrtc
diff --git a/modules/audio_processing/aec/aec_core.h b/modules/audio_processing/aec/aec_core.h
deleted file mode 100644
index 659b6a1..0000000
--- a/modules/audio_processing/aec/aec_core.h
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * Specifies the interface for the AEC core.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
-#define MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-extern "C" {
-#include "common_audio/ring_buffer.h"
-}
-#include "modules/audio_processing/aec/aec_common.h"
-#include "modules/audio_processing/utility/block_mean_calculator.h"
-#include "modules/audio_processing/utility/ooura_fft.h"
-#include "rtc_base/constructor_magic.h"
-
-namespace webrtc {
-
-#define FRAME_LEN 80
-#define PART_LEN 64 // Length of partition
-#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients
-#define PART_LEN2 (PART_LEN * 2) // Length of partition * 2
-#define NUM_HIGH_BANDS_MAX 2 // Max number of high bands
-
-class ApmDataDumper;
-
-typedef float complex_t[2];
-// For performance reasons, some arrays of complex numbers are replaced by twice
-// as long arrays of float, all the real parts followed by all the imaginary
-// ones (complex_t[SIZE] -> float[2][SIZE]). This allows SIMD optimizations and
-// is better than two arrays (one for the real parts and one for the imaginary
-// parts) as this other way would require two pointers instead of one and cause
-// extra register spilling. This also allows the offsets to be calculated at
-// compile time.
-
-// Metrics
-enum { kOffsetLevel = -100 };
-
-typedef struct Stats {
- float instant;
- float average;
- float min;
- float max;
- float sum;
- float hisum;
- float himean;
- size_t counter;
- size_t hicounter;
-} Stats;
-
-// Number of partitions for the extended filter mode. The first one is an enum
-// to be used in array declarations, as it represents the maximum filter length.
-enum { kExtendedNumPartitions = 32 };
-static const int kNormalNumPartitions = 12;
-
-// Delay estimator constants, used for logging and delay compensation if
-// if reported delays are disabled.
-enum { kLookaheadBlocks = 15 };
-enum {
- // 500 ms for 16 kHz which is equivalent with the limit of reported delays.
- kHistorySizeBlocks = 125
-};
-
-typedef struct PowerLevel {
- PowerLevel();
-
- BlockMeanCalculator framelevel;
- BlockMeanCalculator averagelevel;
- float minlevel;
-} PowerLevel;
-
-class Aec2BlockBuffer {
- public:
- Aec2BlockBuffer();
- ~Aec2BlockBuffer();
- void ReInit();
- void Insert(const float block[PART_LEN]);
- void ExtractExtendedBlock(float extended_block[PART_LEN]);
- int AdjustSize(int buffer_size_decrease);
- size_t Size();
- size_t AvaliableSpace();
-
- private:
- RingBuffer* buffer_;
-};
-
-class DivergentFilterFraction {
- public:
- DivergentFilterFraction();
-
- // Reset.
- void Reset();
-
- void AddObservation(const PowerLevel& nearlevel,
- const PowerLevel& linoutlevel,
- const PowerLevel& nlpoutlevel);
-
- // Return the latest fraction.
- float GetLatestFraction() const;
-
- private:
- // Clear all values added.
- void Clear();
-
- size_t count_;
- size_t occurrence_;
- float fraction_;
-
- RTC_DISALLOW_COPY_AND_ASSIGN(DivergentFilterFraction);
-};
-
-typedef struct CoherenceState {
- complex_t sde[PART_LEN1]; // cross-psd of nearend and error
- complex_t sxd[PART_LEN1]; // cross-psd of farend and nearend
- float sx[PART_LEN1], sd[PART_LEN1], se[PART_LEN1]; // far, near, error psd
-} CoherenceState;
-
-struct AecCore {
- explicit AecCore(int instance_index);
- ~AecCore();
-
- std::unique_ptr<ApmDataDumper> data_dumper;
- const OouraFft ooura_fft;
-
- CoherenceState coherence_state;
-
- int farBufWritePos, farBufReadPos;
-
- int knownDelay;
- int inSamples, outSamples;
- int delayEstCtr;
-
- // Nearend buffer used for changing from FRAME_LEN to PART_LEN sample block
- // sizes. The buffer stores all the incoming bands and for each band a maximum
- // of PART_LEN - (FRAME_LEN - PART_LEN) values need to be buffered in order to
- // change the block size from FRAME_LEN to PART_LEN.
- float nearend_buffer[NUM_HIGH_BANDS_MAX + 1]
- [PART_LEN - (FRAME_LEN - PART_LEN)];
- size_t nearend_buffer_size;
- float output_buffer[NUM_HIGH_BANDS_MAX + 1][2 * PART_LEN];
- size_t output_buffer_size;
-
- float eBuf[PART_LEN2]; // error
-
- float previous_nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN];
-
- float xPow[PART_LEN1];
- float dPow[PART_LEN1];
- float dMinPow[PART_LEN1];
- float dInitMinPow[PART_LEN1];
- float* noisePow;
-
- float xfBuf[2][kExtendedNumPartitions * PART_LEN1]; // farend fft buffer
- float wfBuf[2][kExtendedNumPartitions * PART_LEN1]; // filter fft
- // Farend windowed fft buffer.
- complex_t xfwBuf[kExtendedNumPartitions * PART_LEN1];
-
- float hNs[PART_LEN1];
- float hNlFbMin, hNlFbLocalMin;
- float hNlXdAvgMin;
- int hNlNewMin, hNlMinCtr;
- float overDrive;
- float overdrive_scaling;
- int nlp_mode;
- float outBuf[PART_LEN];
- int delayIdx;
-
- short stNearState, echoState;
- short divergeState;
-
- int xfBufBlockPos;
-
- Aec2BlockBuffer farend_block_buffer_;
-
- int system_delay; // Current system delay buffered in AEC.
-
- int mult; // sampling frequency multiple
- int sampFreq = 16000;
- size_t num_bands;
- uint32_t seed;
-
- float filter_step_size; // stepsize
- float error_threshold; // error threshold
-
- int noiseEstCtr;
-
- PowerLevel farlevel;
- PowerLevel nearlevel;
- PowerLevel linoutlevel;
- PowerLevel nlpoutlevel;
-
- int metricsMode;
- int stateCounter;
- Stats erl;
- Stats erle;
- Stats aNlp;
- Stats rerl;
- DivergentFilterFraction divergent_filter_fraction;
-
- // Quantities to control H band scaling for SWB input
- int freq_avg_ic; // initial bin for averaging nlp gain
- int flag_Hband_cn; // for comfort noise
- float cn_scale_Hband; // scale for comfort noise in H band
-
- int delay_metrics_delivered;
- int delay_histogram[kHistorySizeBlocks];
- int num_delay_values;
- int delay_median;
- int delay_std;
- float fraction_poor_delays;
- int delay_logging_enabled;
- void* delay_estimator_farend;
- void* delay_estimator;
- // Variables associated with delay correction through signal based delay
- // estimation feedback.
- int previous_delay;
- int delay_correction_count;
- int shift_offset;
- float delay_quality_threshold;
- int frame_count;
-
- // 0 = delay agnostic mode (signal based delay correction) disabled.
- // Otherwise enabled.
- int delay_agnostic_enabled;
- // 1 = extended filter mode enabled, 0 = disabled.
- int extended_filter_enabled;
- // 1 = refined filter adaptation aec mode enabled, 0 = disabled.
- bool refined_adaptive_filter_enabled;
-
- // Runtime selection of number of filter partitions.
- int num_partitions;
-
- // Flag that extreme filter divergence has been detected by the Echo
- // Suppressor.
- int extreme_filter_divergence;
-};
-
-AecCore* WebRtcAec_CreateAec(int instance_count); // Returns NULL on error.
-void WebRtcAec_FreeAec(AecCore* aec);
-int WebRtcAec_InitAec(AecCore* aec, int sampFreq);
-void WebRtcAec_InitAec_SSE2(void);
-#if defined(MIPS_FPU_LE)
-void WebRtcAec_InitAec_mips(void);
-#endif
-#if defined(WEBRTC_HAS_NEON)
-void WebRtcAec_InitAec_neon(void);
-#endif
-
-void WebRtcAec_BufferFarendBlock(AecCore* aec, const float* farend);
-void WebRtcAec_ProcessFrames(AecCore* aec,
- const float* const* nearend,
- size_t num_bands,
- size_t num_samples,
- int knownDelay,
- float* const* out);
-
-// A helper function to call adjust the farend buffer size.
-// Returns the number of elements the size was decreased with, and adjusts
-// |system_delay| by the corresponding amount in ms.
-int WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(AecCore* aec,
- int size_decrease);
-
-// Calculates the median, standard deviation and amount of poor values among the
-// delay estimates aggregated up to the first call to the function. After that
-// first call the metrics are aggregated and updated every second. With poor
-// values we mean values that most likely will cause the AEC to perform poorly.
-// TODO(bjornv): Consider changing tests and tools to handle constant
-// constant aggregation window throughout the session instead.
-int WebRtcAec_GetDelayMetricsCore(AecCore* self,
- int* median,
- int* std,
- float* fraction_poor_delays);
-
-// Returns the echo state (1: echo, 0: no echo).
-int WebRtcAec_echo_state(AecCore* self);
-
-// Gets statistics of the echo metrics ERL, ERLE, A_NLP.
-void WebRtcAec_GetEchoStats(AecCore* self,
- Stats* erl,
- Stats* erle,
- Stats* a_nlp,
- float* divergent_filter_fraction);
-
-// Sets local configuration modes.
-void WebRtcAec_SetConfigCore(AecCore* self,
- int nlp_mode,
- int metrics_mode,
- int delay_logging);
-
-// Non-zero enables, zero disables.
-void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable);
-
-// Returns non-zero if delay agnostic (i.e., signal based delay estimation) is
-// enabled and zero if disabled.
-int WebRtcAec_delay_agnostic_enabled(AecCore* self);
-
-// Turns on/off the refined adaptive filter feature.
-void WebRtcAec_enable_refined_adaptive_filter(AecCore* self, bool enable);
-
-// Returns whether the refined adaptive filter is enabled.
-bool WebRtcAec_refined_adaptive_filter(const AecCore* self);
-
-// Enables or disables extended filter mode. Non-zero enables, zero disables.
-void WebRtcAec_enable_extended_filter(AecCore* self, int enable);
-
-// Returns non-zero if extended filter mode is enabled and zero if disabled.
-int WebRtcAec_extended_filter_enabled(AecCore* self);
-
-// Returns the current |system_delay|, i.e., the buffered difference between
-// far-end and near-end.
-int WebRtcAec_system_delay(AecCore* self);
-
-// Sets the |system_delay| to |value|. Note that if the value is changed
-// improperly, there can be a performance regression. So it should be used with
-// care.
-void WebRtcAec_SetSystemDelay(AecCore* self, int delay);
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
diff --git a/modules/audio_processing/aec/aec_core_mips.cc b/modules/audio_processing/aec/aec_core_mips.cc
deleted file mode 100644
index 2b388a7..0000000
--- a/modules/audio_processing/aec/aec_core_mips.cc
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * The core AEC algorithm, which is presented with time-aligned signals.
- */
-
-#include <math.h>
-
-#include "modules/audio_processing/aec/aec_core.h"
-
-extern "C" {
-#include "common_audio/signal_processing/include/signal_processing_library.h"
-}
-#include "modules/audio_processing/aec/aec_core_optimized_methods.h"
-#include "modules/audio_processing/utility/ooura_fft.h"
-
-namespace webrtc {
-
-extern const float WebRtcAec_weightCurve[65];
-extern const float WebRtcAec_overDriveCurve[65];
-
-void WebRtcAec_FilterFar_mips(
- int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float y_fft[2][PART_LEN1]) {
- int i;
- for (i = 0; i < num_partitions; i++) {
- int xPos = (i + x_fft_buf_block_pos) * PART_LEN1;
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + x_fft_buf_block_pos >= num_partitions) {
- xPos -= num_partitions * (PART_LEN1);
- }
- float* yf0 = y_fft[0];
- float* yf1 = y_fft[1];
- float* aRe = x_fft_buf[0] + xPos;
- float* aIm = x_fft_buf[1] + xPos;
- float* bRe = h_fft_buf[0] + pos;
- float* bIm = h_fft_buf[1] + pos;
- float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13;
- int len = PART_LEN1 >> 1;
-
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "1: \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[bRe]) \n\t"
- "lwc1 %[f2], 0(%[bIm]) \n\t"
- "lwc1 %[f3], 0(%[aIm]) \n\t"
- "lwc1 %[f4], 4(%[aRe]) \n\t"
- "lwc1 %[f5], 4(%[bRe]) \n\t"
- "lwc1 %[f6], 4(%[bIm]) \n\t"
- "mul.s %[f8], %[f0], %[f1] \n\t"
- "mul.s %[f0], %[f0], %[f2] \n\t"
- "mul.s %[f9], %[f4], %[f5] \n\t"
- "mul.s %[f4], %[f4], %[f6] \n\t"
- "lwc1 %[f7], 4(%[aIm]) \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f12], %[f2], %[f3] \n\t"
- "mul.s %[f1], %[f3], %[f1] \n\t"
- "mul.s %[f11], %[f6], %[f7] \n\t"
- "addiu %[aRe], %[aRe], 8 \n\t"
- "addiu %[aIm], %[aIm], 8 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "sub.s %[f8], %[f8], %[f12] \n\t"
- "mul.s %[f12], %[f7], %[f5] \n\t"
- "lwc1 %[f2], 0(%[yf0]) \n\t"
- "add.s %[f1], %[f0], %[f1] \n\t"
- "lwc1 %[f3], 0(%[yf1]) \n\t"
- "sub.s %[f9], %[f9], %[f11] \n\t"
- "lwc1 %[f6], 4(%[yf0]) \n\t"
- "add.s %[f4], %[f4], %[f12] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "addiu %[aRe], %[aRe], 8 \n\t"
- "addiu %[aIm], %[aIm], 8 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "nmsub.s %[f8], %[f8], %[f2], %[f3] \n\t"
- "lwc1 %[f2], 0(%[yf0]) \n\t"
- "madd.s %[f1], %[f0], %[f3], %[f1] \n\t"
- "lwc1 %[f3], 0(%[yf1]) \n\t"
- "nmsub.s %[f9], %[f9], %[f6], %[f7] \n\t"
- "lwc1 %[f6], 4(%[yf0]) \n\t"
- "madd.s %[f4], %[f4], %[f7], %[f5] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "lwc1 %[f5], 4(%[yf1]) \n\t"
- "add.s %[f2], %[f2], %[f8] \n\t"
- "addiu %[bRe], %[bRe], 8 \n\t"
- "addiu %[bIm], %[bIm], 8 \n\t"
- "add.s %[f3], %[f3], %[f1] \n\t"
- "add.s %[f6], %[f6], %[f9] \n\t"
- "add.s %[f5], %[f5], %[f4] \n\t"
- "swc1 %[f2], 0(%[yf0]) \n\t"
- "swc1 %[f3], 0(%[yf1]) \n\t"
- "swc1 %[f6], 4(%[yf0]) \n\t"
- "swc1 %[f5], 4(%[yf1]) \n\t"
- "addiu %[yf0], %[yf0], 8 \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[yf1], %[yf1], 8 \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[bRe]) \n\t"
- "lwc1 %[f2], 0(%[bIm]) \n\t"
- "lwc1 %[f3], 0(%[aIm]) \n\t"
- "mul.s %[f8], %[f0], %[f1] \n\t"
- "mul.s %[f0], %[f0], %[f2] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f12], %[f2], %[f3] \n\t"
- "mul.s %[f1], %[f3], %[f1] \n\t"
- "sub.s %[f8], %[f8], %[f12] \n\t"
- "lwc1 %[f2], 0(%[yf0]) \n\t"
- "add.s %[f1], %[f0], %[f1] \n\t"
- "lwc1 %[f3], 0(%[yf1]) \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "nmsub.s %[f8], %[f8], %[f2], %[f3] \n\t"
- "lwc1 %[f2], 0(%[yf0]) \n\t"
- "madd.s %[f1], %[f0], %[f3], %[f1] \n\t"
- "lwc1 %[f3], 0(%[yf1]) \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "add.s %[f2], %[f2], %[f8] \n\t"
- "add.s %[f3], %[f3], %[f1] \n\t"
- "swc1 %[f2], 0(%[yf0]) \n\t"
- "swc1 %[f3], 0(%[yf1]) \n\t"
- ".set pop \n\t"
- : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
- [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
- [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11),
- [f12] "=&f"(f12), [f13] "=&f"(f13), [aRe] "+r"(aRe), [aIm] "+r"(aIm),
- [bRe] "+r"(bRe), [bIm] "+r"(bIm), [yf0] "+r"(yf0), [yf1] "+r"(yf1),
- [len] "+r"(len)
- :
- : "memory");
- }
-}
-
-void WebRtcAec_FilterAdaptation_mips(
- const OouraFft& ooura_fft,
- int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float e_fft[2][PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
- float fft[PART_LEN2];
- int i;
- for (i = 0; i < num_partitions; i++) {
- int xPos = (i + x_fft_buf_block_pos) * (PART_LEN1);
- int pos;
- // Check for wrap
- if (i + x_fft_buf_block_pos >= num_partitions) {
- xPos -= num_partitions * PART_LEN1;
- }
-
- pos = i * PART_LEN1;
- float* aRe = x_fft_buf[0] + xPos;
- float* aIm = x_fft_buf[1] + xPos;
- float* bRe = e_fft[0];
- float* bIm = e_fft[1];
- float* fft_tmp;
-
- float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12;
- int len = PART_LEN >> 1;
-
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[fft_tmp], %[fft], 0 \n\t"
- "1: \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[bRe]) \n\t"
- "lwc1 %[f2], 0(%[bIm]) \n\t"
- "lwc1 %[f4], 4(%[aRe]) \n\t"
- "lwc1 %[f5], 4(%[bRe]) \n\t"
- "lwc1 %[f6], 4(%[bIm]) \n\t"
- "addiu %[aRe], %[aRe], 8 \n\t"
- "addiu %[bRe], %[bRe], 8 \n\t"
- "mul.s %[f8], %[f0], %[f1] \n\t"
- "mul.s %[f0], %[f0], %[f2] \n\t"
- "lwc1 %[f3], 0(%[aIm]) \n\t"
- "mul.s %[f9], %[f4], %[f5] \n\t"
- "lwc1 %[f7], 4(%[aIm]) \n\t"
- "mul.s %[f4], %[f4], %[f6] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f10], %[f3], %[f2] \n\t"
- "mul.s %[f1], %[f3], %[f1] \n\t"
- "mul.s %[f11], %[f7], %[f6] \n\t"
- "mul.s %[f5], %[f7], %[f5] \n\t"
- "addiu %[aIm], %[aIm], 8 \n\t"
- "addiu %[bIm], %[bIm], 8 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "add.s %[f8], %[f8], %[f10] \n\t"
- "sub.s %[f1], %[f0], %[f1] \n\t"
- "add.s %[f9], %[f9], %[f11] \n\t"
- "sub.s %[f5], %[f4], %[f5] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "addiu %[aIm], %[aIm], 8 \n\t"
- "addiu %[bIm], %[bIm], 8 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "madd.s %[f8], %[f8], %[f3], %[f2] \n\t"
- "nmsub.s %[f1], %[f0], %[f3], %[f1] \n\t"
- "madd.s %[f9], %[f9], %[f7], %[f6] \n\t"
- "nmsub.s %[f5], %[f4], %[f7], %[f5] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "swc1 %[f8], 0(%[fft_tmp]) \n\t"
- "swc1 %[f1], 4(%[fft_tmp]) \n\t"
- "swc1 %[f9], 8(%[fft_tmp]) \n\t"
- "swc1 %[f5], 12(%[fft_tmp]) \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[fft_tmp], %[fft_tmp], 16 \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[bRe]) \n\t"
- "lwc1 %[f2], 0(%[bIm]) \n\t"
- "lwc1 %[f3], 0(%[aIm]) \n\t"
- "mul.s %[f8], %[f0], %[f1] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f10], %[f3], %[f2] \n\t"
- "add.s %[f8], %[f8], %[f10] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "madd.s %[f8], %[f8], %[f3], %[f2] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "swc1 %[f8], 4(%[fft]) \n\t"
- ".set pop \n\t"
- : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
- [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
- [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11),
- [f12] "=&f"(f12), [aRe] "+r"(aRe), [aIm] "+r"(aIm), [bRe] "+r"(bRe),
- [bIm] "+r"(bIm), [fft_tmp] "=&r"(fft_tmp), [len] "+r"(len)
- : [fft] "r"(fft)
- : "memory");
-
- ooura_fft.InverseFft(fft);
- memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
-
- // fft scaling
- {
- float scale = 2.0f / PART_LEN2;
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[fft_tmp], %[fft], 0 \n\t"
- "addiu %[len], $zero, 8 \n\t"
- "1: \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "lwc1 %[f0], 0(%[fft_tmp]) \n\t"
- "lwc1 %[f1], 4(%[fft_tmp]) \n\t"
- "lwc1 %[f2], 8(%[fft_tmp]) \n\t"
- "lwc1 %[f3], 12(%[fft_tmp]) \n\t"
- "mul.s %[f0], %[f0], %[scale] \n\t"
- "mul.s %[f1], %[f1], %[scale] \n\t"
- "mul.s %[f2], %[f2], %[scale] \n\t"
- "mul.s %[f3], %[f3], %[scale] \n\t"
- "lwc1 %[f4], 16(%[fft_tmp]) \n\t"
- "lwc1 %[f5], 20(%[fft_tmp]) \n\t"
- "lwc1 %[f6], 24(%[fft_tmp]) \n\t"
- "lwc1 %[f7], 28(%[fft_tmp]) \n\t"
- "mul.s %[f4], %[f4], %[scale] \n\t"
- "mul.s %[f5], %[f5], %[scale] \n\t"
- "mul.s %[f6], %[f6], %[scale] \n\t"
- "mul.s %[f7], %[f7], %[scale] \n\t"
- "swc1 %[f0], 0(%[fft_tmp]) \n\t"
- "swc1 %[f1], 4(%[fft_tmp]) \n\t"
- "swc1 %[f2], 8(%[fft_tmp]) \n\t"
- "swc1 %[f3], 12(%[fft_tmp]) \n\t"
- "swc1 %[f4], 16(%[fft_tmp]) \n\t"
- "swc1 %[f5], 20(%[fft_tmp]) \n\t"
- "swc1 %[f6], 24(%[fft_tmp]) \n\t"
- "swc1 %[f7], 28(%[fft_tmp]) \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[fft_tmp], %[fft_tmp], 32 \n\t"
- ".set pop \n\t"
- : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
- [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
- [len] "=&r"(len), [fft_tmp] "=&r"(fft_tmp)
- : [scale] "f"(scale), [fft] "r"(fft)
- : "memory");
- }
- ooura_fft.Fft(fft);
- aRe = h_fft_buf[0] + pos;
- aIm = h_fft_buf[1] + pos;
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[fft_tmp], %[fft], 0 \n\t"
- "addiu %[len], $zero, 31 \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[fft_tmp]) \n\t"
- "lwc1 %[f2], 256(%[aRe]) \n\t"
- "lwc1 %[f3], 4(%[fft_tmp]) \n\t"
- "lwc1 %[f4], 4(%[aRe]) \n\t"
- "lwc1 %[f5], 8(%[fft_tmp]) \n\t"
- "lwc1 %[f6], 4(%[aIm]) \n\t"
- "lwc1 %[f7], 12(%[fft_tmp]) \n\t"
- "add.s %[f0], %[f0], %[f1] \n\t"
- "add.s %[f2], %[f2], %[f3] \n\t"
- "add.s %[f4], %[f4], %[f5] \n\t"
- "add.s %[f6], %[f6], %[f7] \n\t"
- "addiu %[fft_tmp], %[fft_tmp], 16 \n\t"
- "swc1 %[f0], 0(%[aRe]) \n\t"
- "swc1 %[f2], 256(%[aRe]) \n\t"
- "swc1 %[f4], 4(%[aRe]) \n\t"
- "addiu %[aRe], %[aRe], 8 \n\t"
- "swc1 %[f6], 4(%[aIm]) \n\t"
- "addiu %[aIm], %[aIm], 8 \n\t"
- "1: \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[fft_tmp]) \n\t"
- "lwc1 %[f2], 0(%[aIm]) \n\t"
- "lwc1 %[f3], 4(%[fft_tmp]) \n\t"
- "lwc1 %[f4], 4(%[aRe]) \n\t"
- "lwc1 %[f5], 8(%[fft_tmp]) \n\t"
- "lwc1 %[f6], 4(%[aIm]) \n\t"
- "lwc1 %[f7], 12(%[fft_tmp]) \n\t"
- "add.s %[f0], %[f0], %[f1] \n\t"
- "add.s %[f2], %[f2], %[f3] \n\t"
- "add.s %[f4], %[f4], %[f5] \n\t"
- "add.s %[f6], %[f6], %[f7] \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "addiu %[fft_tmp], %[fft_tmp], 16 \n\t"
- "swc1 %[f0], 0(%[aRe]) \n\t"
- "swc1 %[f2], 0(%[aIm]) \n\t"
- "swc1 %[f4], 4(%[aRe]) \n\t"
- "addiu %[aRe], %[aRe], 8 \n\t"
- "swc1 %[f6], 4(%[aIm]) \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[aIm], %[aIm], 8 \n\t"
- ".set pop \n\t"
- : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
- [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
- [len] "=&r"(len), [fft_tmp] "=&r"(fft_tmp), [aRe] "+r"(aRe),
- [aIm] "+r"(aIm)
- : [fft] "r"(fft)
- : "memory");
- }
-}
-
-void WebRtcAec_Overdrive_mips(float overdrive_scaling,
- float hNlFb,
- float hNl[PART_LEN1]) {
- const float one = 1.0;
- float* p_hNl;
- const float* p_WebRtcAec_wC;
- float temp1, temp2, temp3, temp4;
-
- p_hNl = &hNl[0];
- p_WebRtcAec_wC = &WebRtcAec_weightCurve[0];
-
- for (int i = 0; i < PART_LEN1; ++i) {
- // Weight subbands
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "lwc1 %[temp1], 0(%[p_hNl]) \n\t"
- "lwc1 %[temp2], 0(%[p_wC]) \n\t"
- "c.lt.s %[hNlFb], %[temp1] \n\t"
- "bc1f 1f \n\t"
- " mul.s %[temp3], %[temp2], %[hNlFb] \n\t"
- "sub.s %[temp4], %[one], %[temp2] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[temp1], %[temp1], %[temp4] \n\t"
- "add.s %[temp1], %[temp3], %[temp1] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "madd.s %[temp1], %[temp3], %[temp1], %[temp4] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "swc1 %[temp1], 0(%[p_hNl]) \n\t"
- "1: \n\t"
- "addiu %[p_wC], %[p_wC], 4 \n\t"
- ".set pop \n\t"
- : [temp1] "=&f"(temp1), [temp2] "=&f"(temp2), [temp3] "=&f"(temp3),
- [temp4] "=&f"(temp4), [p_wC] "+r"(p_WebRtcAec_wC)
- : [hNlFb] "f"(hNlFb), [one] "f"(one), [p_hNl] "r"(p_hNl)
- : "memory");
-
- hNl[i] = powf(hNl[i], overdrive_scaling * WebRtcAec_overDriveCurve[i]);
- }
-}
-
-void WebRtcAec_Suppress_mips(const float hNl[PART_LEN1],
- float efw[2][PART_LEN1]) {
- const float* p_hNl;
- float* p_efw0;
- float* p_efw1;
- float temp1, temp2, temp3, temp4;
-
- p_hNl = &hNl[0];
- p_efw0 = &efw[0][0];
- p_efw1 = &efw[1][0];
-
- for (int i = 0; i < PART_LEN1; ++i) {
- __asm __volatile(
- "lwc1 %[temp1], 0(%[p_hNl]) \n\t"
- "lwc1 %[temp3], 0(%[p_efw1]) \n\t"
- "lwc1 %[temp2], 0(%[p_efw0]) \n\t"
- "addiu %[p_hNl], %[p_hNl], 4 \n\t"
- "mul.s %[temp3], %[temp3], %[temp1] \n\t"
- "mul.s %[temp2], %[temp2], %[temp1] \n\t"
- "addiu %[p_efw0], %[p_efw0], 4 \n\t"
- "addiu %[p_efw1], %[p_efw1], 4 \n\t"
- "neg.s %[temp4], %[temp3] \n\t"
- "swc1 %[temp2], -4(%[p_efw0]) \n\t"
- "swc1 %[temp4], -4(%[p_efw1]) \n\t"
- : [temp1] "=&f"(temp1), [temp2] "=&f"(temp2), [temp3] "=&f"(temp3),
- [temp4] "=&f"(temp4), [p_efw0] "+r"(p_efw0), [p_efw1] "+r"(p_efw1),
- [p_hNl] "+r"(p_hNl)
- :
- : "memory");
- }
-}
-
-void WebRtcAec_ScaleErrorSignal_mips(float mu,
- float error_threshold,
- float x_pow[PART_LEN1],
- float ef[2][PART_LEN1]) {
- int len = (PART_LEN1);
- float* ef0 = ef[0];
- float* ef1 = ef[1];
- float fac1 = 1e-10f;
- float err_th2 = error_threshold * error_threshold;
- float f0, f1, f2;
-#if !defined(MIPS32_R2_LE)
- float f3;
-#endif
-
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "1: \n\t"
- "lwc1 %[f0], 0(%[x_pow]) \n\t"
- "lwc1 %[f1], 0(%[ef0]) \n\t"
- "lwc1 %[f2], 0(%[ef1]) \n\t"
- "add.s %[f0], %[f0], %[fac1] \n\t"
- "div.s %[f1], %[f1], %[f0] \n\t"
- "div.s %[f2], %[f2], %[f0] \n\t"
- "mul.s %[f0], %[f1], %[f1] \n\t"
-#if defined(MIPS32_R2_LE)
- "madd.s %[f0], %[f0], %[f2], %[f2] \n\t"
-#else
- "mul.s %[f3], %[f2], %[f2] \n\t"
- "add.s %[f0], %[f0], %[f3] \n\t"
-#endif
- "c.le.s %[f0], %[err_th2] \n\t"
- "nop \n\t"
- "bc1t 2f \n\t"
- " nop \n\t"
- "sqrt.s %[f0], %[f0] \n\t"
- "add.s %[f0], %[f0], %[fac1] \n\t"
- "div.s %[f0], %[err_th], %[f0] \n\t"
- "mul.s %[f1], %[f1], %[f0] \n\t"
- "mul.s %[f2], %[f2], %[f0] \n\t"
- "2: \n\t"
- "mul.s %[f1], %[f1], %[mu] \n\t"
- "mul.s %[f2], %[f2], %[mu] \n\t"
- "swc1 %[f1], 0(%[ef0]) \n\t"
- "swc1 %[f2], 0(%[ef1]) \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "addiu %[x_pow], %[x_pow], 4 \n\t"
- "addiu %[ef0], %[ef0], 4 \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[ef1], %[ef1], 4 \n\t"
- ".set pop \n\t"
- : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2),
-#if !defined(MIPS32_R2_LE)
- [f3] "=&f"(f3),
-#endif
- [x_pow] "+r"(x_pow), [ef0] "+r"(ef0), [ef1] "+r"(ef1), [len] "+r"(len)
- : [fac1] "f"(fac1), [err_th2] "f"(err_th2), [mu] "f"(mu),
- [err_th] "f"(error_threshold)
- : "memory");
-}
-
-void WebRtcAec_InitAec_mips(void) {
- WebRtcAec_FilterFar = WebRtcAec_FilterFar_mips;
- WebRtcAec_FilterAdaptation = WebRtcAec_FilterAdaptation_mips;
- WebRtcAec_ScaleErrorSignal = WebRtcAec_ScaleErrorSignal_mips;
- WebRtcAec_Overdrive = WebRtcAec_Overdrive_mips;
- WebRtcAec_Suppress = WebRtcAec_Suppress_mips;
-}
-} // namespace webrtc
diff --git a/modules/audio_processing/aec/aec_core_neon.cc b/modules/audio_processing/aec/aec_core_neon.cc
deleted file mode 100644
index 072bd17..0000000
--- a/modules/audio_processing/aec/aec_core_neon.cc
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * The core AEC algorithm, neon version of speed-critical functions.
- *
- * Based on aec_core_sse2.c.
- */
-
-#include <arm_neon.h>
-#include <math.h>
-#include <string.h> // memset
-
-extern "C" {
-#include "common_audio/signal_processing/include/signal_processing_library.h"
-}
-#include "modules/audio_processing/aec/aec_common.h"
-#include "modules/audio_processing/aec/aec_core_optimized_methods.h"
-#include "modules/audio_processing/utility/ooura_fft.h"
-
-namespace webrtc {
-
-enum { kShiftExponentIntoTopMantissa = 8 };
-enum { kFloatExponentShift = 23 };
-
-__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bRe - aIm * bIm;
-}
-
-__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bIm + aIm * bRe;
-}
-
-static void FilterFarNEON(
- int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float y_fft[2][PART_LEN1]) {
- int i;
- for (i = 0; i < num_partitions; i++) {
- int j;
- int xPos = (i + x_fft_buf_block_pos) * PART_LEN1;
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + x_fft_buf_block_pos >= num_partitions) {
- xPos -= num_partitions * PART_LEN1;
- }
-
- // vectorized code (four at once)
- for (j = 0; j + 3 < PART_LEN1; j += 4) {
- const float32x4_t x_fft_buf_re = vld1q_f32(&x_fft_buf[0][xPos + j]);
- const float32x4_t x_fft_buf_im = vld1q_f32(&x_fft_buf[1][xPos + j]);
- const float32x4_t h_fft_buf_re = vld1q_f32(&h_fft_buf[0][pos + j]);
- const float32x4_t h_fft_buf_im = vld1q_f32(&h_fft_buf[1][pos + j]);
- const float32x4_t y_fft_re = vld1q_f32(&y_fft[0][j]);
- const float32x4_t y_fft_im = vld1q_f32(&y_fft[1][j]);
- const float32x4_t a = vmulq_f32(x_fft_buf_re, h_fft_buf_re);
- const float32x4_t e = vmlsq_f32(a, x_fft_buf_im, h_fft_buf_im);
- const float32x4_t c = vmulq_f32(x_fft_buf_re, h_fft_buf_im);
- const float32x4_t f = vmlaq_f32(c, x_fft_buf_im, h_fft_buf_re);
- const float32x4_t g = vaddq_f32(y_fft_re, e);
- const float32x4_t h = vaddq_f32(y_fft_im, f);
- vst1q_f32(&y_fft[0][j], g);
- vst1q_f32(&y_fft[1][j], h);
- }
- // scalar code for the remaining items.
- for (; j < PART_LEN1; j++) {
- y_fft[0][j] += MulRe(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
- h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
- y_fft[1][j] += MulIm(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
- h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
- }
- }
-}
-
-// ARM64's arm_neon.h has already defined vdivq_f32 vsqrtq_f32.
-#if !defined(WEBRTC_ARCH_ARM64)
-static float32x4_t vdivq_f32(float32x4_t a, float32x4_t b) {
- int i;
- float32x4_t x = vrecpeq_f32(b);
- // from arm documentation
- // The Newton-Raphson iteration:
- // x[n+1] = x[n] * (2 - d * x[n])
- // converges to (1/d) if x0 is the result of VRECPE applied to d.
- //
- // Note: The precision did not improve after 2 iterations.
- for (i = 0; i < 2; i++) {
- x = vmulq_f32(vrecpsq_f32(b, x), x);
- }
- // a/b = a*(1/b)
- return vmulq_f32(a, x);
-}
-
-static float32x4_t vsqrtq_f32(float32x4_t s) {
- int i;
- float32x4_t x = vrsqrteq_f32(s);
-
- // Code to handle sqrt(0).
- // If the input to sqrtf() is zero, a zero will be returned.
- // If the input to vrsqrteq_f32() is zero, positive infinity is returned.
- const uint32x4_t vec_p_inf = vdupq_n_u32(0x7F800000);
- // check for divide by zero
- const uint32x4_t div_by_zero = vceqq_u32(vec_p_inf, vreinterpretq_u32_f32(x));
- // zero out the positive infinity results
- x = vreinterpretq_f32_u32(
- vandq_u32(vmvnq_u32(div_by_zero), vreinterpretq_u32_f32(x)));
- // from arm documentation
- // The Newton-Raphson iteration:
- // x[n+1] = x[n] * (3 - d * (x[n] * x[n])) / 2)
- // converges to (1/√d) if x0 is the result of VRSQRTE applied to d.
- //
- // Note: The precision did not improve after 2 iterations.
- for (i = 0; i < 2; i++) {
- x = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x, x), s), x);
- }
- // sqrt(s) = s * 1/sqrt(s)
- return vmulq_f32(s, x);
-}
-#endif // WEBRTC_ARCH_ARM64
-
-static void ScaleErrorSignalNEON(float mu,
- float error_threshold,
- float x_pow[PART_LEN1],
- float ef[2][PART_LEN1]) {
- const float32x4_t k1e_10f = vdupq_n_f32(1e-10f);
- const float32x4_t kMu = vmovq_n_f32(mu);
- const float32x4_t kThresh = vmovq_n_f32(error_threshold);
- int i;
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const float32x4_t x_pow_local = vld1q_f32(&x_pow[i]);
- const float32x4_t ef_re_base = vld1q_f32(&ef[0][i]);
- const float32x4_t ef_im_base = vld1q_f32(&ef[1][i]);
- const float32x4_t xPowPlus = vaddq_f32(x_pow_local, k1e_10f);
- float32x4_t ef_re = vdivq_f32(ef_re_base, xPowPlus);
- float32x4_t ef_im = vdivq_f32(ef_im_base, xPowPlus);
- const float32x4_t ef_re2 = vmulq_f32(ef_re, ef_re);
- const float32x4_t ef_sum2 = vmlaq_f32(ef_re2, ef_im, ef_im);
- const float32x4_t absEf = vsqrtq_f32(ef_sum2);
- const uint32x4_t bigger = vcgtq_f32(absEf, kThresh);
- const float32x4_t absEfPlus = vaddq_f32(absEf, k1e_10f);
- const float32x4_t absEfInv = vdivq_f32(kThresh, absEfPlus);
- uint32x4_t ef_re_if = vreinterpretq_u32_f32(vmulq_f32(ef_re, absEfInv));
- uint32x4_t ef_im_if = vreinterpretq_u32_f32(vmulq_f32(ef_im, absEfInv));
- uint32x4_t ef_re_u32 =
- vandq_u32(vmvnq_u32(bigger), vreinterpretq_u32_f32(ef_re));
- uint32x4_t ef_im_u32 =
- vandq_u32(vmvnq_u32(bigger), vreinterpretq_u32_f32(ef_im));
- ef_re_if = vandq_u32(bigger, ef_re_if);
- ef_im_if = vandq_u32(bigger, ef_im_if);
- ef_re_u32 = vorrq_u32(ef_re_u32, ef_re_if);
- ef_im_u32 = vorrq_u32(ef_im_u32, ef_im_if);
- ef_re = vmulq_f32(vreinterpretq_f32_u32(ef_re_u32), kMu);
- ef_im = vmulq_f32(vreinterpretq_f32_u32(ef_im_u32), kMu);
- vst1q_f32(&ef[0][i], ef_re);
- vst1q_f32(&ef[1][i], ef_im);
- }
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- float abs_ef;
- ef[0][i] /= (x_pow[i] + 1e-10f);
- ef[1][i] /= (x_pow[i] + 1e-10f);
- abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
-
- if (abs_ef > error_threshold) {
- abs_ef = error_threshold / (abs_ef + 1e-10f);
- ef[0][i] *= abs_ef;
- ef[1][i] *= abs_ef;
- }
-
- // Stepsize factor
- ef[0][i] *= mu;
- ef[1][i] *= mu;
- }
-}
-
-static void FilterAdaptationNEON(
- const OouraFft& ooura_fft,
- int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float e_fft[2][PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
- float fft[PART_LEN2];
- int i;
- for (i = 0; i < num_partitions; i++) {
- int xPos = (i + x_fft_buf_block_pos) * PART_LEN1;
- int pos = i * PART_LEN1;
- int j;
- // Check for wrap
- if (i + x_fft_buf_block_pos >= num_partitions) {
- xPos -= num_partitions * PART_LEN1;
- }
-
- // Process the whole array...
- for (j = 0; j < PART_LEN; j += 4) {
- // Load x_fft_buf and e_fft.
- const float32x4_t x_fft_buf_re = vld1q_f32(&x_fft_buf[0][xPos + j]);
- const float32x4_t x_fft_buf_im = vld1q_f32(&x_fft_buf[1][xPos + j]);
- const float32x4_t e_fft_re = vld1q_f32(&e_fft[0][j]);
- const float32x4_t e_fft_im = vld1q_f32(&e_fft[1][j]);
- // Calculate the product of conjugate(x_fft_buf) by e_fft.
- // re(conjugate(a) * b) = aRe * bRe + aIm * bIm
- // im(conjugate(a) * b)= aRe * bIm - aIm * bRe
- const float32x4_t a = vmulq_f32(x_fft_buf_re, e_fft_re);
- const float32x4_t e = vmlaq_f32(a, x_fft_buf_im, e_fft_im);
- const float32x4_t c = vmulq_f32(x_fft_buf_re, e_fft_im);
- const float32x4_t f = vmlsq_f32(c, x_fft_buf_im, e_fft_re);
- // Interleave real and imaginary parts.
- const float32x4x2_t g_n_h = vzipq_f32(e, f);
- // Store
- vst1q_f32(&fft[2 * j + 0], g_n_h.val[0]);
- vst1q_f32(&fft[2 * j + 4], g_n_h.val[1]);
- }
- // ... and fixup the first imaginary entry.
- fft[1] =
- MulRe(x_fft_buf[0][xPos + PART_LEN], -x_fft_buf[1][xPos + PART_LEN],
- e_fft[0][PART_LEN], e_fft[1][PART_LEN]);
-
- ooura_fft.InverseFft(fft);
- memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
-
- // fft scaling
- {
- const float scale = 2.0f / PART_LEN2;
- const float32x4_t scale_ps = vmovq_n_f32(scale);
- for (j = 0; j < PART_LEN; j += 4) {
- const float32x4_t fft_ps = vld1q_f32(&fft[j]);
- const float32x4_t fft_scale = vmulq_f32(fft_ps, scale_ps);
- vst1q_f32(&fft[j], fft_scale);
- }
- }
- ooura_fft.Fft(fft);
-
- {
- const float wt1 = h_fft_buf[1][pos];
- h_fft_buf[0][pos + PART_LEN] += fft[1];
- for (j = 0; j < PART_LEN; j += 4) {
- float32x4_t wtBuf_re = vld1q_f32(&h_fft_buf[0][pos + j]);
- float32x4_t wtBuf_im = vld1q_f32(&h_fft_buf[1][pos + j]);
- const float32x4_t fft0 = vld1q_f32(&fft[2 * j + 0]);
- const float32x4_t fft4 = vld1q_f32(&fft[2 * j + 4]);
- const float32x4x2_t fft_re_im = vuzpq_f32(fft0, fft4);
- wtBuf_re = vaddq_f32(wtBuf_re, fft_re_im.val[0]);
- wtBuf_im = vaddq_f32(wtBuf_im, fft_re_im.val[1]);
-
- vst1q_f32(&h_fft_buf[0][pos + j], wtBuf_re);
- vst1q_f32(&h_fft_buf[1][pos + j], wtBuf_im);
- }
- h_fft_buf[1][pos] = wt1;
- }
- }
-}
-
-static float32x4_t vpowq_f32(float32x4_t a, float32x4_t b) {
- // a^b = exp2(b * log2(a))
- // exp2(x) and log2(x) are calculated using polynomial approximations.
- float32x4_t log2_a, b_log2_a, a_exp_b;
-
- // Calculate log2(x), x = a.
- {
- // To calculate log2(x), we decompose x like this:
- // x = y * 2^n
- // n is an integer
- // y is in the [1.0, 2.0) range
- //
- // log2(x) = log2(y) + n
- // n can be evaluated by playing with float representation.
- // log2(y) in a small range can be approximated, this code uses an order
- // five polynomial approximation. The coefficients have been
- // estimated with the Remez algorithm and the resulting
- // polynomial has a maximum relative error of 0.00086%.
-
- // Compute n.
- // This is done by masking the exponent, shifting it into the top bit of
- // the mantissa, putting eight into the biased exponent (to shift/
- // compensate the fact that the exponent has been shifted in the top/
- // fractional part and finally getting rid of the implicit leading one
- // from the mantissa by substracting it out.
- const uint32x4_t vec_float_exponent_mask = vdupq_n_u32(0x7F800000);
- const uint32x4_t vec_eight_biased_exponent = vdupq_n_u32(0x43800000);
- const uint32x4_t vec_implicit_leading_one = vdupq_n_u32(0x43BF8000);
- const uint32x4_t two_n =
- vandq_u32(vreinterpretq_u32_f32(a), vec_float_exponent_mask);
- const uint32x4_t n_1 = vshrq_n_u32(two_n, kShiftExponentIntoTopMantissa);
- const uint32x4_t n_0 = vorrq_u32(n_1, vec_eight_biased_exponent);
- const float32x4_t n =
- vsubq_f32(vreinterpretq_f32_u32(n_0),
- vreinterpretq_f32_u32(vec_implicit_leading_one));
- // Compute y.
- const uint32x4_t vec_mantissa_mask = vdupq_n_u32(0x007FFFFF);
- const uint32x4_t vec_zero_biased_exponent_is_one = vdupq_n_u32(0x3F800000);
- const uint32x4_t mantissa =
- vandq_u32(vreinterpretq_u32_f32(a), vec_mantissa_mask);
- const float32x4_t y = vreinterpretq_f32_u32(
- vorrq_u32(mantissa, vec_zero_biased_exponent_is_one));
- // Approximate log2(y) ~= (y - 1) * pol5(y).
- // pol5(y) = C5 * y^5 + C4 * y^4 + C3 * y^3 + C2 * y^2 + C1 * y + C0
- const float32x4_t C5 = vdupq_n_f32(-3.4436006e-2f);
- const float32x4_t C4 = vdupq_n_f32(3.1821337e-1f);
- const float32x4_t C3 = vdupq_n_f32(-1.2315303f);
- const float32x4_t C2 = vdupq_n_f32(2.5988452f);
- const float32x4_t C1 = vdupq_n_f32(-3.3241990f);
- const float32x4_t C0 = vdupq_n_f32(3.1157899f);
- float32x4_t pol5_y = C5;
- pol5_y = vmlaq_f32(C4, y, pol5_y);
- pol5_y = vmlaq_f32(C3, y, pol5_y);
- pol5_y = vmlaq_f32(C2, y, pol5_y);
- pol5_y = vmlaq_f32(C1, y, pol5_y);
- pol5_y = vmlaq_f32(C0, y, pol5_y);
- const float32x4_t y_minus_one =
- vsubq_f32(y, vreinterpretq_f32_u32(vec_zero_biased_exponent_is_one));
- const float32x4_t log2_y = vmulq_f32(y_minus_one, pol5_y);
-
- // Combine parts.
- log2_a = vaddq_f32(n, log2_y);
- }
-
- // b * log2(a)
- b_log2_a = vmulq_f32(b, log2_a);
-
- // Calculate exp2(x), x = b * log2(a).
- {
- // To calculate 2^x, we decompose x like this:
- // x = n + y
- // n is an integer, the value of x - 0.5 rounded down, therefore
- // y is in the [0.5, 1.5) range
- //
- // 2^x = 2^n * 2^y
- // 2^n can be evaluated by playing with float representation.
- // 2^y in a small range can be approximated, this code uses an order two
- // polynomial approximation. The coefficients have been estimated
- // with the Remez algorithm and the resulting polynomial has a
- // maximum relative error of 0.17%.
- // To avoid over/underflow, we reduce the range of input to ]-127, 129].
- const float32x4_t max_input = vdupq_n_f32(129.f);
- const float32x4_t min_input = vdupq_n_f32(-126.99999f);
- const float32x4_t x_min = vminq_f32(b_log2_a, max_input);
- const float32x4_t x_max = vmaxq_f32(x_min, min_input);
- // Compute n.
- const float32x4_t half = vdupq_n_f32(0.5f);
- const float32x4_t x_minus_half = vsubq_f32(x_max, half);
- const int32x4_t x_minus_half_floor = vcvtq_s32_f32(x_minus_half);
-
- // Compute 2^n.
- const int32x4_t float_exponent_bias = vdupq_n_s32(127);
- const int32x4_t two_n_exponent =
- vaddq_s32(x_minus_half_floor, float_exponent_bias);
- const float32x4_t two_n =
- vreinterpretq_f32_s32(vshlq_n_s32(two_n_exponent, kFloatExponentShift));
- // Compute y.
- const float32x4_t y = vsubq_f32(x_max, vcvtq_f32_s32(x_minus_half_floor));
-
- // Approximate 2^y ~= C2 * y^2 + C1 * y + C0.
- const float32x4_t C2 = vdupq_n_f32(3.3718944e-1f);
- const float32x4_t C1 = vdupq_n_f32(6.5763628e-1f);
- const float32x4_t C0 = vdupq_n_f32(1.0017247f);
- float32x4_t exp2_y = C2;
- exp2_y = vmlaq_f32(C1, y, exp2_y);
- exp2_y = vmlaq_f32(C0, y, exp2_y);
-
- // Combine parts.
- a_exp_b = vmulq_f32(exp2_y, two_n);
- }
-
- return a_exp_b;
-}
-
-static void OverdriveNEON(float overdrive_scaling,
- float hNlFb,
- float hNl[PART_LEN1]) {
- int i;
- const float32x4_t vec_hNlFb = vmovq_n_f32(hNlFb);
- const float32x4_t vec_one = vdupq_n_f32(1.0f);
- const float32x4_t vec_overdrive_scaling = vmovq_n_f32(overdrive_scaling);
-
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- // Weight subbands
- float32x4_t vec_hNl = vld1q_f32(&hNl[i]);
- const float32x4_t vec_weightCurve = vld1q_f32(&WebRtcAec_weightCurve[i]);
- const uint32x4_t bigger = vcgtq_f32(vec_hNl, vec_hNlFb);
- const float32x4_t vec_weightCurve_hNlFb =
- vmulq_f32(vec_weightCurve, vec_hNlFb);
- const float32x4_t vec_one_weightCurve = vsubq_f32(vec_one, vec_weightCurve);
- const float32x4_t vec_one_weightCurve_hNl =
- vmulq_f32(vec_one_weightCurve, vec_hNl);
- const uint32x4_t vec_if0 =
- vandq_u32(vmvnq_u32(bigger), vreinterpretq_u32_f32(vec_hNl));
- const float32x4_t vec_one_weightCurve_add =
- vaddq_f32(vec_weightCurve_hNlFb, vec_one_weightCurve_hNl);
- const uint32x4_t vec_if1 =
- vandq_u32(bigger, vreinterpretq_u32_f32(vec_one_weightCurve_add));
-
- vec_hNl = vreinterpretq_f32_u32(vorrq_u32(vec_if0, vec_if1));
-
- const float32x4_t vec_overDriveCurve =
- vld1q_f32(&WebRtcAec_overDriveCurve[i]);
- const float32x4_t vec_overDriveSm_overDriveCurve =
- vmulq_f32(vec_overdrive_scaling, vec_overDriveCurve);
- vec_hNl = vpowq_f32(vec_hNl, vec_overDriveSm_overDriveCurve);
- vst1q_f32(&hNl[i], vec_hNl);
- }
-
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- // Weight subbands
- if (hNl[i] > hNlFb) {
- hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
- (1 - WebRtcAec_weightCurve[i]) * hNl[i];
- }
-
- hNl[i] = powf(hNl[i], overdrive_scaling * WebRtcAec_overDriveCurve[i]);
- }
-}
-
-static void SuppressNEON(const float hNl[PART_LEN1], float efw[2][PART_LEN1]) {
- int i;
- const float32x4_t vec_minus_one = vdupq_n_f32(-1.0f);
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- float32x4_t vec_hNl = vld1q_f32(&hNl[i]);
- float32x4_t vec_efw_re = vld1q_f32(&efw[0][i]);
- float32x4_t vec_efw_im = vld1q_f32(&efw[1][i]);
- vec_efw_re = vmulq_f32(vec_efw_re, vec_hNl);
- vec_efw_im = vmulq_f32(vec_efw_im, vec_hNl);
-
- // Ooura fft returns incorrect sign on imaginary component. It matters
- // here because we are making an additive change with comfort noise.
- vec_efw_im = vmulq_f32(vec_efw_im, vec_minus_one);
- vst1q_f32(&efw[0][i], vec_efw_re);
- vst1q_f32(&efw[1][i], vec_efw_im);
- }
-
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- efw[0][i] *= hNl[i];
- efw[1][i] *= hNl[i];
-
- // Ooura fft returns incorrect sign on imaginary component. It matters
- // here because we are making an additive change with comfort noise.
- efw[1][i] *= -1;
- }
-}
-
-static int PartitionDelayNEON(
- int num_partitions,
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
- // Measures the energy in each filter partition and returns the partition with
- // highest energy.
- // TODO(bjornv): Spread computational cost by computing one partition per
- // block?
- float wfEnMax = 0;
- int i;
- int delay = 0;
-
- for (i = 0; i < num_partitions; i++) {
- int j;
- int pos = i * PART_LEN1;
- float wfEn = 0;
- float32x4_t vec_wfEn = vdupq_n_f32(0.0f);
- // vectorized code (four at once)
- for (j = 0; j + 3 < PART_LEN1; j += 4) {
- const float32x4_t vec_wfBuf0 = vld1q_f32(&h_fft_buf[0][pos + j]);
- const float32x4_t vec_wfBuf1 = vld1q_f32(&h_fft_buf[1][pos + j]);
- vec_wfEn = vmlaq_f32(vec_wfEn, vec_wfBuf0, vec_wfBuf0);
- vec_wfEn = vmlaq_f32(vec_wfEn, vec_wfBuf1, vec_wfBuf1);
- }
- {
- float32x2_t vec_total;
- // A B C D
- vec_total = vpadd_f32(vget_low_f32(vec_wfEn), vget_high_f32(vec_wfEn));
- // A+B C+D
- vec_total = vpadd_f32(vec_total, vec_total);
- // A+B+C+D A+B+C+D
- wfEn = vget_lane_f32(vec_total, 0);
- }
-
- // scalar code for the remaining items.
- for (; j < PART_LEN1; j++) {
- wfEn += h_fft_buf[0][pos + j] * h_fft_buf[0][pos + j] +
- h_fft_buf[1][pos + j] * h_fft_buf[1][pos + j];
- }
-
- if (wfEn > wfEnMax) {
- wfEnMax = wfEn;
- delay = i;
- }
- }
- return delay;
-}
-
-// Updates the following smoothed Power Spectral Densities (PSD):
-// - sd : near-end
-// - se : residual echo
-// - sx : far-end
-// - sde : cross-PSD of near-end and residual echo
-// - sxd : cross-PSD of near-end and far-end
-//
-// In addition to updating the PSDs, also the filter diverge state is determined
-// upon actions are taken.
-static void UpdateCoherenceSpectraNEON(int mult,
- bool extended_filter_enabled,
- float efw[2][PART_LEN1],
- float dfw[2][PART_LEN1],
- float xfw[2][PART_LEN1],
- CoherenceState* coherence_state,
- short* filter_divergence_state,
- int* extreme_filter_divergence) {
- // Power estimate smoothing coefficients.
- const float* ptrGCoh =
- extended_filter_enabled
- ? WebRtcAec_kExtendedSmoothingCoefficients[mult - 1]
- : WebRtcAec_kNormalSmoothingCoefficients[mult - 1];
- int i;
- float sdSum = 0, seSum = 0;
- const float32x4_t vec_15 = vdupq_n_f32(WebRtcAec_kMinFarendPSD);
- float32x4_t vec_sdSum = vdupq_n_f32(0.0f);
- float32x4_t vec_seSum = vdupq_n_f32(0.0f);
-
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const float32x4_t vec_dfw0 = vld1q_f32(&dfw[0][i]);
- const float32x4_t vec_dfw1 = vld1q_f32(&dfw[1][i]);
- const float32x4_t vec_efw0 = vld1q_f32(&efw[0][i]);
- const float32x4_t vec_efw1 = vld1q_f32(&efw[1][i]);
- const float32x4_t vec_xfw0 = vld1q_f32(&xfw[0][i]);
- const float32x4_t vec_xfw1 = vld1q_f32(&xfw[1][i]);
- float32x4_t vec_sd =
- vmulq_n_f32(vld1q_f32(&coherence_state->sd[i]), ptrGCoh[0]);
- float32x4_t vec_se =
- vmulq_n_f32(vld1q_f32(&coherence_state->se[i]), ptrGCoh[0]);
- float32x4_t vec_sx =
- vmulq_n_f32(vld1q_f32(&coherence_state->sx[i]), ptrGCoh[0]);
- float32x4_t vec_dfw_sumsq = vmulq_f32(vec_dfw0, vec_dfw0);
- float32x4_t vec_efw_sumsq = vmulq_f32(vec_efw0, vec_efw0);
- float32x4_t vec_xfw_sumsq = vmulq_f32(vec_xfw0, vec_xfw0);
-
- vec_dfw_sumsq = vmlaq_f32(vec_dfw_sumsq, vec_dfw1, vec_dfw1);
- vec_efw_sumsq = vmlaq_f32(vec_efw_sumsq, vec_efw1, vec_efw1);
- vec_xfw_sumsq = vmlaq_f32(vec_xfw_sumsq, vec_xfw1, vec_xfw1);
- vec_xfw_sumsq = vmaxq_f32(vec_xfw_sumsq, vec_15);
- vec_sd = vmlaq_n_f32(vec_sd, vec_dfw_sumsq, ptrGCoh[1]);
- vec_se = vmlaq_n_f32(vec_se, vec_efw_sumsq, ptrGCoh[1]);
- vec_sx = vmlaq_n_f32(vec_sx, vec_xfw_sumsq, ptrGCoh[1]);
-
- vst1q_f32(&coherence_state->sd[i], vec_sd);
- vst1q_f32(&coherence_state->se[i], vec_se);
- vst1q_f32(&coherence_state->sx[i], vec_sx);
-
- {
- float32x4x2_t vec_sde = vld2q_f32(&coherence_state->sde[i][0]);
- float32x4_t vec_dfwefw0011 = vmulq_f32(vec_dfw0, vec_efw0);
- float32x4_t vec_dfwefw0110 = vmulq_f32(vec_dfw0, vec_efw1);
- vec_sde.val[0] = vmulq_n_f32(vec_sde.val[0], ptrGCoh[0]);
- vec_sde.val[1] = vmulq_n_f32(vec_sde.val[1], ptrGCoh[0]);
- vec_dfwefw0011 = vmlaq_f32(vec_dfwefw0011, vec_dfw1, vec_efw1);
- vec_dfwefw0110 = vmlsq_f32(vec_dfwefw0110, vec_dfw1, vec_efw0);
- vec_sde.val[0] = vmlaq_n_f32(vec_sde.val[0], vec_dfwefw0011, ptrGCoh[1]);
- vec_sde.val[1] = vmlaq_n_f32(vec_sde.val[1], vec_dfwefw0110, ptrGCoh[1]);
- vst2q_f32(&coherence_state->sde[i][0], vec_sde);
- }
-
- {
- float32x4x2_t vec_sxd = vld2q_f32(&coherence_state->sxd[i][0]);
- float32x4_t vec_dfwxfw0011 = vmulq_f32(vec_dfw0, vec_xfw0);
- float32x4_t vec_dfwxfw0110 = vmulq_f32(vec_dfw0, vec_xfw1);
- vec_sxd.val[0] = vmulq_n_f32(vec_sxd.val[0], ptrGCoh[0]);
- vec_sxd.val[1] = vmulq_n_f32(vec_sxd.val[1], ptrGCoh[0]);
- vec_dfwxfw0011 = vmlaq_f32(vec_dfwxfw0011, vec_dfw1, vec_xfw1);
- vec_dfwxfw0110 = vmlsq_f32(vec_dfwxfw0110, vec_dfw1, vec_xfw0);
- vec_sxd.val[0] = vmlaq_n_f32(vec_sxd.val[0], vec_dfwxfw0011, ptrGCoh[1]);
- vec_sxd.val[1] = vmlaq_n_f32(vec_sxd.val[1], vec_dfwxfw0110, ptrGCoh[1]);
- vst2q_f32(&coherence_state->sxd[i][0], vec_sxd);
- }
-
- vec_sdSum = vaddq_f32(vec_sdSum, vec_sd);
- vec_seSum = vaddq_f32(vec_seSum, vec_se);
- }
- {
- float32x2_t vec_sdSum_total;
- float32x2_t vec_seSum_total;
- // A B C D
- vec_sdSum_total =
- vpadd_f32(vget_low_f32(vec_sdSum), vget_high_f32(vec_sdSum));
- vec_seSum_total =
- vpadd_f32(vget_low_f32(vec_seSum), vget_high_f32(vec_seSum));
- // A+B C+D
- vec_sdSum_total = vpadd_f32(vec_sdSum_total, vec_sdSum_total);
- vec_seSum_total = vpadd_f32(vec_seSum_total, vec_seSum_total);
- // A+B+C+D A+B+C+D
- sdSum = vget_lane_f32(vec_sdSum_total, 0);
- seSum = vget_lane_f32(vec_seSum_total, 0);
- }
-
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- coherence_state->sd[i] =
- ptrGCoh[0] * coherence_state->sd[i] +
- ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
- coherence_state->se[i] =
- ptrGCoh[0] * coherence_state->se[i] +
- ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
- // We threshold here to protect against the ill-effects of a zero farend.
- // The threshold is not arbitrarily chosen, but balances protection and
- // adverse interaction with the algorithm's tuning.
- // TODO(bjornv): investigate further why this is so sensitive.
- coherence_state->sx[i] =
- ptrGCoh[0] * coherence_state->sx[i] +
- ptrGCoh[1] *
- WEBRTC_SPL_MAX(xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
- WebRtcAec_kMinFarendPSD);
-
- coherence_state->sde[i][0] =
- ptrGCoh[0] * coherence_state->sde[i][0] +
- ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
- coherence_state->sde[i][1] =
- ptrGCoh[0] * coherence_state->sde[i][1] +
- ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
-
- coherence_state->sxd[i][0] =
- ptrGCoh[0] * coherence_state->sxd[i][0] +
- ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
- coherence_state->sxd[i][1] =
- ptrGCoh[0] * coherence_state->sxd[i][1] +
- ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
-
- sdSum += coherence_state->sd[i];
- seSum += coherence_state->se[i];
- }
-
- // Divergent filter safeguard update.
- *filter_divergence_state =
- (*filter_divergence_state ? 1.05f : 1.0f) * seSum > sdSum;
-
- // Signal extreme filter divergence if the error is significantly larger
- // than the nearend (13 dB).
- *extreme_filter_divergence = (seSum > (19.95f * sdSum));
-}
-
-// Window time domain data to be used by the fft.
-static void WindowDataNEON(float* x_windowed, const float* x) {
- int i;
- for (i = 0; i < PART_LEN; i += 4) {
- const float32x4_t vec_Buf1 = vld1q_f32(&x[i]);
- const float32x4_t vec_Buf2 = vld1q_f32(&x[PART_LEN + i]);
- const float32x4_t vec_sqrtHanning = vld1q_f32(&WebRtcAec_sqrtHanning[i]);
- // A B C D
- float32x4_t vec_sqrtHanning_rev =
- vld1q_f32(&WebRtcAec_sqrtHanning[PART_LEN - i - 3]);
- // B A D C
- vec_sqrtHanning_rev = vrev64q_f32(vec_sqrtHanning_rev);
- // D C B A
- vec_sqrtHanning_rev = vcombine_f32(vget_high_f32(vec_sqrtHanning_rev),
- vget_low_f32(vec_sqrtHanning_rev));
- vst1q_f32(&x_windowed[i], vmulq_f32(vec_Buf1, vec_sqrtHanning));
- vst1q_f32(&x_windowed[PART_LEN + i],
- vmulq_f32(vec_Buf2, vec_sqrtHanning_rev));
- }
-}
-
-// Puts fft output data into a complex valued array.
-static void StoreAsComplexNEON(const float* data,
- float data_complex[2][PART_LEN1]) {
- int i;
- for (i = 0; i < PART_LEN; i += 4) {
- const float32x4x2_t vec_data = vld2q_f32(&data[2 * i]);
- vst1q_f32(&data_complex[0][i], vec_data.val[0]);
- vst1q_f32(&data_complex[1][i], vec_data.val[1]);
- }
- // fix beginning/end values
- data_complex[1][0] = 0;
- data_complex[1][PART_LEN] = 0;
- data_complex[0][0] = data[0];
- data_complex[0][PART_LEN] = data[1];
-}
-
-static void ComputeCoherenceNEON(const CoherenceState* coherence_state,
- float* cohde,
- float* cohxd) {
- int i;
-
- {
- const float32x4_t vec_1eminus10 = vdupq_n_f32(1e-10f);
-
- // Subband coherence
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const float32x4_t vec_sd = vld1q_f32(&coherence_state->sd[i]);
- const float32x4_t vec_se = vld1q_f32(&coherence_state->se[i]);
- const float32x4_t vec_sx = vld1q_f32(&coherence_state->sx[i]);
- const float32x4_t vec_sdse = vmlaq_f32(vec_1eminus10, vec_sd, vec_se);
- const float32x4_t vec_sdsx = vmlaq_f32(vec_1eminus10, vec_sd, vec_sx);
- float32x4x2_t vec_sde = vld2q_f32(&coherence_state->sde[i][0]);
- float32x4x2_t vec_sxd = vld2q_f32(&coherence_state->sxd[i][0]);
- float32x4_t vec_cohde = vmulq_f32(vec_sde.val[0], vec_sde.val[0]);
- float32x4_t vec_cohxd = vmulq_f32(vec_sxd.val[0], vec_sxd.val[0]);
- vec_cohde = vmlaq_f32(vec_cohde, vec_sde.val[1], vec_sde.val[1]);
- vec_cohde = vdivq_f32(vec_cohde, vec_sdse);
- vec_cohxd = vmlaq_f32(vec_cohxd, vec_sxd.val[1], vec_sxd.val[1]);
- vec_cohxd = vdivq_f32(vec_cohxd, vec_sdsx);
-
- vst1q_f32(&cohde[i], vec_cohde);
- vst1q_f32(&cohxd[i], vec_cohxd);
- }
- }
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- cohde[i] = (coherence_state->sde[i][0] * coherence_state->sde[i][0] +
- coherence_state->sde[i][1] * coherence_state->sde[i][1]) /
- (coherence_state->sd[i] * coherence_state->se[i] + 1e-10f);
- cohxd[i] = (coherence_state->sxd[i][0] * coherence_state->sxd[i][0] +
- coherence_state->sxd[i][1] * coherence_state->sxd[i][1]) /
- (coherence_state->sx[i] * coherence_state->sd[i] + 1e-10f);
- }
-}
-
-void WebRtcAec_InitAec_neon(void) {
- WebRtcAec_FilterFar = FilterFarNEON;
- WebRtcAec_ScaleErrorSignal = ScaleErrorSignalNEON;
- WebRtcAec_FilterAdaptation = FilterAdaptationNEON;
- WebRtcAec_Overdrive = OverdriveNEON;
- WebRtcAec_Suppress = SuppressNEON;
- WebRtcAec_ComputeCoherence = ComputeCoherenceNEON;
- WebRtcAec_UpdateCoherenceSpectra = UpdateCoherenceSpectraNEON;
- WebRtcAec_StoreAsComplex = StoreAsComplexNEON;
- WebRtcAec_PartitionDelay = PartitionDelayNEON;
- WebRtcAec_WindowData = WindowDataNEON;
-}
-} // namespace webrtc
diff --git a/modules/audio_processing/aec/aec_core_optimized_methods.h b/modules/audio_processing/aec/aec_core_optimized_methods.h
deleted file mode 100644
index 03c027d..0000000
--- a/modules/audio_processing/aec/aec_core_optimized_methods.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_OPTIMIZED_METHODS_H_
-#define MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_OPTIMIZED_METHODS_H_
-
-#include <memory>
-
-#include "modules/audio_processing/aec/aec_core.h"
-
-namespace webrtc {
-
-typedef void (*WebRtcAecFilterFar)(
- int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float y_fft[2][PART_LEN1]);
-extern WebRtcAecFilterFar WebRtcAec_FilterFar;
-typedef void (*WebRtcAecScaleErrorSignal)(float mu,
- float error_threshold,
- float x_pow[PART_LEN1],
- float ef[2][PART_LEN1]);
-extern WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal;
-typedef void (*WebRtcAecFilterAdaptation)(
- const OouraFft& ooura_fft,
- int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float e_fft[2][PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]);
-extern WebRtcAecFilterAdaptation WebRtcAec_FilterAdaptation;
-
-typedef void (*WebRtcAecOverdrive)(float overdrive_scaling,
- const float hNlFb,
- float hNl[PART_LEN1]);
-extern WebRtcAecOverdrive WebRtcAec_Overdrive;
-
-typedef void (*WebRtcAecSuppress)(const float hNl[PART_LEN1],
- float efw[2][PART_LEN1]);
-extern WebRtcAecSuppress WebRtcAec_Suppress;
-
-typedef void (*WebRtcAecComputeCoherence)(const CoherenceState* coherence_state,
- float* cohde,
- float* cohxd);
-extern WebRtcAecComputeCoherence WebRtcAec_ComputeCoherence;
-
-typedef void (*WebRtcAecUpdateCoherenceSpectra)(int mult,
- bool extended_filter_enabled,
- float efw[2][PART_LEN1],
- float dfw[2][PART_LEN1],
- float xfw[2][PART_LEN1],
- CoherenceState* coherence_state,
- short* filter_divergence_state,
- int* extreme_filter_divergence);
-extern WebRtcAecUpdateCoherenceSpectra WebRtcAec_UpdateCoherenceSpectra;
-
-typedef int (*WebRtcAecPartitionDelay)(
- int num_partitions,
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]);
-extern WebRtcAecPartitionDelay WebRtcAec_PartitionDelay;
-
-typedef void (*WebRtcAecStoreAsComplex)(const float* data,
- float data_complex[2][PART_LEN1]);
-extern WebRtcAecStoreAsComplex WebRtcAec_StoreAsComplex;
-
-typedef void (*WebRtcAecWindowData)(float* x_windowed, const float* x);
-extern WebRtcAecWindowData WebRtcAec_WindowData;
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_OPTIMIZED_METHODS_H_
diff --git a/modules/audio_processing/aec/aec_core_sse2.cc b/modules/audio_processing/aec/aec_core_sse2.cc
deleted file mode 100644
index ede04dd..0000000
--- a/modules/audio_processing/aec/aec_core_sse2.cc
+++ /dev/null
@@ -1,749 +0,0 @@
-/*
- * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * The core AEC algorithm, SSE2 version of speed-critical functions.
- */
-
-#include <emmintrin.h>
-#include <math.h>
-#include <string.h> // memset
-
-extern "C" {
-#include "common_audio/signal_processing/include/signal_processing_library.h"
-}
-#include "modules/audio_processing/aec/aec_common.h"
-#include "modules/audio_processing/aec/aec_core_optimized_methods.h"
-#include "modules/audio_processing/utility/ooura_fft.h"
-
-namespace webrtc {
-
-__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bRe - aIm * bIm;
-}
-
-__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bIm + aIm * bRe;
-}
-
-static void FilterFarSSE2(
- int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float y_fft[2][PART_LEN1]) {
- int i;
- for (i = 0; i < num_partitions; i++) {
- int j;
- int xPos = (i + x_fft_buf_block_pos) * PART_LEN1;
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + x_fft_buf_block_pos >= num_partitions) {
- xPos -= num_partitions * (PART_LEN1);
- }
-
- // vectorized code (four at once)
- for (j = 0; j + 3 < PART_LEN1; j += 4) {
- const __m128 x_fft_buf_re = _mm_loadu_ps(&x_fft_buf[0][xPos + j]);
- const __m128 x_fft_buf_im = _mm_loadu_ps(&x_fft_buf[1][xPos + j]);
- const __m128 h_fft_buf_re = _mm_loadu_ps(&h_fft_buf[0][pos + j]);
- const __m128 h_fft_buf_im = _mm_loadu_ps(&h_fft_buf[1][pos + j]);
- const __m128 y_fft_re = _mm_loadu_ps(&y_fft[0][j]);
- const __m128 y_fft_im = _mm_loadu_ps(&y_fft[1][j]);
- const __m128 a = _mm_mul_ps(x_fft_buf_re, h_fft_buf_re);
- const __m128 b = _mm_mul_ps(x_fft_buf_im, h_fft_buf_im);
- const __m128 c = _mm_mul_ps(x_fft_buf_re, h_fft_buf_im);
- const __m128 d = _mm_mul_ps(x_fft_buf_im, h_fft_buf_re);
- const __m128 e = _mm_sub_ps(a, b);
- const __m128 f = _mm_add_ps(c, d);
- const __m128 g = _mm_add_ps(y_fft_re, e);
- const __m128 h = _mm_add_ps(y_fft_im, f);
- _mm_storeu_ps(&y_fft[0][j], g);
- _mm_storeu_ps(&y_fft[1][j], h);
- }
- // scalar code for the remaining items.
- for (; j < PART_LEN1; j++) {
- y_fft[0][j] += MulRe(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
- h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
- y_fft[1][j] += MulIm(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
- h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
- }
- }
-}
-
-static void ScaleErrorSignalSSE2(float mu,
- float error_threshold,
- float x_pow[PART_LEN1],
- float ef[2][PART_LEN1]) {
- const __m128 k1e_10f = _mm_set1_ps(1e-10f);
- const __m128 kMu = _mm_set1_ps(mu);
- const __m128 kThresh = _mm_set1_ps(error_threshold);
-
- int i;
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const __m128 x_pow_local = _mm_loadu_ps(&x_pow[i]);
- const __m128 ef_re_base = _mm_loadu_ps(&ef[0][i]);
- const __m128 ef_im_base = _mm_loadu_ps(&ef[1][i]);
-
- const __m128 xPowPlus = _mm_add_ps(x_pow_local, k1e_10f);
- __m128 ef_re = _mm_div_ps(ef_re_base, xPowPlus);
- __m128 ef_im = _mm_div_ps(ef_im_base, xPowPlus);
- const __m128 ef_re2 = _mm_mul_ps(ef_re, ef_re);
- const __m128 ef_im2 = _mm_mul_ps(ef_im, ef_im);
- const __m128 ef_sum2 = _mm_add_ps(ef_re2, ef_im2);
- const __m128 absEf = _mm_sqrt_ps(ef_sum2);
- const __m128 bigger = _mm_cmpgt_ps(absEf, kThresh);
- __m128 absEfPlus = _mm_add_ps(absEf, k1e_10f);
- const __m128 absEfInv = _mm_div_ps(kThresh, absEfPlus);
- __m128 ef_re_if = _mm_mul_ps(ef_re, absEfInv);
- __m128 ef_im_if = _mm_mul_ps(ef_im, absEfInv);
- ef_re_if = _mm_and_ps(bigger, ef_re_if);
- ef_im_if = _mm_and_ps(bigger, ef_im_if);
- ef_re = _mm_andnot_ps(bigger, ef_re);
- ef_im = _mm_andnot_ps(bigger, ef_im);
- ef_re = _mm_or_ps(ef_re, ef_re_if);
- ef_im = _mm_or_ps(ef_im, ef_im_if);
- ef_re = _mm_mul_ps(ef_re, kMu);
- ef_im = _mm_mul_ps(ef_im, kMu);
-
- _mm_storeu_ps(&ef[0][i], ef_re);
- _mm_storeu_ps(&ef[1][i], ef_im);
- }
- // scalar code for the remaining items.
- {
- for (; i < (PART_LEN1); i++) {
- float abs_ef;
- ef[0][i] /= (x_pow[i] + 1e-10f);
- ef[1][i] /= (x_pow[i] + 1e-10f);
- abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
-
- if (abs_ef > error_threshold) {
- abs_ef = error_threshold / (abs_ef + 1e-10f);
- ef[0][i] *= abs_ef;
- ef[1][i] *= abs_ef;
- }
-
- // Stepsize factor
- ef[0][i] *= mu;
- ef[1][i] *= mu;
- }
- }
-}
-
-static void FilterAdaptationSSE2(
- const OouraFft& ooura_fft,
- int num_partitions,
- int x_fft_buf_block_pos,
- float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
- float e_fft[2][PART_LEN1],
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
- float fft[PART_LEN2];
- int i, j;
- for (i = 0; i < num_partitions; i++) {
- int xPos = (i + x_fft_buf_block_pos) * (PART_LEN1);
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + x_fft_buf_block_pos >= num_partitions) {
- xPos -= num_partitions * PART_LEN1;
- }
-
- // Process the whole array...
- for (j = 0; j < PART_LEN; j += 4) {
- // Load x_fft_buf and e_fft.
- const __m128 x_fft_buf_re = _mm_loadu_ps(&x_fft_buf[0][xPos + j]);
- const __m128 x_fft_buf_im = _mm_loadu_ps(&x_fft_buf[1][xPos + j]);
- const __m128 e_fft_re = _mm_loadu_ps(&e_fft[0][j]);
- const __m128 e_fft_im = _mm_loadu_ps(&e_fft[1][j]);
- // Calculate the product of conjugate(x_fft_buf) by e_fft.
- // re(conjugate(a) * b) = aRe * bRe + aIm * bIm
- // im(conjugate(a) * b)= aRe * bIm - aIm * bRe
- const __m128 a = _mm_mul_ps(x_fft_buf_re, e_fft_re);
- const __m128 b = _mm_mul_ps(x_fft_buf_im, e_fft_im);
- const __m128 c = _mm_mul_ps(x_fft_buf_re, e_fft_im);
- const __m128 d = _mm_mul_ps(x_fft_buf_im, e_fft_re);
- const __m128 e = _mm_add_ps(a, b);
- const __m128 f = _mm_sub_ps(c, d);
- // Interleave real and imaginary parts.
- const __m128 g = _mm_unpacklo_ps(e, f);
- const __m128 h = _mm_unpackhi_ps(e, f);
- // Store
- _mm_storeu_ps(&fft[2 * j + 0], g);
- _mm_storeu_ps(&fft[2 * j + 4], h);
- }
- // ... and fixup the first imaginary entry.
- fft[1] =
- MulRe(x_fft_buf[0][xPos + PART_LEN], -x_fft_buf[1][xPos + PART_LEN],
- e_fft[0][PART_LEN], e_fft[1][PART_LEN]);
-
- ooura_fft.InverseFft(fft);
- memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
-
- // fft scaling
- {
- float scale = 2.0f / PART_LEN2;
- const __m128 scale_ps = _mm_load_ps1(&scale);
- for (j = 0; j < PART_LEN; j += 4) {
- const __m128 fft_ps = _mm_loadu_ps(&fft[j]);
- const __m128 fft_scale = _mm_mul_ps(fft_ps, scale_ps);
- _mm_storeu_ps(&fft[j], fft_scale);
- }
- }
- ooura_fft.Fft(fft);
-
- {
- float wt1 = h_fft_buf[1][pos];
- h_fft_buf[0][pos + PART_LEN] += fft[1];
- for (j = 0; j < PART_LEN; j += 4) {
- __m128 wtBuf_re = _mm_loadu_ps(&h_fft_buf[0][pos + j]);
- __m128 wtBuf_im = _mm_loadu_ps(&h_fft_buf[1][pos + j]);
- const __m128 fft0 = _mm_loadu_ps(&fft[2 * j + 0]);
- const __m128 fft4 = _mm_loadu_ps(&fft[2 * j + 4]);
- const __m128 fft_re =
- _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(2, 0, 2, 0));
- const __m128 fft_im =
- _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(3, 1, 3, 1));
- wtBuf_re = _mm_add_ps(wtBuf_re, fft_re);
- wtBuf_im = _mm_add_ps(wtBuf_im, fft_im);
- _mm_storeu_ps(&h_fft_buf[0][pos + j], wtBuf_re);
- _mm_storeu_ps(&h_fft_buf[1][pos + j], wtBuf_im);
- }
- h_fft_buf[1][pos] = wt1;
- }
- }
-}
-
-static __m128 mm_pow_ps(__m128 a, __m128 b) {
- // a^b = exp2(b * log2(a))
- // exp2(x) and log2(x) are calculated using polynomial approximations.
- __m128 log2_a, b_log2_a, a_exp_b;
-
- // Calculate log2(x), x = a.
- {
- // To calculate log2(x), we decompose x like this:
- // x = y * 2^n
- // n is an integer
- // y is in the [1.0, 2.0) range
- //
- // log2(x) = log2(y) + n
- // n can be evaluated by playing with float representation.
- // log2(y) in a small range can be approximated, this code uses an order
- // five polynomial approximation. The coefficients have been
- // estimated with the Remez algorithm and the resulting
- // polynomial has a maximum relative error of 0.00086%.
-
- // Compute n.
- // This is done by masking the exponent, shifting it into the top bit of
- // the mantissa, putting eight into the biased exponent (to shift/
- // compensate the fact that the exponent has been shifted in the top/
- // fractional part and finally getting rid of the implicit leading one
- // from the mantissa by substracting it out.
- static const ALIGN16_BEG int float_exponent_mask[4] ALIGN16_END = {
- 0x7F800000, 0x7F800000, 0x7F800000, 0x7F800000};
- static const ALIGN16_BEG int eight_biased_exponent[4] ALIGN16_END = {
- 0x43800000, 0x43800000, 0x43800000, 0x43800000};
- static const ALIGN16_BEG int implicit_leading_one[4] ALIGN16_END = {
- 0x43BF8000, 0x43BF8000, 0x43BF8000, 0x43BF8000};
- static const int shift_exponent_into_top_mantissa = 8;
- const __m128 two_n =
- _mm_and_ps(a, *(reinterpret_cast<const __m128*>(float_exponent_mask)));
- const __m128 n_1 = _mm_castsi128_ps(_mm_srli_epi32(
- _mm_castps_si128(two_n), shift_exponent_into_top_mantissa));
- const __m128 n_0 = _mm_or_ps(
- n_1, *(reinterpret_cast<const __m128*>(eight_biased_exponent)));
- const __m128 n = _mm_sub_ps(
- n_0, *(reinterpret_cast<const __m128*>(implicit_leading_one)));
-
- // Compute y.
- static const ALIGN16_BEG int mantissa_mask[4] ALIGN16_END = {
- 0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF};
- static const ALIGN16_BEG int zero_biased_exponent_is_one[4] ALIGN16_END = {
- 0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000};
- const __m128 mantissa =
- _mm_and_ps(a, *(reinterpret_cast<const __m128*>(mantissa_mask)));
- const __m128 y = _mm_or_ps(
- mantissa,
- *(reinterpret_cast<const __m128*>(zero_biased_exponent_is_one)));
-
- // Approximate log2(y) ~= (y - 1) * pol5(y).
- // pol5(y) = C5 * y^5 + C4 * y^4 + C3 * y^3 + C2 * y^2 + C1 * y + C0
- static const ALIGN16_BEG float ALIGN16_END C5[4] = {
- -3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f};
- static const ALIGN16_BEG float ALIGN16_END C4[4] = {
- 3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f};
- static const ALIGN16_BEG float ALIGN16_END C3[4] = {
- -1.2315303f, -1.2315303f, -1.2315303f, -1.2315303f};
- static const ALIGN16_BEG float ALIGN16_END C2[4] = {2.5988452f, 2.5988452f,
- 2.5988452f, 2.5988452f};
- static const ALIGN16_BEG float ALIGN16_END C1[4] = {
- -3.3241990f, -3.3241990f, -3.3241990f, -3.3241990f};
- static const ALIGN16_BEG float ALIGN16_END C0[4] = {3.1157899f, 3.1157899f,
- 3.1157899f, 3.1157899f};
- const __m128 pol5_y_0 =
- _mm_mul_ps(y, *(reinterpret_cast<const __m128*>(C5)));
- const __m128 pol5_y_1 =
- _mm_add_ps(pol5_y_0, *(reinterpret_cast<const __m128*>(C4)));
- const __m128 pol5_y_2 = _mm_mul_ps(pol5_y_1, y);
- const __m128 pol5_y_3 =
- _mm_add_ps(pol5_y_2, *(reinterpret_cast<const __m128*>(C3)));
- const __m128 pol5_y_4 = _mm_mul_ps(pol5_y_3, y);
- const __m128 pol5_y_5 =
- _mm_add_ps(pol5_y_4, *(reinterpret_cast<const __m128*>(C2)));
- const __m128 pol5_y_6 = _mm_mul_ps(pol5_y_5, y);
- const __m128 pol5_y_7 =
- _mm_add_ps(pol5_y_6, *(reinterpret_cast<const __m128*>(C1)));
- const __m128 pol5_y_8 = _mm_mul_ps(pol5_y_7, y);
- const __m128 pol5_y =
- _mm_add_ps(pol5_y_8, *(reinterpret_cast<const __m128*>(C0)));
- const __m128 y_minus_one = _mm_sub_ps(
- y, *(reinterpret_cast<const __m128*>(zero_biased_exponent_is_one)));
- const __m128 log2_y = _mm_mul_ps(y_minus_one, pol5_y);
-
- // Combine parts.
- log2_a = _mm_add_ps(n, log2_y);
- }
-
- // b * log2(a)
- b_log2_a = _mm_mul_ps(b, log2_a);
-
- // Calculate exp2(x), x = b * log2(a).
- {
- // To calculate 2^x, we decompose x like this:
- // x = n + y
- // n is an integer, the value of x - 0.5 rounded down, therefore
- // y is in the [0.5, 1.5) range
- //
- // 2^x = 2^n * 2^y
- // 2^n can be evaluated by playing with float representation.
- // 2^y in a small range can be approximated, this code uses an order two
- // polynomial approximation. The coefficients have been estimated
- // with the Remez algorithm and the resulting polynomial has a
- // maximum relative error of 0.17%.
-
- // To avoid over/underflow, we reduce the range of input to ]-127, 129].
- static const ALIGN16_BEG float max_input[4] ALIGN16_END = {129.f, 129.f,
- 129.f, 129.f};
- static const ALIGN16_BEG float min_input[4] ALIGN16_END = {
- -126.99999f, -126.99999f, -126.99999f, -126.99999f};
- const __m128 x_min =
- _mm_min_ps(b_log2_a, *(reinterpret_cast<const __m128*>(max_input)));
- const __m128 x_max =
- _mm_max_ps(x_min, *(reinterpret_cast<const __m128*>(min_input)));
- // Compute n.
- static const ALIGN16_BEG float half[4] ALIGN16_END = {0.5f, 0.5f, 0.5f,
- 0.5f};
- const __m128 x_minus_half =
- _mm_sub_ps(x_max, *(reinterpret_cast<const __m128*>(half)));
- const __m128i x_minus_half_floor = _mm_cvtps_epi32(x_minus_half);
- // Compute 2^n.
- static const ALIGN16_BEG int float_exponent_bias[4] ALIGN16_END = {
- 127, 127, 127, 127};
- static const int float_exponent_shift = 23;
- const __m128i two_n_exponent =
- _mm_add_epi32(x_minus_half_floor,
- *(reinterpret_cast<const __m128i*>(float_exponent_bias)));
- const __m128 two_n =
- _mm_castsi128_ps(_mm_slli_epi32(two_n_exponent, float_exponent_shift));
- // Compute y.
- const __m128 y = _mm_sub_ps(x_max, _mm_cvtepi32_ps(x_minus_half_floor));
- // Approximate 2^y ~= C2 * y^2 + C1 * y + C0.
- static const ALIGN16_BEG float C2[4] ALIGN16_END = {
- 3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f};
- static const ALIGN16_BEG float C1[4] ALIGN16_END = {
- 6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f};
- static const ALIGN16_BEG float C0[4] ALIGN16_END = {1.0017247f, 1.0017247f,
- 1.0017247f, 1.0017247f};
- const __m128 exp2_y_0 =
- _mm_mul_ps(y, *(reinterpret_cast<const __m128*>(C2)));
- const __m128 exp2_y_1 =
- _mm_add_ps(exp2_y_0, *(reinterpret_cast<const __m128*>(C1)));
- const __m128 exp2_y_2 = _mm_mul_ps(exp2_y_1, y);
- const __m128 exp2_y =
- _mm_add_ps(exp2_y_2, *(reinterpret_cast<const __m128*>(C0)));
-
- // Combine parts.
- a_exp_b = _mm_mul_ps(exp2_y, two_n);
- }
- return a_exp_b;
-}
-
-static void OverdriveSSE2(float overdrive_scaling,
- float hNlFb,
- float hNl[PART_LEN1]) {
- int i;
- const __m128 vec_hNlFb = _mm_set1_ps(hNlFb);
- const __m128 vec_one = _mm_set1_ps(1.0f);
- const __m128 vec_overdrive_scaling = _mm_set1_ps(overdrive_scaling);
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- // Weight subbands
- __m128 vec_hNl = _mm_loadu_ps(&hNl[i]);
- const __m128 vec_weightCurve = _mm_loadu_ps(&WebRtcAec_weightCurve[i]);
- const __m128 bigger = _mm_cmpgt_ps(vec_hNl, vec_hNlFb);
- const __m128 vec_weightCurve_hNlFb = _mm_mul_ps(vec_weightCurve, vec_hNlFb);
- const __m128 vec_one_weightCurve = _mm_sub_ps(vec_one, vec_weightCurve);
- const __m128 vec_one_weightCurve_hNl =
- _mm_mul_ps(vec_one_weightCurve, vec_hNl);
- const __m128 vec_if0 = _mm_andnot_ps(bigger, vec_hNl);
- const __m128 vec_if1 = _mm_and_ps(
- bigger, _mm_add_ps(vec_weightCurve_hNlFb, vec_one_weightCurve_hNl));
- vec_hNl = _mm_or_ps(vec_if0, vec_if1);
-
- const __m128 vec_overDriveCurve =
- _mm_loadu_ps(&WebRtcAec_overDriveCurve[i]);
- const __m128 vec_overDriveSm_overDriveCurve =
- _mm_mul_ps(vec_overdrive_scaling, vec_overDriveCurve);
- vec_hNl = mm_pow_ps(vec_hNl, vec_overDriveSm_overDriveCurve);
- _mm_storeu_ps(&hNl[i], vec_hNl);
- }
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- // Weight subbands
- if (hNl[i] > hNlFb) {
- hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
- (1 - WebRtcAec_weightCurve[i]) * hNl[i];
- }
- hNl[i] = powf(hNl[i], overdrive_scaling * WebRtcAec_overDriveCurve[i]);
- }
-}
-
-static void SuppressSSE2(const float hNl[PART_LEN1], float efw[2][PART_LEN1]) {
- int i;
- const __m128 vec_minus_one = _mm_set1_ps(-1.0f);
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- // Suppress error signal
- __m128 vec_hNl = _mm_loadu_ps(&hNl[i]);
- __m128 vec_efw_re = _mm_loadu_ps(&efw[0][i]);
- __m128 vec_efw_im = _mm_loadu_ps(&efw[1][i]);
- vec_efw_re = _mm_mul_ps(vec_efw_re, vec_hNl);
- vec_efw_im = _mm_mul_ps(vec_efw_im, vec_hNl);
-
- // Ooura fft returns incorrect sign on imaginary component. It matters
- // here because we are making an additive change with comfort noise.
- vec_efw_im = _mm_mul_ps(vec_efw_im, vec_minus_one);
- _mm_storeu_ps(&efw[0][i], vec_efw_re);
- _mm_storeu_ps(&efw[1][i], vec_efw_im);
- }
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- // Suppress error signal
- efw[0][i] *= hNl[i];
- efw[1][i] *= hNl[i];
-
- // Ooura fft returns incorrect sign on imaginary component. It matters
- // here because we are making an additive change with comfort noise.
- efw[1][i] *= -1;
- }
-}
-
-__inline static void _mm_add_ps_4x1(__m128 sum, float* dst) {
- // A+B C+D
- sum = _mm_add_ps(sum, _mm_shuffle_ps(sum, sum, _MM_SHUFFLE(0, 0, 3, 2)));
- // A+B+C+D A+B+C+D
- sum = _mm_add_ps(sum, _mm_shuffle_ps(sum, sum, _MM_SHUFFLE(1, 1, 1, 1)));
- _mm_store_ss(dst, sum);
-}
-
-static int PartitionDelaySSE2(
- int num_partitions,
- float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
- // Measures the energy in each filter partition and returns the partition with
- // highest energy.
- // TODO(bjornv): Spread computational cost by computing one partition per
- // block?
- float wfEnMax = 0;
- int i;
- int delay = 0;
-
- for (i = 0; i < num_partitions; i++) {
- int j;
- int pos = i * PART_LEN1;
- float wfEn = 0;
- __m128 vec_wfEn = _mm_set1_ps(0.0f);
- // vectorized code (four at once)
- for (j = 0; j + 3 < PART_LEN1; j += 4) {
- const __m128 vec_wfBuf0 = _mm_loadu_ps(&h_fft_buf[0][pos + j]);
- const __m128 vec_wfBuf1 = _mm_loadu_ps(&h_fft_buf[1][pos + j]);
- vec_wfEn = _mm_add_ps(vec_wfEn, _mm_mul_ps(vec_wfBuf0, vec_wfBuf0));
- vec_wfEn = _mm_add_ps(vec_wfEn, _mm_mul_ps(vec_wfBuf1, vec_wfBuf1));
- }
- _mm_add_ps_4x1(vec_wfEn, &wfEn);
-
- // scalar code for the remaining items.
- for (; j < PART_LEN1; j++) {
- wfEn += h_fft_buf[0][pos + j] * h_fft_buf[0][pos + j] +
- h_fft_buf[1][pos + j] * h_fft_buf[1][pos + j];
- }
-
- if (wfEn > wfEnMax) {
- wfEnMax = wfEn;
- delay = i;
- }
- }
- return delay;
-}
-
-// Updates the following smoothed Power Spectral Densities (PSD):
-// - sd : near-end
-// - se : residual echo
-// - sx : far-end
-// - sde : cross-PSD of near-end and residual echo
-// - sxd : cross-PSD of near-end and far-end
-//
-// In addition to updating the PSDs, also the filter diverge state is determined
-// upon actions are taken.
-static void UpdateCoherenceSpectraSSE2(int mult,
- bool extended_filter_enabled,
- float efw[2][PART_LEN1],
- float dfw[2][PART_LEN1],
- float xfw[2][PART_LEN1],
- CoherenceState* coherence_state,
- short* filter_divergence_state,
- int* extreme_filter_divergence) {
- // Power estimate smoothing coefficients.
- const float* ptrGCoh =
- extended_filter_enabled
- ? WebRtcAec_kExtendedSmoothingCoefficients[mult - 1]
- : WebRtcAec_kNormalSmoothingCoefficients[mult - 1];
- int i;
- float sdSum = 0, seSum = 0;
- const __m128 vec_15 = _mm_set1_ps(WebRtcAec_kMinFarendPSD);
- const __m128 vec_GCoh0 = _mm_set1_ps(ptrGCoh[0]);
- const __m128 vec_GCoh1 = _mm_set1_ps(ptrGCoh[1]);
- __m128 vec_sdSum = _mm_set1_ps(0.0f);
- __m128 vec_seSum = _mm_set1_ps(0.0f);
-
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const __m128 vec_dfw0 = _mm_loadu_ps(&dfw[0][i]);
- const __m128 vec_dfw1 = _mm_loadu_ps(&dfw[1][i]);
- const __m128 vec_efw0 = _mm_loadu_ps(&efw[0][i]);
- const __m128 vec_efw1 = _mm_loadu_ps(&efw[1][i]);
- const __m128 vec_xfw0 = _mm_loadu_ps(&xfw[0][i]);
- const __m128 vec_xfw1 = _mm_loadu_ps(&xfw[1][i]);
- __m128 vec_sd =
- _mm_mul_ps(_mm_loadu_ps(&coherence_state->sd[i]), vec_GCoh0);
- __m128 vec_se =
- _mm_mul_ps(_mm_loadu_ps(&coherence_state->se[i]), vec_GCoh0);
- __m128 vec_sx =
- _mm_mul_ps(_mm_loadu_ps(&coherence_state->sx[i]), vec_GCoh0);
- __m128 vec_dfw_sumsq = _mm_mul_ps(vec_dfw0, vec_dfw0);
- __m128 vec_efw_sumsq = _mm_mul_ps(vec_efw0, vec_efw0);
- __m128 vec_xfw_sumsq = _mm_mul_ps(vec_xfw0, vec_xfw0);
- vec_dfw_sumsq = _mm_add_ps(vec_dfw_sumsq, _mm_mul_ps(vec_dfw1, vec_dfw1));
- vec_efw_sumsq = _mm_add_ps(vec_efw_sumsq, _mm_mul_ps(vec_efw1, vec_efw1));
- vec_xfw_sumsq = _mm_add_ps(vec_xfw_sumsq, _mm_mul_ps(vec_xfw1, vec_xfw1));
- vec_xfw_sumsq = _mm_max_ps(vec_xfw_sumsq, vec_15);
- vec_sd = _mm_add_ps(vec_sd, _mm_mul_ps(vec_dfw_sumsq, vec_GCoh1));
- vec_se = _mm_add_ps(vec_se, _mm_mul_ps(vec_efw_sumsq, vec_GCoh1));
- vec_sx = _mm_add_ps(vec_sx, _mm_mul_ps(vec_xfw_sumsq, vec_GCoh1));
- _mm_storeu_ps(&coherence_state->sd[i], vec_sd);
- _mm_storeu_ps(&coherence_state->se[i], vec_se);
- _mm_storeu_ps(&coherence_state->sx[i], vec_sx);
-
- {
- const __m128 vec_3210 = _mm_loadu_ps(&coherence_state->sde[i][0]);
- const __m128 vec_7654 = _mm_loadu_ps(&coherence_state->sde[i + 2][0]);
- __m128 vec_a =
- _mm_shuffle_ps(vec_3210, vec_7654, _MM_SHUFFLE(2, 0, 2, 0));
- __m128 vec_b =
- _mm_shuffle_ps(vec_3210, vec_7654, _MM_SHUFFLE(3, 1, 3, 1));
- __m128 vec_dfwefw0011 = _mm_mul_ps(vec_dfw0, vec_efw0);
- __m128 vec_dfwefw0110 = _mm_mul_ps(vec_dfw0, vec_efw1);
- vec_a = _mm_mul_ps(vec_a, vec_GCoh0);
- vec_b = _mm_mul_ps(vec_b, vec_GCoh0);
- vec_dfwefw0011 =
- _mm_add_ps(vec_dfwefw0011, _mm_mul_ps(vec_dfw1, vec_efw1));
- vec_dfwefw0110 =
- _mm_sub_ps(vec_dfwefw0110, _mm_mul_ps(vec_dfw1, vec_efw0));
- vec_a = _mm_add_ps(vec_a, _mm_mul_ps(vec_dfwefw0011, vec_GCoh1));
- vec_b = _mm_add_ps(vec_b, _mm_mul_ps(vec_dfwefw0110, vec_GCoh1));
- _mm_storeu_ps(&coherence_state->sde[i][0], _mm_unpacklo_ps(vec_a, vec_b));
- _mm_storeu_ps(&coherence_state->sde[i + 2][0],
- _mm_unpackhi_ps(vec_a, vec_b));
- }
-
- {
- const __m128 vec_3210 = _mm_loadu_ps(&coherence_state->sxd[i][0]);
- const __m128 vec_7654 = _mm_loadu_ps(&coherence_state->sxd[i + 2][0]);
- __m128 vec_a =
- _mm_shuffle_ps(vec_3210, vec_7654, _MM_SHUFFLE(2, 0, 2, 0));
- __m128 vec_b =
- _mm_shuffle_ps(vec_3210, vec_7654, _MM_SHUFFLE(3, 1, 3, 1));
- __m128 vec_dfwxfw0011 = _mm_mul_ps(vec_dfw0, vec_xfw0);
- __m128 vec_dfwxfw0110 = _mm_mul_ps(vec_dfw0, vec_xfw1);
- vec_a = _mm_mul_ps(vec_a, vec_GCoh0);
- vec_b = _mm_mul_ps(vec_b, vec_GCoh0);
- vec_dfwxfw0011 =
- _mm_add_ps(vec_dfwxfw0011, _mm_mul_ps(vec_dfw1, vec_xfw1));
- vec_dfwxfw0110 =
- _mm_sub_ps(vec_dfwxfw0110, _mm_mul_ps(vec_dfw1, vec_xfw0));
- vec_a = _mm_add_ps(vec_a, _mm_mul_ps(vec_dfwxfw0011, vec_GCoh1));
- vec_b = _mm_add_ps(vec_b, _mm_mul_ps(vec_dfwxfw0110, vec_GCoh1));
- _mm_storeu_ps(&coherence_state->sxd[i][0], _mm_unpacklo_ps(vec_a, vec_b));
- _mm_storeu_ps(&coherence_state->sxd[i + 2][0],
- _mm_unpackhi_ps(vec_a, vec_b));
- }
-
- vec_sdSum = _mm_add_ps(vec_sdSum, vec_sd);
- vec_seSum = _mm_add_ps(vec_seSum, vec_se);
- }
-
- _mm_add_ps_4x1(vec_sdSum, &sdSum);
- _mm_add_ps_4x1(vec_seSum, &seSum);
-
- for (; i < PART_LEN1; i++) {
- coherence_state->sd[i] =
- ptrGCoh[0] * coherence_state->sd[i] +
- ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
- coherence_state->se[i] =
- ptrGCoh[0] * coherence_state->se[i] +
- ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
- // We threshold here to protect against the ill-effects of a zero farend.
- // The threshold is not arbitrarily chosen, but balances protection and
- // adverse interaction with the algorithm's tuning.
- // TODO(bjornv): investigate further why this is so sensitive.
- coherence_state->sx[i] =
- ptrGCoh[0] * coherence_state->sx[i] +
- ptrGCoh[1] *
- WEBRTC_SPL_MAX(xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
- WebRtcAec_kMinFarendPSD);
-
- coherence_state->sde[i][0] =
- ptrGCoh[0] * coherence_state->sde[i][0] +
- ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
- coherence_state->sde[i][1] =
- ptrGCoh[0] * coherence_state->sde[i][1] +
- ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
-
- coherence_state->sxd[i][0] =
- ptrGCoh[0] * coherence_state->sxd[i][0] +
- ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
- coherence_state->sxd[i][1] =
- ptrGCoh[0] * coherence_state->sxd[i][1] +
- ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
-
- sdSum += coherence_state->sd[i];
- seSum += coherence_state->se[i];
- }
-
- // Divergent filter safeguard update.
- *filter_divergence_state =
- (*filter_divergence_state ? 1.05f : 1.0f) * seSum > sdSum;
-
- // Signal extreme filter divergence if the error is significantly larger
- // than the nearend (13 dB).
- *extreme_filter_divergence = (seSum > (19.95f * sdSum));
-}
-
-// Window time domain data to be used by the fft.
-static void WindowDataSSE2(float* x_windowed, const float* x) {
- int i;
- for (i = 0; i < PART_LEN; i += 4) {
- const __m128 vec_Buf1 = _mm_loadu_ps(&x[i]);
- const __m128 vec_Buf2 = _mm_loadu_ps(&x[PART_LEN + i]);
- const __m128 vec_sqrtHanning = _mm_load_ps(&WebRtcAec_sqrtHanning[i]);
- // A B C D
- __m128 vec_sqrtHanning_rev =
- _mm_loadu_ps(&WebRtcAec_sqrtHanning[PART_LEN - i - 3]);
- // D C B A
- vec_sqrtHanning_rev = _mm_shuffle_ps(
- vec_sqrtHanning_rev, vec_sqrtHanning_rev, _MM_SHUFFLE(0, 1, 2, 3));
- _mm_storeu_ps(&x_windowed[i], _mm_mul_ps(vec_Buf1, vec_sqrtHanning));
- _mm_storeu_ps(&x_windowed[PART_LEN + i],
- _mm_mul_ps(vec_Buf2, vec_sqrtHanning_rev));
- }
-}
-
-// Puts fft output data into a complex valued array.
-static void StoreAsComplexSSE2(const float* data,
- float data_complex[2][PART_LEN1]) {
- int i;
- for (i = 0; i < PART_LEN; i += 4) {
- const __m128 vec_fft0 = _mm_loadu_ps(&data[2 * i]);
- const __m128 vec_fft4 = _mm_loadu_ps(&data[2 * i + 4]);
- const __m128 vec_a =
- _mm_shuffle_ps(vec_fft0, vec_fft4, _MM_SHUFFLE(2, 0, 2, 0));
- const __m128 vec_b =
- _mm_shuffle_ps(vec_fft0, vec_fft4, _MM_SHUFFLE(3, 1, 3, 1));
- _mm_storeu_ps(&data_complex[0][i], vec_a);
- _mm_storeu_ps(&data_complex[1][i], vec_b);
- }
- // fix beginning/end values
- data_complex[1][0] = 0;
- data_complex[1][PART_LEN] = 0;
- data_complex[0][0] = data[0];
- data_complex[0][PART_LEN] = data[1];
-}
-
-static void ComputeCoherenceSSE2(const CoherenceState* coherence_state,
- float* cohde,
- float* cohxd) {
- int i;
-
- {
- const __m128 vec_1eminus10 = _mm_set1_ps(1e-10f);
-
- // Subband coherence
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const __m128 vec_sd = _mm_loadu_ps(&coherence_state->sd[i]);
- const __m128 vec_se = _mm_loadu_ps(&coherence_state->se[i]);
- const __m128 vec_sx = _mm_loadu_ps(&coherence_state->sx[i]);
- const __m128 vec_sdse =
- _mm_add_ps(vec_1eminus10, _mm_mul_ps(vec_sd, vec_se));
- const __m128 vec_sdsx =
- _mm_add_ps(vec_1eminus10, _mm_mul_ps(vec_sd, vec_sx));
- const __m128 vec_sde_3210 = _mm_loadu_ps(&coherence_state->sde[i][0]);
- const __m128 vec_sde_7654 = _mm_loadu_ps(&coherence_state->sde[i + 2][0]);
- const __m128 vec_sxd_3210 = _mm_loadu_ps(&coherence_state->sxd[i][0]);
- const __m128 vec_sxd_7654 = _mm_loadu_ps(&coherence_state->sxd[i + 2][0]);
- const __m128 vec_sde_0 =
- _mm_shuffle_ps(vec_sde_3210, vec_sde_7654, _MM_SHUFFLE(2, 0, 2, 0));
- const __m128 vec_sde_1 =
- _mm_shuffle_ps(vec_sde_3210, vec_sde_7654, _MM_SHUFFLE(3, 1, 3, 1));
- const __m128 vec_sxd_0 =
- _mm_shuffle_ps(vec_sxd_3210, vec_sxd_7654, _MM_SHUFFLE(2, 0, 2, 0));
- const __m128 vec_sxd_1 =
- _mm_shuffle_ps(vec_sxd_3210, vec_sxd_7654, _MM_SHUFFLE(3, 1, 3, 1));
- __m128 vec_cohde = _mm_mul_ps(vec_sde_0, vec_sde_0);
- __m128 vec_cohxd = _mm_mul_ps(vec_sxd_0, vec_sxd_0);
- vec_cohde = _mm_add_ps(vec_cohde, _mm_mul_ps(vec_sde_1, vec_sde_1));
- vec_cohde = _mm_div_ps(vec_cohde, vec_sdse);
- vec_cohxd = _mm_add_ps(vec_cohxd, _mm_mul_ps(vec_sxd_1, vec_sxd_1));
- vec_cohxd = _mm_div_ps(vec_cohxd, vec_sdsx);
- _mm_storeu_ps(&cohde[i], vec_cohde);
- _mm_storeu_ps(&cohxd[i], vec_cohxd);
- }
-
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- cohde[i] = (coherence_state->sde[i][0] * coherence_state->sde[i][0] +
- coherence_state->sde[i][1] * coherence_state->sde[i][1]) /
- (coherence_state->sd[i] * coherence_state->se[i] + 1e-10f);
- cohxd[i] = (coherence_state->sxd[i][0] * coherence_state->sxd[i][0] +
- coherence_state->sxd[i][1] * coherence_state->sxd[i][1]) /
- (coherence_state->sx[i] * coherence_state->sd[i] + 1e-10f);
- }
- }
-}
-
-void WebRtcAec_InitAec_SSE2(void) {
- WebRtcAec_FilterFar = FilterFarSSE2;
- WebRtcAec_ScaleErrorSignal = ScaleErrorSignalSSE2;
- WebRtcAec_FilterAdaptation = FilterAdaptationSSE2;
- WebRtcAec_Overdrive = OverdriveSSE2;
- WebRtcAec_Suppress = SuppressSSE2;
- WebRtcAec_ComputeCoherence = ComputeCoherenceSSE2;
- WebRtcAec_UpdateCoherenceSpectra = UpdateCoherenceSpectraSSE2;
- WebRtcAec_StoreAsComplex = StoreAsComplexSSE2;
- WebRtcAec_PartitionDelay = PartitionDelaySSE2;
- WebRtcAec_WindowData = WindowDataSSE2;
-}
-} // namespace webrtc
diff --git a/modules/audio_processing/aec/aec_resampler.cc b/modules/audio_processing/aec/aec_resampler.cc
deleted file mode 100644
index 210c2be..0000000
--- a/modules/audio_processing/aec/aec_resampler.cc
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for
- * clock skew by resampling the farend signal.
- */
-
-#include "modules/audio_processing/aec/aec_resampler.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "modules/audio_processing/aec/aec_core.h"
-#include "rtc_base/checks.h"
-
-namespace webrtc {
-
-enum { kEstimateLengthFrames = 400 };
-
-typedef struct {
- float buffer[kResamplerBufferSize];
- float position;
-
- int deviceSampleRateHz;
- int skewData[kEstimateLengthFrames];
- int skewDataIndex;
- float skewEstimate;
-} AecResampler;
-
-static int EstimateSkew(const int* rawSkew,
- int size,
- int deviceSampleRateHz,
- float* skewEst);
-
-void* WebRtcAec_CreateResampler() {
- return malloc(sizeof(AecResampler));
-}
-
-int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
- AecResampler* obj = static_cast<AecResampler*>(resampInst);
- memset(obj->buffer, 0, sizeof(obj->buffer));
- obj->position = 0.0;
-
- obj->deviceSampleRateHz = deviceSampleRateHz;
- memset(obj->skewData, 0, sizeof(obj->skewData));
- obj->skewDataIndex = 0;
- obj->skewEstimate = 0.0;
-
- return 0;
-}
-
-void WebRtcAec_FreeResampler(void* resampInst) {
- AecResampler* obj = static_cast<AecResampler*>(resampInst);
- free(obj);
-}
-
-void WebRtcAec_ResampleLinear(void* resampInst,
- const float* inspeech,
- size_t size,
- float skew,
- float* outspeech,
- size_t* size_out) {
- AecResampler* obj = static_cast<AecResampler*>(resampInst);
-
- float* y;
- float be, tnew;
- size_t tn, mm;
-
- RTC_DCHECK_LE(size, 2 * FRAME_LEN);
- RTC_DCHECK(resampInst);
- RTC_DCHECK(inspeech);
- RTC_DCHECK(outspeech);
- RTC_DCHECK(size_out);
-
- // Add new frame data in lookahead
- memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay], inspeech,
- size * sizeof(inspeech[0]));
-
- // Sample rate ratio
- be = 1 + skew;
-
- // Loop over input frame
- mm = 0;
- y = &obj->buffer[FRAME_LEN]; // Point at current frame
-
- tnew = be * mm + obj->position;
- tn = (size_t)tnew;
-
- while (tn < size) {
- // Interpolation
- outspeech[mm] = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
- mm++;
-
- tnew = be * mm + obj->position;
- tn = static_cast<int>(tnew);
- }
-
- *size_out = mm;
- obj->position += (*size_out) * be - size;
-
- // Shift buffer
- memmove(obj->buffer, &obj->buffer[size],
- (kResamplerBufferSize - size) * sizeof(obj->buffer[0]));
-}
-
-int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
- AecResampler* obj = static_cast<AecResampler*>(resampInst);
- int err = 0;
-
- if (obj->skewDataIndex < kEstimateLengthFrames) {
- obj->skewData[obj->skewDataIndex] = rawSkew;
- obj->skewDataIndex++;
- } else if (obj->skewDataIndex == kEstimateLengthFrames) {
- err = EstimateSkew(obj->skewData, kEstimateLengthFrames,
- obj->deviceSampleRateHz, skewEst);
- obj->skewEstimate = *skewEst;
- obj->skewDataIndex++;
- } else {
- *skewEst = obj->skewEstimate;
- }
-
- return err;
-}
-
-int EstimateSkew(const int* rawSkew,
- int size,
- int deviceSampleRateHz,
- float* skewEst) {
- const int absLimitOuter = static_cast<int>(0.04f * deviceSampleRateHz);
- const int absLimitInner = static_cast<int>(0.0025f * deviceSampleRateHz);
- int i = 0;
- int n = 0;
- float rawAvg = 0;
- float err = 0;
- float rawAbsDev = 0;
- int upperLimit = 0;
- int lowerLimit = 0;
- float cumSum = 0;
- float x = 0;
- float x2 = 0;
- float y = 0;
- float xy = 0;
- float xAvg = 0;
- float denom = 0;
- float skew = 0;
-
- *skewEst = 0; // Set in case of error below.
- for (i = 0; i < size; i++) {
- if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
- n++;
- rawAvg += rawSkew[i];
- }
- }
-
- if (n == 0) {
- return -1;
- }
- RTC_DCHECK_GT(n, 0);
- rawAvg /= n;
-
- for (i = 0; i < size; i++) {
- if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
- err = rawSkew[i] - rawAvg;
- rawAbsDev += err >= 0 ? err : -err;
- }
- }
- RTC_DCHECK_GT(n, 0);
- rawAbsDev /= n;
- upperLimit = static_cast<int>(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
- lowerLimit = static_cast<int>(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
-
- n = 0;
- for (i = 0; i < size; i++) {
- if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
- (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
- n++;
- cumSum += rawSkew[i];
- x += n;
- x2 += n * n;
- y += cumSum;
- xy += n * cumSum;
- }
- }
-
- if (n == 0) {
- return -1;
- }
- RTC_DCHECK_GT(n, 0);
- xAvg = x / n;
- denom = x2 - xAvg * x;
-
- if (denom != 0) {
- skew = (xy - xAvg * y) / denom;
- }
-
- *skewEst = skew;
- return 0;
-}
-} // namespace webrtc
diff --git a/modules/audio_processing/aec/aec_resampler.h b/modules/audio_processing/aec/aec_resampler.h
deleted file mode 100644
index a112c43..0000000
--- a/modules/audio_processing/aec/aec_resampler.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
-#define MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
-
-#include <stddef.h>
-
-#include "modules/audio_processing/aec/aec_core.h"
-
-namespace webrtc {
-
-enum { kResamplingDelay = 1 };
-enum { kResamplerBufferSize = FRAME_LEN * 4 };
-
-// Unless otherwise specified, functions return 0 on success and -1 on error.
-void* WebRtcAec_CreateResampler(); // Returns NULL on error.
-int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz);
-void WebRtcAec_FreeResampler(void* resampInst);
-
-// Estimates skew from raw measurement.
-int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst);
-
-// Resamples input using linear interpolation.
-void WebRtcAec_ResampleLinear(void* resampInst,
- const float* inspeech,
- size_t size,
- float skew,
- float* outspeech,
- size_t* size_out);
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
diff --git a/modules/audio_processing/aec/echo_cancellation.cc b/modules/audio_processing/aec/echo_cancellation.cc
deleted file mode 100644
index fd1aec4..0000000
--- a/modules/audio_processing/aec/echo_cancellation.cc
+++ /dev/null
@@ -1,864 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * Contains the API functions for the AEC.
- */
-#include "modules/audio_processing/aec/echo_cancellation.h"
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-extern "C" {
-#include "common_audio/ring_buffer.h"
-#include "common_audio/signal_processing/include/signal_processing_library.h"
-}
-#include "modules/audio_processing/aec/aec_core.h"
-#include "modules/audio_processing/aec/aec_resampler.h"
-#include "modules/audio_processing/logging/apm_data_dumper.h"
-
-namespace webrtc {
-
-Aec::Aec() = default;
-Aec::~Aec() = default;
-
-// Measured delays [ms]
-// Device Chrome GTP
-// MacBook Air 10
-// MacBook Retina 10 100
-// MacPro 30?
-//
-// Win7 Desktop 70 80?
-// Win7 T430s 110
-// Win8 T420s 70
-//
-// Daisy 50
-// Pixel (w/ preproc?) 240
-// Pixel (w/o preproc?) 110 110
-
-// The extended filter mode gives us the flexibility to ignore the system's
-// reported delays. We do this for platforms which we believe provide results
-// which are incompatible with the AEC's expectations. Based on measurements
-// (some provided above) we set a conservative (i.e. lower than measured)
-// fixed delay.
-//
-// WEBRTC_UNTRUSTED_DELAY will only have an impact when |extended_filter_mode|
-// is enabled. See the note along with |DelayCorrection| in
-// echo_cancellation_impl.h for more details on the mode.
-//
-// Justification:
-// Chromium/Mac: Here, the true latency is so low (~10-20 ms), that it plays
-// havoc with the AEC's buffering. To avoid this, we set a fixed delay of 20 ms
-// and then compensate by rewinding by 10 ms (in wideband) through
-// kDelayDiffOffsetSamples. This trick does not seem to work for larger rewind
-// values, but fortunately this is sufficient.
-//
-// Chromium/Linux(ChromeOS): The values we get on this platform don't correspond
-// well to reality. The variance doesn't match the AEC's buffer changes, and the
-// bulk values tend to be too low. However, the range across different hardware
-// appears to be too large to choose a single value.
-//
-// GTP/Linux(ChromeOS): TBD, but for the moment we will trust the values.
-#if defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_MAC)
-#define WEBRTC_UNTRUSTED_DELAY
-#endif
-
-#if defined(WEBRTC_UNTRUSTED_DELAY) && defined(WEBRTC_MAC)
-static const int kDelayDiffOffsetSamples = -160;
-#else
-// Not enabled for now.
-static const int kDelayDiffOffsetSamples = 0;
-#endif
-
-#if defined(WEBRTC_MAC)
-static const int kFixedDelayMs = 20;
-#else
-static const int kFixedDelayMs = 50;
-#endif
-#if !defined(WEBRTC_UNTRUSTED_DELAY)
-static const int kMinTrustedDelayMs = 20;
-#endif
-static const int kMaxTrustedDelayMs = 500;
-
-// Maximum length of resampled signal. Must be an integer multiple of frames
-// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
-// The factor of 2 handles wb, and the + 1 is as a safety margin
-// TODO(bjornv): Replace with kResamplerBufferSize
-#define MAX_RESAMP_LEN (5 * FRAME_LEN)
-
-static const int kMaxBufSizeStart = 62; // In partitions
-static const int sampMsNb = 8; // samples per ms in nb
-static const int initCheck = 42;
-
-int Aec::instance_count = 0;
-
-// Estimates delay to set the position of the far-end buffer read pointer
-// (controlled by knownDelay)
-static void EstBufDelayNormal(Aec* aecInst);
-static void EstBufDelayExtended(Aec* aecInst);
-static int ProcessNormal(Aec* aecInst,
- const float* const* nearend,
- size_t num_bands,
- float* const* out,
- size_t num_samples,
- int16_t reported_delay_ms,
- int32_t skew);
-static void ProcessExtended(Aec* aecInst,
- const float* const* nearend,
- size_t num_bands,
- float* const* out,
- size_t num_samples,
- int16_t reported_delay_ms,
- int32_t skew);
-
-void* WebRtcAec_Create() {
- Aec* aecpc = new Aec();
-
- if (!aecpc) {
- return NULL;
- }
- aecpc->data_dumper.reset(new ApmDataDumper(aecpc->instance_count));
-
- aecpc->aec = WebRtcAec_CreateAec(aecpc->instance_count);
- if (!aecpc->aec) {
- WebRtcAec_Free(aecpc);
- return NULL;
- }
- aecpc->resampler = WebRtcAec_CreateResampler();
- if (!aecpc->resampler) {
- WebRtcAec_Free(aecpc);
- return NULL;
- }
- // Create far-end pre-buffer. The buffer size has to be large enough for
- // largest possible drift compensation (kResamplerBufferSize) + "almost" an
- // FFT buffer (PART_LEN2 - 1).
- aecpc->far_pre_buf =
- WebRtc_CreateBuffer(PART_LEN2 + kResamplerBufferSize, sizeof(float));
- if (!aecpc->far_pre_buf) {
- WebRtcAec_Free(aecpc);
- return NULL;
- }
-
- aecpc->initFlag = 0;
-
- aecpc->instance_count++;
- return aecpc;
-}
-
-void WebRtcAec_Free(void* aecInst) {
- Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
-
- if (aecpc == NULL) {
- return;
- }
-
- WebRtc_FreeBuffer(aecpc->far_pre_buf);
-
- WebRtcAec_FreeAec(aecpc->aec);
- WebRtcAec_FreeResampler(aecpc->resampler);
- delete aecpc;
-}
-
-int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
- Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
- aecpc->data_dumper->InitiateNewSetOfRecordings();
- AecConfig aecConfig;
-
- if (sampFreq != 8000 && sampFreq != 16000 && sampFreq != 32000 &&
- sampFreq != 48000) {
- return AEC_BAD_PARAMETER_ERROR;
- }
- aecpc->sampFreq = sampFreq;
-
- if (scSampFreq < 1 || scSampFreq > 96000) {
- return AEC_BAD_PARAMETER_ERROR;
- }
- aecpc->scSampFreq = scSampFreq;
-
- // Initialize echo canceller core
- if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
- return AEC_UNSPECIFIED_ERROR;
- }
-
- if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
- return AEC_UNSPECIFIED_ERROR;
- }
-
- WebRtc_InitBuffer(aecpc->far_pre_buf);
- WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN); // Start overlap.
-
- aecpc->initFlag = initCheck; // indicates that initialization has been done
-
- if (aecpc->sampFreq == 32000 || aecpc->sampFreq == 48000) {
- aecpc->splitSampFreq = 16000;
- } else {
- aecpc->splitSampFreq = sampFreq;
- }
-
- aecpc->delayCtr = 0;
- aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq;
- // Sampling frequency multiplier (SWB is processed as 160 frame size).
- aecpc->rate_factor = aecpc->splitSampFreq / 8000;
-
- aecpc->sum = 0;
- aecpc->counter = 0;
- aecpc->checkBuffSize = 1;
- aecpc->firstVal = 0;
-
- // We skip the startup_phase completely (setting to 0) if DA-AEC is enabled,
- // but not extended_filter mode.
- aecpc->startup_phase = WebRtcAec_extended_filter_enabled(aecpc->aec) ||
- !WebRtcAec_delay_agnostic_enabled(aecpc->aec);
- aecpc->bufSizeStart = 0;
- aecpc->checkBufSizeCtr = 0;
- aecpc->msInSndCardBuf = 0;
- aecpc->filtDelay = -1; // -1 indicates an initialized state.
- aecpc->timeForDelayChange = 0;
- aecpc->knownDelay = 0;
- aecpc->lastDelayDiff = 0;
-
- aecpc->skewFrCtr = 0;
- aecpc->resample = kAecFalse;
- aecpc->highSkewCtr = 0;
- aecpc->skew = 0;
-
- aecpc->farend_started = 0;
-
- // Default settings.
- aecConfig.nlpMode = kAecNlpModerate;
- aecConfig.skewMode = kAecFalse;
- aecConfig.metricsMode = kAecFalse;
- aecConfig.delay_logging = kAecFalse;
-
- if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
- return AEC_UNSPECIFIED_ERROR;
- }
-
- return 0;
-}
-
-// Returns any error that is caused when buffering the
-// far-end signal.
-int32_t WebRtcAec_GetBufferFarendError(void* aecInst,
- const float* farend,
- size_t nrOfSamples) {
- Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
-
- if (!farend)
- return AEC_NULL_POINTER_ERROR;
-
- if (aecpc->initFlag != initCheck)
- return AEC_UNINITIALIZED_ERROR;
-
- // number of samples == 160 for SWB input
- if (nrOfSamples != 80 && nrOfSamples != 160)
- return AEC_BAD_PARAMETER_ERROR;
-
- return 0;
-}
-
-// only buffer L band for farend
-int32_t WebRtcAec_BufferFarend(void* aecInst,
- const float* farend,
- size_t nrOfSamples) {
- Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
- size_t newNrOfSamples = nrOfSamples;
- float new_farend[MAX_RESAMP_LEN];
- const float* farend_ptr = farend;
-
- // Get any error caused by buffering the farend signal.
- int32_t error_code =
- WebRtcAec_GetBufferFarendError(aecInst, farend, nrOfSamples);
-
- if (error_code != 0)
- return error_code;
-
- if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
- // Resample and get a new number of samples
- WebRtcAec_ResampleLinear(aecpc->resampler, farend, nrOfSamples, aecpc->skew,
- new_farend, &newNrOfSamples);
- farend_ptr = new_farend;
- }
-
- aecpc->farend_started = 1;
- WebRtcAec_SetSystemDelay(aecpc->aec, WebRtcAec_system_delay(aecpc->aec) +
- static_cast<int>(newNrOfSamples));
-
- // Write the time-domain data to |far_pre_buf|.
- WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, newNrOfSamples);
-
- // TODO(minyue): reduce to |PART_LEN| samples for each buffering.
- while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
- // We have enough data to pass to the FFT, hence read PART_LEN2 samples.
- {
- float* ptmp = NULL;
- float tmp[PART_LEN2];
- WebRtc_ReadBuffer(aecpc->far_pre_buf, reinterpret_cast<void**>(&ptmp),
- tmp, PART_LEN2);
- WebRtcAec_BufferFarendBlock(aecpc->aec, &ptmp[PART_LEN]);
- }
-
- // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
- WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
- }
-
- return 0;
-}
-
-int32_t WebRtcAec_Process(void* aecInst,
- const float* const* nearend,
- size_t num_bands,
- float* const* out,
- size_t nrOfSamples,
- int16_t msInSndCardBuf,
- int32_t skew) {
- Aec* aecpc = reinterpret_cast<Aec*>(aecInst);
- int32_t retVal = 0;
-
- if (out == NULL) {
- return AEC_NULL_POINTER_ERROR;
- }
-
- if (aecpc->initFlag != initCheck) {
- return AEC_UNINITIALIZED_ERROR;
- }
-
- // number of samples == 160 for SWB input
- if (nrOfSamples != 80 && nrOfSamples != 160) {
- return AEC_BAD_PARAMETER_ERROR;
- }
-
- if (msInSndCardBuf < 0) {
- msInSndCardBuf = 0;
- retVal = AEC_BAD_PARAMETER_WARNING;
- } else if (msInSndCardBuf > kMaxTrustedDelayMs) {
- // The clamping is now done in ProcessExtended/Normal().
- retVal = AEC_BAD_PARAMETER_WARNING;
- }
-
- // This returns the value of aec->extended_filter_enabled.
- if (WebRtcAec_extended_filter_enabled(aecpc->aec)) {
- ProcessExtended(aecpc, nearend, num_bands, out, nrOfSamples, msInSndCardBuf,
- skew);
- } else {
- retVal = ProcessNormal(aecpc, nearend, num_bands, out, nrOfSamples,
- msInSndCardBuf, skew);
- }
-
- int far_buf_size_samples = WebRtcAec_system_delay(aecpc->aec);
- aecpc->data_dumper->DumpRaw("aec_system_delay", 1, &far_buf_size_samples);
- aecpc->data_dumper->DumpRaw("aec_known_delay", 1, &aecpc->knownDelay);
-
- return retVal;
-}
-
-int WebRtcAec_set_config(void* handle, AecConfig config) {
- Aec* self = reinterpret_cast<Aec*>(handle);
- if (self->initFlag != initCheck) {
- return AEC_UNINITIALIZED_ERROR;
- }
-
- if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) {
- return AEC_BAD_PARAMETER_ERROR;
- }
- self->skewMode = config.skewMode;
-
- if (config.nlpMode != kAecNlpConservative &&
- config.nlpMode != kAecNlpModerate &&
- config.nlpMode != kAecNlpAggressive) {
- return AEC_BAD_PARAMETER_ERROR;
- }
-
- if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) {
- return AEC_BAD_PARAMETER_ERROR;
- }
-
- if (config.delay_logging != kAecFalse && config.delay_logging != kAecTrue) {
- return AEC_BAD_PARAMETER_ERROR;
- }
-
- WebRtcAec_SetConfigCore(self->aec, config.nlpMode, config.metricsMode,
- config.delay_logging);
- return 0;
-}
-
-int WebRtcAec_get_echo_status(void* handle, int* status) {
- Aec* self = reinterpret_cast<Aec*>(handle);
- if (status == NULL) {
- return AEC_NULL_POINTER_ERROR;
- }
- if (self->initFlag != initCheck) {
- return AEC_UNINITIALIZED_ERROR;
- }
-
- *status = WebRtcAec_echo_state(self->aec);
-
- return 0;
-}
-
-int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics) {
- const float kUpWeight = 0.7f;
- float dtmp;
- int stmp;
- Aec* self = reinterpret_cast<Aec*>(handle);
- Stats erl;
- Stats erle;
- Stats a_nlp;
-
- if (handle == NULL) {
- return -1;
- }
- if (metrics == NULL) {
- return AEC_NULL_POINTER_ERROR;
- }
- if (self->initFlag != initCheck) {
- return AEC_UNINITIALIZED_ERROR;
- }
-
- WebRtcAec_GetEchoStats(self->aec, &erl, &erle, &a_nlp,
- &metrics->divergent_filter_fraction);
-
- // ERL
- metrics->erl.instant = static_cast<int>(erl.instant);
-
- if ((erl.himean > kOffsetLevel) && (erl.average > kOffsetLevel)) {
- // Use a mix between regular average and upper part average.
- dtmp = kUpWeight * erl.himean + (1 - kUpWeight) * erl.average;
- metrics->erl.average = static_cast<int>(dtmp);
- } else {
- metrics->erl.average = kOffsetLevel;
- }
-
- metrics->erl.max = static_cast<int>(erl.max);
-
- if (erl.min < (kOffsetLevel * (-1))) {
- metrics->erl.min = static_cast<int>(erl.min);
- } else {
- metrics->erl.min = kOffsetLevel;
- }
-
- // ERLE
- metrics->erle.instant = static_cast<int>(erle.instant);
-
- if ((erle.himean > kOffsetLevel) && (erle.average > kOffsetLevel)) {
- // Use a mix between regular average and upper part average.
- dtmp = kUpWeight * erle.himean + (1 - kUpWeight) * erle.average;
- metrics->erle.average = static_cast<int>(dtmp);
- } else {
- metrics->erle.average = kOffsetLevel;
- }
-
- metrics->erle.max = static_cast<int>(erle.max);
-
- if (erle.min < (kOffsetLevel * (-1))) {
- metrics->erle.min = static_cast<int>(erle.min);
- } else {
- metrics->erle.min = kOffsetLevel;
- }
-
- // RERL
- if ((metrics->erl.average > kOffsetLevel) &&
- (metrics->erle.average > kOffsetLevel)) {
- stmp = metrics->erl.average + metrics->erle.average;
- } else {
- stmp = kOffsetLevel;
- }
- metrics->rerl.average = stmp;
-
- // No other statistics needed, but returned for completeness.
- metrics->rerl.instant = stmp;
- metrics->rerl.max = stmp;
- metrics->rerl.min = stmp;
-
- // A_NLP
- metrics->aNlp.instant = static_cast<int>(a_nlp.instant);
-
- if ((a_nlp.himean > kOffsetLevel) && (a_nlp.average > kOffsetLevel)) {
- // Use a mix between regular average and upper part average.
- dtmp = kUpWeight * a_nlp.himean + (1 - kUpWeight) * a_nlp.average;
- metrics->aNlp.average = static_cast<int>(dtmp);
- } else {
- metrics->aNlp.average = kOffsetLevel;
- }
-
- metrics->aNlp.max = static_cast<int>(a_nlp.max);
-
- if (a_nlp.min < (kOffsetLevel * (-1))) {
- metrics->aNlp.min = static_cast<int>(a_nlp.min);
- } else {
- metrics->aNlp.min = kOffsetLevel;
- }
-
- return 0;
-}
-
-int WebRtcAec_GetDelayMetrics(void* handle,
- int* median,
- int* std,
- float* fraction_poor_delays) {
- Aec* self = reinterpret_cast<Aec*>(handle);
- if (median == NULL) {
- return AEC_NULL_POINTER_ERROR;
- }
- if (std == NULL) {
- return AEC_NULL_POINTER_ERROR;
- }
- if (self->initFlag != initCheck) {
- return AEC_UNINITIALIZED_ERROR;
- }
- if (WebRtcAec_GetDelayMetricsCore(self->aec, median, std,
- fraction_poor_delays) == -1) {
- // Logging disabled.
- return AEC_UNSUPPORTED_FUNCTION_ERROR;
- }
-
- return 0;
-}
-
-AecCore* WebRtcAec_aec_core(void* handle) {
- if (!handle) {
- return NULL;
- }
- return reinterpret_cast<Aec*>(handle)->aec;
-}
-
-static int ProcessNormal(Aec* aecInst,
- const float* const* nearend,
- size_t num_bands,
- float* const* out,
- size_t num_samples,
- int16_t reported_delay_ms,
- int32_t skew) {
- int retVal = 0;
- size_t i;
- size_t nBlocks10ms;
- // Limit resampling to doubling/halving of signal
- const float minSkewEst = -0.5f;
- const float maxSkewEst = 1.0f;
-
- reported_delay_ms = reported_delay_ms > kMaxTrustedDelayMs
- ? kMaxTrustedDelayMs
- : reported_delay_ms;
- // TODO(andrew): we need to investigate if this +10 is really wanted.
- reported_delay_ms += 10;
- aecInst->msInSndCardBuf = reported_delay_ms;
-
- if (aecInst->skewMode == kAecTrue) {
- if (aecInst->skewFrCtr < 25) {
- aecInst->skewFrCtr++;
- } else {
- retVal = WebRtcAec_GetSkew(aecInst->resampler, skew, &aecInst->skew);
- if (retVal == -1) {
- aecInst->skew = 0;
- retVal = AEC_BAD_PARAMETER_WARNING;
- }
-
- aecInst->skew /= aecInst->sampFactor * num_samples;
-
- if (aecInst->skew < 1.0e-3 && aecInst->skew > -1.0e-3) {
- aecInst->resample = kAecFalse;
- } else {
- aecInst->resample = kAecTrue;
- }
-
- if (aecInst->skew < minSkewEst) {
- aecInst->skew = minSkewEst;
- } else if (aecInst->skew > maxSkewEst) {
- aecInst->skew = maxSkewEst;
- }
-
- aecInst->data_dumper->DumpRaw("aec_skew", 1, &aecInst->skew);
- }
- }
-
- nBlocks10ms = num_samples / (FRAME_LEN * aecInst->rate_factor);
-
- if (aecInst->startup_phase) {
- for (i = 0; i < num_bands; ++i) {
- // Only needed if they don't already point to the same place.
- if (nearend[i] != out[i]) {
- memcpy(out[i], nearend[i], sizeof(nearend[i][0]) * num_samples);
- }
- }
-
- // The AEC is in the start up mode
- // AEC is disabled until the system delay is OK
-
- // Mechanism to ensure that the system delay is reasonably stable.
- if (aecInst->checkBuffSize) {
- aecInst->checkBufSizeCtr++;
- // Before we fill up the far-end buffer we require the system delay
- // to be stable (+/-8 ms) compared to the first value. This
- // comparison is made during the following 6 consecutive 10 ms
- // blocks. If it seems to be stable then we start to fill up the
- // far-end buffer.
- if (aecInst->counter == 0) {
- aecInst->firstVal = aecInst->msInSndCardBuf;
- aecInst->sum = 0;
- }
-
- if (abs(aecInst->firstVal - aecInst->msInSndCardBuf) <
- WEBRTC_SPL_MAX(0.2 * aecInst->msInSndCardBuf, sampMsNb)) {
- aecInst->sum += aecInst->msInSndCardBuf;
- aecInst->counter++;
- } else {
- aecInst->counter = 0;
- }
-
- if (aecInst->counter * nBlocks10ms >= 6) {
- // The far-end buffer size is determined in partitions of
- // PART_LEN samples. Use 75% of the average value of the system
- // delay as buffer size to start with.
- aecInst->bufSizeStart =
- WEBRTC_SPL_MIN((3 * aecInst->sum * aecInst->rate_factor * 8) /
- (4 * aecInst->counter * PART_LEN),
- kMaxBufSizeStart);
- // Buffer size has now been determined.
- aecInst->checkBuffSize = 0;
- }
-
- if (aecInst->checkBufSizeCtr * nBlocks10ms > 50) {
- // For really bad systems, don't disable the echo canceller for
- // more than 0.5 sec.
- aecInst->bufSizeStart = WEBRTC_SPL_MIN(
- (aecInst->msInSndCardBuf * aecInst->rate_factor * 3) / 40,
- kMaxBufSizeStart);
- aecInst->checkBuffSize = 0;
- }
- }
-
- // If |checkBuffSize| changed in the if-statement above.
- if (!aecInst->checkBuffSize) {
- // The system delay is now reasonably stable (or has been unstable
- // for too long). When the far-end buffer is filled with
- // approximately the same amount of data as reported by the system
- // we end the startup phase.
- int overhead_elements = WebRtcAec_system_delay(aecInst->aec) / PART_LEN -
- aecInst->bufSizeStart;
- if (overhead_elements == 0) {
- // Enable the AEC
- aecInst->startup_phase = 0;
- } else if (overhead_elements > 0) {
- // TODO(bjornv): Do we need a check on how much we actually
- // moved the read pointer? It should always be possible to move
- // the pointer |overhead_elements| since we have only added data
- // to the buffer and no delay compensation nor AEC processing
- // has been done.
- WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aecInst->aec,
- overhead_elements);
-
- // Enable the AEC
- aecInst->startup_phase = 0;
- }
- }
- } else {
- // AEC is enabled.
- EstBufDelayNormal(aecInst);
-
- // Call the AEC.
- // TODO(bjornv): Re-structure such that we don't have to pass
- // |aecInst->knownDelay| as input. Change name to something like
- // |system_buffer_diff|.
- WebRtcAec_ProcessFrames(aecInst->aec, nearend, num_bands, num_samples,
- aecInst->knownDelay, out);
- }
-
- return retVal;
-}
-
-static void ProcessExtended(Aec* self,
- const float* const* nearend,
- size_t num_bands,
- float* const* out,
- size_t num_samples,
- int16_t reported_delay_ms,
- int32_t skew) {
- size_t i;
- const int delay_diff_offset = kDelayDiffOffsetSamples;
- RTC_DCHECK(num_samples == 80 || num_samples == 160);
-#if defined(WEBRTC_UNTRUSTED_DELAY)
- reported_delay_ms = kFixedDelayMs;
-#else
- // This is the usual mode where we trust the reported system delay values.
- // Due to the longer filter, we no longer add 10 ms to the reported delay
- // to reduce chance of non-causality. Instead we apply a minimum here to avoid
- // issues with the read pointer jumping around needlessly.
- reported_delay_ms = reported_delay_ms < kMinTrustedDelayMs
- ? kMinTrustedDelayMs
- : reported_delay_ms;
- // If the reported delay appears to be bogus, we attempt to recover by using
- // the measured fixed delay values. We use >= here because higher layers
- // may already clamp to this maximum value, and we would otherwise not
- // detect it here.
- reported_delay_ms = reported_delay_ms >= kMaxTrustedDelayMs
- ? kFixedDelayMs
- : reported_delay_ms;
-#endif
- self->msInSndCardBuf = reported_delay_ms;
-
- if (!self->farend_started) {
- for (i = 0; i < num_bands; ++i) {
- // Only needed if they don't already point to the same place.
- if (nearend[i] != out[i]) {
- memcpy(out[i], nearend[i], sizeof(nearend[i][0]) * num_samples);
- }
- }
- return;
- }
- if (self->startup_phase) {
- // In the extended mode, there isn't a startup "phase", just a special
- // action on the first frame. In the trusted delay case, we'll take the
- // current reported delay, unless it's less then our conservative
- // measurement.
- int startup_size_ms =
- reported_delay_ms < kFixedDelayMs ? kFixedDelayMs : reported_delay_ms;
-#if defined(WEBRTC_ANDROID)
- int target_delay = startup_size_ms * self->rate_factor * 8;
-#else
- // To avoid putting the AEC in a non-causal state we're being slightly
- // conservative and scale by 2. On Android we use a fixed delay and
- // therefore there is no need to scale the target_delay.
- int target_delay = startup_size_ms * self->rate_factor * 8 / 2;
-#endif
- int overhead_elements =
- (WebRtcAec_system_delay(self->aec) - target_delay) / PART_LEN;
- WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(self->aec,
- overhead_elements);
- self->startup_phase = 0;
- }
-
- EstBufDelayExtended(self);
-
- {
- // |delay_diff_offset| gives us the option to manually rewind the delay on
- // very low delay platforms which can't be expressed purely through
- // |reported_delay_ms|.
- const int adjusted_known_delay =
- WEBRTC_SPL_MAX(0, self->knownDelay + delay_diff_offset);
-
- WebRtcAec_ProcessFrames(self->aec, nearend, num_bands, num_samples,
- adjusted_known_delay, out);
- }
-}
-
-static void EstBufDelayNormal(Aec* aecInst) {
- int nSampSndCard = aecInst->msInSndCardBuf * sampMsNb * aecInst->rate_factor;
- int current_delay = nSampSndCard - WebRtcAec_system_delay(aecInst->aec);
- int delay_difference = 0;
-
- // Before we proceed with the delay estimate filtering we:
- // 1) Compensate for the frame that will be read.
- // 2) Compensate for drift resampling.
- // 3) Compensate for non-causality if needed, since the estimated delay can't
- // be negative.
-
- // 1) Compensating for the frame(s) that will be read/processed.
- current_delay += FRAME_LEN * aecInst->rate_factor;
-
- // 2) Account for resampling frame delay.
- if (aecInst->skewMode == kAecTrue && aecInst->resample == kAecTrue) {
- current_delay -= kResamplingDelay;
- }
-
- // 3) Compensate for non-causality, if needed, by flushing one block.
- if (current_delay < PART_LEN) {
- current_delay +=
- WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aecInst->aec, 1) *
- PART_LEN;
- }
-
- // We use -1 to signal an initialized state in the "extended" implementation;
- // compensate for that.
- aecInst->filtDelay = aecInst->filtDelay < 0 ? 0 : aecInst->filtDelay;
- aecInst->filtDelay = WEBRTC_SPL_MAX(
- 0, static_cast<int16_t>(0.8 * aecInst->filtDelay + 0.2 * current_delay));
-
- delay_difference = aecInst->filtDelay - aecInst->knownDelay;
- if (delay_difference > 224) {
- if (aecInst->lastDelayDiff < 96) {
- aecInst->timeForDelayChange = 0;
- } else {
- aecInst->timeForDelayChange++;
- }
- } else if (delay_difference < 96 && aecInst->knownDelay > 0) {
- if (aecInst->lastDelayDiff > 224) {
- aecInst->timeForDelayChange = 0;
- } else {
- aecInst->timeForDelayChange++;
- }
- } else {
- aecInst->timeForDelayChange = 0;
- }
- aecInst->lastDelayDiff = delay_difference;
-
- if (aecInst->timeForDelayChange > 25) {
- aecInst->knownDelay = WEBRTC_SPL_MAX((int)aecInst->filtDelay - 160, 0);
- }
-}
-
-static void EstBufDelayExtended(Aec* aecInst) {
- int reported_delay =
- aecInst->msInSndCardBuf * sampMsNb * aecInst->rate_factor;
- int current_delay = reported_delay - WebRtcAec_system_delay(aecInst->aec);
- int delay_difference = 0;
-
- // Before we proceed with the delay estimate filtering we:
- // 1) Compensate for the frame that will be read.
- // 2) Compensate for drift resampling.
- // 3) Compensate for non-causality if needed, since the estimated delay can't
- // be negative.
-
- // 1) Compensating for the frame(s) that will be read/processed.
- current_delay += FRAME_LEN * aecInst->rate_factor;
-
- // 2) Account for resampling frame delay.
- if (aecInst->skewMode == kAecTrue && aecInst->resample == kAecTrue) {
- current_delay -= kResamplingDelay;
- }
-
- // 3) Compensate for non-causality, if needed, by flushing two blocks.
- if (current_delay < PART_LEN) {
- current_delay +=
- WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aecInst->aec, 2) *
- PART_LEN;
- }
-
- if (aecInst->filtDelay == -1) {
- aecInst->filtDelay = WEBRTC_SPL_MAX(0, 0.5 * current_delay);
- } else {
- aecInst->filtDelay = WEBRTC_SPL_MAX(
- 0,
- static_cast<int16_t>(0.95 * aecInst->filtDelay + 0.05 * current_delay));
- }
-
- delay_difference = aecInst->filtDelay - aecInst->knownDelay;
- if (delay_difference > 384) {
- if (aecInst->lastDelayDiff < 128) {
- aecInst->timeForDelayChange = 0;
- } else {
- aecInst->timeForDelayChange++;
- }
- } else if (delay_difference < 128 && aecInst->knownDelay > 0) {
- if (aecInst->lastDelayDiff > 384) {
- aecInst->timeForDelayChange = 0;
- } else {
- aecInst->timeForDelayChange++;
- }
- } else {
- aecInst->timeForDelayChange = 0;
- }
- aecInst->lastDelayDiff = delay_difference;
-
- if (aecInst->timeForDelayChange > 25) {
- aecInst->knownDelay = WEBRTC_SPL_MAX((int)aecInst->filtDelay - 256, 0);
- }
-}
-} // namespace webrtc
diff --git a/modules/audio_processing/aec/echo_cancellation.h b/modules/audio_processing/aec/echo_cancellation.h
deleted file mode 100644
index 62dc0f0..0000000
--- a/modules/audio_processing/aec/echo_cancellation.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_AEC_ECHO_CANCELLATION_H_
-#define MODULES_AUDIO_PROCESSING_AEC_ECHO_CANCELLATION_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-extern "C" {
-#include "common_audio/ring_buffer.h"
-}
-#include "modules/audio_processing/aec/aec_core.h"
-
-namespace webrtc {
-
-// Errors
-#define AEC_UNSPECIFIED_ERROR 12000
-#define AEC_UNSUPPORTED_FUNCTION_ERROR 12001
-#define AEC_UNINITIALIZED_ERROR 12002
-#define AEC_NULL_POINTER_ERROR 12003
-#define AEC_BAD_PARAMETER_ERROR 12004
-
-// Warnings
-#define AEC_BAD_PARAMETER_WARNING 12050
-
-enum { kAecNlpConservative = 0, kAecNlpModerate, kAecNlpAggressive };
-
-enum { kAecFalse = 0, kAecTrue };
-
-typedef struct {
- int16_t nlpMode; // default kAecNlpModerate
- int16_t skewMode; // default kAecFalse
- int16_t metricsMode; // default kAecFalse
- int delay_logging; // default kAecFalse
- // float realSkew;
-} AecConfig;
-
-typedef struct {
- int instant;
- int average;
- int max;
- int min;
-} AecLevel;
-
-typedef struct {
- AecLevel rerl;
- AecLevel erl;
- AecLevel erle;
- AecLevel aNlp;
- float divergent_filter_fraction;
-} AecMetrics;
-
-struct AecCore;
-
-class ApmDataDumper;
-
-typedef struct Aec {
- Aec();
- ~Aec();
-
- std::unique_ptr<ApmDataDumper> data_dumper;
-
- int delayCtr;
- int sampFreq;
- int splitSampFreq;
- int scSampFreq;
- float sampFactor; // scSampRate / sampFreq
- short skewMode;
- int bufSizeStart;
- int knownDelay;
- int rate_factor;
-
- short initFlag; // indicates if AEC has been initialized
-
- // Variables used for averaging far end buffer size
- short counter;
- int sum;
- short firstVal;
- short checkBufSizeCtr;
-
- // Variables used for delay shifts
- short msInSndCardBuf;
- short filtDelay; // Filtered delay estimate.
- int timeForDelayChange;
- int startup_phase;
- int checkBuffSize;
- short lastDelayDiff;
-
- // Structures
- void* resampler;
-
- int skewFrCtr;
- int resample; // if the skew is small enough we don't resample
- int highSkewCtr;
- float skew;
-
- RingBuffer* far_pre_buf; // Time domain far-end pre-buffer.
-
- int farend_started;
-
- // Aec instance counter.
- static int instance_count;
- AecCore* aec;
-} Aec;
-
-/*
- * Allocates the memory needed by the AEC. The memory needs to be initialized
- * separately using the WebRtcAec_Init() function. Returns a pointer to the
- * object or NULL on error.
- */
-void* WebRtcAec_Create();
-
-/*
- * This function releases the memory allocated by WebRtcAec_Create().
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- */
-void WebRtcAec_Free(void* aecInst);
-
-/*
- * Initializes an AEC instance.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- * int32_t sampFreq Sampling frequency of data
- * int32_t scSampFreq Soundcard sampling frequency
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int32_t return 0: OK
- * -1: error
- */
-int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq);
-
-/*
- * Inserts an 80 or 160 sample block of data into the farend buffer.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- * const float* farend In buffer containing one frame of
- * farend signal for L band
- * int16_t nrOfSamples Number of samples in farend buffer
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int32_t return 0: OK
- * 12000-12050: error code
- */
-int32_t WebRtcAec_BufferFarend(void* aecInst,
- const float* farend,
- size_t nrOfSamples);
-
-/*
- * Reports any errors that would arise if buffering a farend buffer
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- * const float* farend In buffer containing one frame of
- * farend signal for L band
- * int16_t nrOfSamples Number of samples in farend buffer
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int32_t return 0: OK
- * 12000-12050: error code
- */
-int32_t WebRtcAec_GetBufferFarendError(void* aecInst,
- const float* farend,
- size_t nrOfSamples);
-
-/*
- * Runs the echo canceller on an 80 or 160 sample blocks of data.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- * float* const* nearend In buffer containing one frame of
- * nearend+echo signal for each band
- * int num_bands Number of bands in nearend buffer
- * int16_t nrOfSamples Number of samples in nearend buffer
- * int16_t msInSndCardBuf Delay estimate for sound card and
- * system buffers
- * int16_t skew Difference between number of samples played
- * and recorded at the soundcard (for clock skew
- * compensation)
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * float* const* out Out buffer, one frame of processed nearend
- * for each band
- * int32_t return 0: OK
- * 12000-12050: error code
- */
-int32_t WebRtcAec_Process(void* aecInst,
- const float* const* nearend,
- size_t num_bands,
- float* const* out,
- size_t nrOfSamples,
- int16_t msInSndCardBuf,
- int32_t skew);
-
-/*
- * This function enables the user to set certain parameters on-the-fly.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* handle Pointer to the AEC instance
- * AecConfig config Config instance that contains all
- * properties to be set
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int return 0: OK
- * 12000-12050: error code
- */
-int WebRtcAec_set_config(void* handle, AecConfig config);
-
-/*
- * Gets the current echo status of the nearend signal.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* handle Pointer to the AEC instance
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int* status 0: Almost certainly nearend single-talk
- * 1: Might not be neared single-talk
- * int return 0: OK
- * 12000-12050: error code
- */
-int WebRtcAec_get_echo_status(void* handle, int* status);
-
-/*
- * Gets the current echo metrics for the session.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* handle Pointer to the AEC instance
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * AecMetrics* metrics Struct which will be filled out with the
- * current echo metrics.
- * int return 0: OK
- * 12000-12050: error code
- */
-int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics);
-
-/*
- * Gets the current delay metrics for the session.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* handle Pointer to the AEC instance
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int* median Delay median value.
- * int* std Delay standard deviation.
- * float* fraction_poor_delays Fraction of the delay estimates that may
- * cause the AEC to perform poorly.
- *
- * int return 0: OK
- * 12000-12050: error code
- */
-int WebRtcAec_GetDelayMetrics(void* handle,
- int* median,
- int* std,
- float* fraction_poor_delays);
-
-// Returns a pointer to the low level AEC handle.
-//
-// Input:
-// - handle : Pointer to the AEC instance.
-//
-// Return value:
-// - AecCore pointer : NULL for error.
-//
-struct AecCore* WebRtcAec_aec_core(void* handle);
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_PROCESSING_AEC_ECHO_CANCELLATION_H_
diff --git a/modules/audio_processing/aec/echo_cancellation_unittest.cc b/modules/audio_processing/aec/echo_cancellation_unittest.cc
deleted file mode 100644
index b9c89fd..0000000
--- a/modules/audio_processing/aec/echo_cancellation_unittest.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// TODO(bjornv): Make this a comprehensive test.
-
-#include "modules/audio_processing/aec/echo_cancellation.h"
-
-#include <stdlib.h>
-#include <time.h>
-
-#include "modules/audio_processing/aec/aec_core.h"
-#include "rtc_base/checks.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-
-TEST(EchoCancellationTest, CreateAndFreeHasExpectedBehavior) {
- void* handle = WebRtcAec_Create();
- ASSERT_TRUE(handle);
- WebRtcAec_Free(nullptr);
- WebRtcAec_Free(handle);
-}
-
-TEST(EchoCancellationTest, ApplyAecCoreHandle) {
- void* handle = WebRtcAec_Create();
- ASSERT_TRUE(handle);
- EXPECT_TRUE(WebRtcAec_aec_core(NULL) == NULL);
- AecCore* aec_core = WebRtcAec_aec_core(handle);
- EXPECT_TRUE(aec_core != NULL);
- // A simple test to verify that we can set and get a value from the lower
- // level |aec_core| handle.
- int delay = 111;
- WebRtcAec_SetSystemDelay(aec_core, delay);
- EXPECT_EQ(delay, WebRtcAec_system_delay(aec_core));
- WebRtcAec_Free(handle);
-}
-
-} // namespace webrtc
diff --git a/modules/audio_processing/aec/system_delay_unittest.cc b/modules/audio_processing/aec/system_delay_unittest.cc
deleted file mode 100644
index 9c57e8b..0000000
--- a/modules/audio_processing/aec/system_delay_unittest.cc
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "modules/audio_processing/aec/aec_core.h"
-#include "modules/audio_processing/aec/echo_cancellation.h"
-#include "rtc_base/numerics/safe_conversions.h"
-#include "test/gtest.h"
-namespace webrtc {
-namespace {
-
-class SystemDelayTest : public ::testing::Test {
- protected:
- SystemDelayTest();
- void SetUp() override;
- void TearDown() override;
-
- // Initialization of AEC handle with respect to |sample_rate_hz|. Since the
- // device sample rate is unimportant we set that value to 48000 Hz.
- void Init(int sample_rate_hz);
-
- // Makes one render call and one capture call in that specific order.
- void RenderAndCapture(int device_buffer_ms);
-
- // Fills up the far-end buffer with respect to the default device buffer size.
- size_t BufferFillUp();
-
- // Runs and verifies the behavior in a stable startup procedure.
- void RunStableStartup();
-
- // Maps buffer size in ms into samples, taking the unprocessed frame into
- // account.
- int MapBufferSizeToSamples(int size_in_ms, bool extended_filter);
-
- void* handle_;
- Aec* self_;
- size_t samples_per_frame_;
- // Dummy input/output speech data.
- static const int kSamplesPerChunk = 160;
- float far_[kSamplesPerChunk];
- float near_[kSamplesPerChunk];
- float out_[kSamplesPerChunk];
- const float* near_ptr_;
- float* out_ptr_;
-};
-
-SystemDelayTest::SystemDelayTest()
- : handle_(NULL), self_(NULL), samples_per_frame_(0) {
- // Dummy input data are set with more or less arbitrary non-zero values.
- for (int i = 0; i < kSamplesPerChunk; i++) {
- far_[i] = 257.0;
- near_[i] = 514.0;
- }
- memset(out_, 0, sizeof(out_));
- near_ptr_ = near_;
- out_ptr_ = out_;
-}
-
-void SystemDelayTest::SetUp() {
- handle_ = WebRtcAec_Create();
- ASSERT_TRUE(handle_);
- self_ = reinterpret_cast<Aec*>(handle_);
-}
-
-void SystemDelayTest::TearDown() {
- // Free AEC
- WebRtcAec_Free(handle_);
- handle_ = NULL;
-}
-
-// In SWB mode nothing is added to the buffer handling with respect to
-// functionality compared to WB. We therefore only verify behavior in NB and WB.
-static const int kSampleRateHz[] = {8000, 16000};
-static const size_t kNumSampleRates =
- sizeof(kSampleRateHz) / sizeof(*kSampleRateHz);
-
-// Default audio device buffer size used.
-static const int kDeviceBufMs = 100;
-
-// Requirement for a stable device convergence time in ms. Should converge in
-// less than |kStableConvergenceMs|.
-static const int kStableConvergenceMs = 100;
-
-// Maximum convergence time in ms. This means that we should leave the startup
-// phase after |kMaxConvergenceMs| independent of device buffer stability
-// conditions.
-static const int kMaxConvergenceMs = 500;
-
-void SystemDelayTest::Init(int sample_rate_hz) {
- // Initialize AEC
- EXPECT_EQ(0, WebRtcAec_Init(handle_, sample_rate_hz, 48000));
- EXPECT_EQ(0, WebRtcAec_system_delay(self_->aec));
-
- // One frame equals 10 ms of data.
- samples_per_frame_ = static_cast<size_t>(sample_rate_hz / 100);
-}
-
-void SystemDelayTest::RenderAndCapture(int device_buffer_ms) {
- EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_));
- EXPECT_EQ(0, WebRtcAec_Process(handle_, &near_ptr_, 1, &out_ptr_,
- samples_per_frame_, device_buffer_ms, 0));
-}
-
-size_t SystemDelayTest::BufferFillUp() {
- // To make sure we have a full buffer when we verify stability we first fill
- // up the far-end buffer with the same amount as we will report in through
- // Process().
- size_t buffer_size = 0;
- for (int i = 0; i < kDeviceBufMs / 10; i++) {
- EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_));
- buffer_size += samples_per_frame_;
- EXPECT_EQ(static_cast<int>(buffer_size),
- WebRtcAec_system_delay(self_->aec));
- }
- return buffer_size;
-}
-
-void SystemDelayTest::RunStableStartup() {
- // To make sure we have a full buffer when we verify stability we first fill
- // up the far-end buffer with the same amount as we will report in through
- // Process().
- size_t buffer_size = BufferFillUp();
-
- if (WebRtcAec_delay_agnostic_enabled(self_->aec) == 1) {
- // In extended_filter mode we set the buffer size after the first processed
- // 10 ms chunk. Hence, we don't need to wait for the reported system delay
- // values to become stable.
- RenderAndCapture(kDeviceBufMs);
- buffer_size += samples_per_frame_;
- EXPECT_EQ(0, self_->startup_phase);
- } else {
- // A stable device should be accepted and put in a regular process mode
- // within |kStableConvergenceMs|.
- int process_time_ms = 0;
- for (; process_time_ms < kStableConvergenceMs; process_time_ms += 10) {
- RenderAndCapture(kDeviceBufMs);
- buffer_size += samples_per_frame_;
- if (self_->startup_phase == 0) {
- // We have left the startup phase.
- break;
- }
- }
- // Verify convergence time.
- EXPECT_GT(kStableConvergenceMs, process_time_ms);
- }
- // Verify that the buffer has been flushed.
- EXPECT_GE(static_cast<int>(buffer_size), WebRtcAec_system_delay(self_->aec));
-}
-
-int SystemDelayTest::MapBufferSizeToSamples(int size_in_ms,
- bool extended_filter) {
- // If extended_filter is disabled we add an extra 10 ms for the unprocessed
- // frame. That is simply how the algorithm is constructed.
- return static_cast<int>((size_in_ms + (extended_filter ? 0 : 10)) *
- samples_per_frame_ / 10);
-}
-
-// The tests should meet basic requirements and not be adjusted to what is
-// actually implemented. If we don't get good code coverage this way we either
-// lack in tests or have unnecessary code.
-// General requirements:
-// 1) If we add far-end data the system delay should be increased with the same
-// amount we add.
-// 2) If the far-end buffer is full we should flush the oldest data to make room
-// for the new. In this case the system delay is unaffected.
-// 3) There should exist a startup phase in which the buffer size is to be
-// determined. In this phase no cancellation should be performed.
-// 4) Under stable conditions (small variations in device buffer sizes) the AEC
-// should determine an appropriate local buffer size within
-// |kStableConvergenceMs| ms.
-// 5) Under unstable conditions the AEC should make a decision within
-// |kMaxConvergenceMs| ms.
-// 6) If the local buffer runs out of data we should stuff the buffer with older
-// frames.
-// 7) The system delay should within |kMaxConvergenceMs| ms heal from
-// disturbances like drift, data glitches, toggling events and outliers.
-// 8) The system delay should never become negative.
-
-TEST_F(SystemDelayTest, CorrectIncreaseWhenBufferFarend) {
- // When we add data to the AEC buffer the internal system delay should be
- // incremented with the same amount as the size of data.
- // This process should be independent of DA-AEC and extended_filter mode.
- for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
- WebRtcAec_enable_extended_filter(self_->aec, extended_filter);
- EXPECT_EQ(extended_filter, WebRtcAec_extended_filter_enabled(self_->aec));
- for (int da_aec = 0; da_aec <= 1; ++da_aec) {
- WebRtcAec_enable_delay_agnostic(self_->aec, da_aec);
- EXPECT_EQ(da_aec, WebRtcAec_delay_agnostic_enabled(self_->aec));
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- // Loop through a couple of calls to make sure the system delay
- // increments correctly.
- for (int j = 1; j <= 5; j++) {
- EXPECT_EQ(0,
- WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_));
- EXPECT_EQ(static_cast<int>(j * samples_per_frame_),
- WebRtcAec_system_delay(self_->aec));
- }
- }
- }
- }
-}
-
-// TODO(bjornv): Add a test to verify behavior if the far-end buffer is full
-// when adding new data.
-
-TEST_F(SystemDelayTest, CorrectDelayAfterStableStartup) {
- // We run the system in a stable startup. After that we verify that the system
- // delay meets the requirements.
- // This process should be independent of DA-AEC and extended_filter mode.
- for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
- WebRtcAec_enable_extended_filter(self_->aec, extended_filter);
- EXPECT_EQ(extended_filter, WebRtcAec_extended_filter_enabled(self_->aec));
- for (int da_aec = 0; da_aec <= 1; ++da_aec) {
- WebRtcAec_enable_delay_agnostic(self_->aec, da_aec);
- EXPECT_EQ(da_aec, WebRtcAec_delay_agnostic_enabled(self_->aec));
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
-
- // Verify system delay with respect to requirements, i.e., the
- // |system_delay| is in the interval [75%, 100%] of what's reported on
- // the average.
- // In extended_filter mode we target 50% and measure after one processed
- // 10 ms chunk.
- int average_reported_delay =
- static_cast<int>(kDeviceBufMs * samples_per_frame_ / 10);
- EXPECT_GE(average_reported_delay, WebRtcAec_system_delay(self_->aec));
- int lower_bound = WebRtcAec_extended_filter_enabled(self_->aec)
- ? (average_reported_delay / 2 -
- rtc::checked_cast<int>(samples_per_frame_))
- : average_reported_delay * 3 / 4;
- EXPECT_LE(lower_bound, WebRtcAec_system_delay(self_->aec));
- }
- }
- }
-}
-
-TEST_F(SystemDelayTest, CorrectDelayAfterUnstableStartup) {
- // This test does not apply in extended_filter mode, since we only use the
- // the first 10 ms chunk to determine a reasonable buffer size. Neither does
- // it apply if DA-AEC is on because that overrides the startup procedure.
- WebRtcAec_enable_extended_filter(self_->aec, 0);
- EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(self_->aec));
- WebRtcAec_enable_delay_agnostic(self_->aec, 0);
- EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(self_->aec));
-
- // In an unstable system we would start processing after |kMaxConvergenceMs|.
- // On the last frame the AEC buffer is adjusted to 60% of the last reported
- // device buffer size.
- // We construct an unstable system by altering the device buffer size between
- // two values |kDeviceBufMs| +- 25 ms.
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
-
- // To make sure we have a full buffer when we verify stability we first fill
- // up the far-end buffer with the same amount as we will report in on the
- // average through Process().
- size_t buffer_size = BufferFillUp();
-
- int buffer_offset_ms = 25;
- int reported_delay_ms = 0;
- int process_time_ms = 0;
- for (; process_time_ms <= kMaxConvergenceMs; process_time_ms += 10) {
- reported_delay_ms = kDeviceBufMs + buffer_offset_ms;
- RenderAndCapture(reported_delay_ms);
- buffer_size += samples_per_frame_;
- buffer_offset_ms = -buffer_offset_ms;
- if (self_->startup_phase == 0) {
- // We have left the startup phase.
- break;
- }
- }
- // Verify convergence time.
- EXPECT_GE(kMaxConvergenceMs, process_time_ms);
- // Verify that the buffer has been flushed.
- EXPECT_GE(static_cast<int>(buffer_size),
- WebRtcAec_system_delay(self_->aec));
-
- // Verify system delay with respect to requirements, i.e., the
- // |system_delay| is in the interval [60%, 100%] of what's last reported.
- EXPECT_GE(static_cast<int>(reported_delay_ms * samples_per_frame_ / 10),
- WebRtcAec_system_delay(self_->aec));
- EXPECT_LE(
- static_cast<int>(reported_delay_ms * samples_per_frame_ / 10 * 3 / 5),
- WebRtcAec_system_delay(self_->aec));
- }
-}
-
-TEST_F(SystemDelayTest, CorrectDelayAfterStableBufferBuildUp) {
- // This test does not apply in extended_filter mode, since we only use the
- // the first 10 ms chunk to determine a reasonable buffer size. Neither does
- // it apply if DA-AEC is on because that overrides the startup procedure.
- WebRtcAec_enable_extended_filter(self_->aec, 0);
- EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(self_->aec));
- WebRtcAec_enable_delay_agnostic(self_->aec, 0);
- EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(self_->aec));
-
- // In this test we start by establishing the device buffer size during stable
- // conditions, but with an empty internal far-end buffer. Once that is done we
- // verify that the system delay is increased correctly until we have reach an
- // internal buffer size of 75% of what's been reported.
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
-
- // We assume that running |kStableConvergenceMs| calls will put the
- // algorithm in a state where the device buffer size has been determined. We
- // can make that assumption since we have a separate stability test.
- int process_time_ms = 0;
- for (; process_time_ms < kStableConvergenceMs; process_time_ms += 10) {
- EXPECT_EQ(0, WebRtcAec_Process(handle_, &near_ptr_, 1, &out_ptr_,
- samples_per_frame_, kDeviceBufMs, 0));
- }
- // Verify that a buffer size has been established.
- EXPECT_EQ(0, self_->checkBuffSize);
-
- // We now have established the required buffer size. Let us verify that we
- // fill up before leaving the startup phase for normal processing.
- size_t buffer_size = 0;
- size_t target_buffer_size = kDeviceBufMs * samples_per_frame_ / 10 * 3 / 4;
- process_time_ms = 0;
- for (; process_time_ms <= kMaxConvergenceMs; process_time_ms += 10) {
- RenderAndCapture(kDeviceBufMs);
- buffer_size += samples_per_frame_;
- if (self_->startup_phase == 0) {
- // We have left the startup phase.
- break;
- }
- }
- // Verify convergence time.
- EXPECT_GT(kMaxConvergenceMs, process_time_ms);
- // Verify that the buffer has reached the desired size.
- EXPECT_LE(static_cast<int>(target_buffer_size),
- WebRtcAec_system_delay(self_->aec));
-
- // Verify normal behavior (system delay is kept constant) after startup by
- // running a couple of calls to BufferFarend() and Process().
- for (int j = 0; j < 6; j++) {
- int system_delay_before_calls = WebRtcAec_system_delay(self_->aec);
- RenderAndCapture(kDeviceBufMs);
- EXPECT_EQ(system_delay_before_calls, WebRtcAec_system_delay(self_->aec));
- }
- }
-}
-
-TEST_F(SystemDelayTest, CorrectDelayWhenBufferUnderrun) {
- // Here we test a buffer under run scenario. If we keep on calling
- // WebRtcAec_Process() we will finally run out of data, but should
- // automatically stuff the buffer. We verify this behavior by checking if the
- // system delay goes negative.
- // This process should be independent of DA-AEC and extended_filter mode.
- for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
- WebRtcAec_enable_extended_filter(self_->aec, extended_filter);
- EXPECT_EQ(extended_filter, WebRtcAec_extended_filter_enabled(self_->aec));
- for (int da_aec = 0; da_aec <= 1; ++da_aec) {
- WebRtcAec_enable_delay_agnostic(self_->aec, da_aec);
- EXPECT_EQ(da_aec, WebRtcAec_delay_agnostic_enabled(self_->aec));
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
-
- // The AEC has now left the Startup phase. We now have at most
- // |kStableConvergenceMs| in the buffer. Keep on calling Process() until
- // we run out of data and verify that the system delay is non-negative.
- for (int j = 0; j <= kStableConvergenceMs; j += 10) {
- EXPECT_EQ(0, WebRtcAec_Process(handle_, &near_ptr_, 1, &out_ptr_,
- samples_per_frame_, kDeviceBufMs, 0));
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
- }
- }
- }
- }
-}
-
-TEST_F(SystemDelayTest, CorrectDelayDuringDrift) {
- // This drift test should verify that the system delay is never exceeding the
- // device buffer. The drift is simulated by decreasing the reported device
- // buffer size by 1 ms every 100 ms. If the device buffer size goes below 30
- // ms we jump (add) 10 ms to give a repeated pattern.
-
- // This process should be independent of DA-AEC and extended_filter mode.
- for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
- WebRtcAec_enable_extended_filter(self_->aec, extended_filter);
- EXPECT_EQ(extended_filter, WebRtcAec_extended_filter_enabled(self_->aec));
- for (int da_aec = 0; da_aec <= 1; ++da_aec) {
- WebRtcAec_enable_delay_agnostic(self_->aec, da_aec);
- EXPECT_EQ(da_aec, WebRtcAec_delay_agnostic_enabled(self_->aec));
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
-
- // We have left the startup phase and proceed with normal processing.
- int jump = 0;
- for (int j = 0; j < 1000; j++) {
- // Drift = -1 ms per 100 ms of data.
- int device_buf_ms = kDeviceBufMs - (j / 10) + jump;
- int device_buf =
- MapBufferSizeToSamples(device_buf_ms, extended_filter == 1);
-
- if (device_buf_ms < 30) {
- // Add 10 ms data, taking affect next frame.
- jump += 10;
- }
- RenderAndCapture(device_buf_ms);
-
- // Verify that the system delay does not exceed the device buffer.
- EXPECT_GE(device_buf, WebRtcAec_system_delay(self_->aec));
-
- // Verify that the system delay is non-negative.
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
- }
- }
- }
- }
-}
-
-TEST_F(SystemDelayTest, ShouldRecoverAfterGlitch) {
- // This glitch test should verify that the system delay recovers if there is
- // a glitch in data. The data glitch is constructed as 200 ms of buffering
- // after which the stable procedure continues. The glitch is never reported by
- // the device.
- // The system is said to be in a non-causal state if the difference between
- // the device buffer and system delay is less than a block (64 samples).
-
- // This process should be independent of DA-AEC and extended_filter mode.
- for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
- WebRtcAec_enable_extended_filter(self_->aec, extended_filter);
- EXPECT_EQ(extended_filter, WebRtcAec_extended_filter_enabled(self_->aec));
- for (int da_aec = 0; da_aec <= 1; ++da_aec) {
- WebRtcAec_enable_delay_agnostic(self_->aec, da_aec);
- EXPECT_EQ(da_aec, WebRtcAec_delay_agnostic_enabled(self_->aec));
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
- int device_buf =
- MapBufferSizeToSamples(kDeviceBufMs, extended_filter == 1);
- // Glitch state.
- for (int j = 0; j < 20; j++) {
- EXPECT_EQ(0,
- WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_));
- // No need to verify system delay, since that is done in a separate
- // test.
- }
- // Verify that we are in a non-causal state, i.e.,
- // |system_delay| > |device_buf|.
- EXPECT_LT(device_buf, WebRtcAec_system_delay(self_->aec));
-
- // Recover state. Should recover at least 4 ms of data per 10 ms, hence
- // a glitch of 200 ms will take at most 200 * 10 / 4 = 500 ms to recover
- // from.
- bool non_causal = true; // We are currently in a non-causal state.
- for (int j = 0; j < 50; j++) {
- int system_delay_before = WebRtcAec_system_delay(self_->aec);
- RenderAndCapture(kDeviceBufMs);
- int system_delay_after = WebRtcAec_system_delay(self_->aec);
- // We have recovered if
- // |device_buf| - |system_delay_after| >= PART_LEN (1 block).
- // During recovery, |system_delay_after| < |system_delay_before|,
- // otherwise they are equal.
- if (non_causal) {
- EXPECT_LT(system_delay_after, system_delay_before);
- if (device_buf - system_delay_after >= PART_LEN) {
- non_causal = false;
- }
- } else {
- EXPECT_EQ(system_delay_before, system_delay_after);
- }
- // Verify that the system delay is non-negative.
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
- }
- // Check that we have recovered.
- EXPECT_FALSE(non_causal);
- }
- }
- }
-}
-
-TEST_F(SystemDelayTest, UnaffectedWhenSpuriousDeviceBufferValues) {
- // This test does not apply in extended_filter mode, since we only use the
- // the first 10 ms chunk to determine a reasonable buffer size.
- const int extended_filter = 0;
- WebRtcAec_enable_extended_filter(self_->aec, extended_filter);
- EXPECT_EQ(extended_filter, WebRtcAec_extended_filter_enabled(self_->aec));
-
- // Should be DA-AEC independent.
- for (int da_aec = 0; da_aec <= 1; ++da_aec) {
- WebRtcAec_enable_delay_agnostic(self_->aec, da_aec);
- EXPECT_EQ(da_aec, WebRtcAec_delay_agnostic_enabled(self_->aec));
- // This spurious device buffer data test aims at verifying that the system
- // delay is unaffected by large outliers.
- // The system is said to be in a non-causal state if the difference between
- // the device buffer and system delay is less than a block (64 samples).
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
- int device_buf =
- MapBufferSizeToSamples(kDeviceBufMs, extended_filter == 1);
-
- // Normal state. We are currently not in a non-causal state.
- bool non_causal = false;
-
- // Run 1 s and replace device buffer size with 500 ms every 100 ms.
- for (int j = 0; j < 100; j++) {
- int system_delay_before_calls = WebRtcAec_system_delay(self_->aec);
- int device_buf_ms = j % 10 == 0 ? 500 : kDeviceBufMs;
- RenderAndCapture(device_buf_ms);
-
- // Check for non-causality.
- if (device_buf - WebRtcAec_system_delay(self_->aec) < PART_LEN) {
- non_causal = true;
- }
- EXPECT_FALSE(non_causal);
- EXPECT_EQ(system_delay_before_calls,
- WebRtcAec_system_delay(self_->aec));
-
- // Verify that the system delay is non-negative.
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
- }
- }
- }
-}
-
-TEST_F(SystemDelayTest, CorrectImpactWhenTogglingDeviceBufferValues) {
- // This test aims at verifying that the system delay is "unaffected" by
- // toggling values reported by the device.
- // The test is constructed such that every other device buffer value is zero
- // and then 2 * |kDeviceBufMs|, hence the size is constant on the average. The
- // zero values will force us into a non-causal state and thereby lowering the
- // system delay until we basically run out of data. Once that happens the
- // buffer will be stuffed.
- // TODO(bjornv): This test will have a better impact if we verified that the
- // delay estimate goes up when the system delay goes down to meet the average
- // device buffer size.
-
- // This test does not apply if DA-AEC is enabled and extended_filter mode
- // disabled.
- for (int extended_filter = 0; extended_filter <= 1; ++extended_filter) {
- WebRtcAec_enable_extended_filter(self_->aec, extended_filter);
- EXPECT_EQ(extended_filter, WebRtcAec_extended_filter_enabled(self_->aec));
- for (int da_aec = 0; da_aec <= 1; ++da_aec) {
- WebRtcAec_enable_delay_agnostic(self_->aec, da_aec);
- EXPECT_EQ(da_aec, WebRtcAec_delay_agnostic_enabled(self_->aec));
- if (extended_filter == 0 && da_aec == 1) {
- continue;
- }
- for (size_t i = 0; i < kNumSampleRates; i++) {
- Init(kSampleRateHz[i]);
- RunStableStartup();
- const int device_buf =
- MapBufferSizeToSamples(kDeviceBufMs, extended_filter == 1);
-
- // Normal state. We are currently not in a non-causal state.
- bool non_causal = false;
-
- // Loop through 100 frames (both render and capture), which equals 1 s
- // of data. Every odd frame we set the device buffer size to
- // 2 * |kDeviceBufMs| and even frames we set the device buffer size to
- // zero.
- for (int j = 0; j < 100; j++) {
- int system_delay_before_calls = WebRtcAec_system_delay(self_->aec);
- int device_buf_ms = 2 * (j % 2) * kDeviceBufMs;
- RenderAndCapture(device_buf_ms);
-
- // Check for non-causality, compared with the average device buffer
- // size.
- non_causal |= (device_buf - WebRtcAec_system_delay(self_->aec) < 64);
- EXPECT_GE(system_delay_before_calls,
- WebRtcAec_system_delay(self_->aec));
-
- // Verify that the system delay is non-negative.
- EXPECT_LE(0, WebRtcAec_system_delay(self_->aec));
- }
- // Verify we are not in a non-causal state.
- EXPECT_FALSE(non_causal);
- }
- }
- }
-}
-
-} // namespace
-} // namespace webrtc
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 97a8379..4d9cdb4 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -155,7 +155,6 @@
bool AudioProcessingImpl::SubmoduleStates::Update(
bool high_pass_filter_enabled,
- bool echo_canceller_enabled,
bool mobile_echo_controller_enabled,
bool residual_echo_detector_enabled,
bool noise_suppressor_enabled,
@@ -167,7 +166,6 @@
bool transient_suppressor_enabled) {
bool changed = false;
changed |= (high_pass_filter_enabled != high_pass_filter_enabled_);
- changed |= (echo_canceller_enabled != echo_canceller_enabled_);
changed |=
(mobile_echo_controller_enabled != mobile_echo_controller_enabled_);
changed |=
@@ -182,7 +180,6 @@
changed |= (transient_suppressor_enabled != transient_suppressor_enabled_);
if (changed) {
high_pass_filter_enabled_ = high_pass_filter_enabled;
- echo_canceller_enabled_ = echo_canceller_enabled;
mobile_echo_controller_enabled_ = mobile_echo_controller_enabled;
residual_echo_detector_enabled_ = residual_echo_detector_enabled;
noise_suppressor_enabled_ = noise_suppressor_enabled;
@@ -212,9 +209,8 @@
bool AudioProcessingImpl::SubmoduleStates::CaptureMultiBandProcessingActive(
bool ec_processing_active) const {
- return high_pass_filter_enabled_ || echo_canceller_enabled_ ||
- mobile_echo_controller_enabled_ || noise_suppressor_enabled_ ||
- adaptive_gain_controller_enabled_ ||
+ return high_pass_filter_enabled_ || mobile_echo_controller_enabled_ ||
+ noise_suppressor_enabled_ || adaptive_gain_controller_enabled_ ||
(echo_controller_enabled_ && ec_processing_active);
}
@@ -230,9 +226,8 @@
bool AudioProcessingImpl::SubmoduleStates::RenderMultiBandSubModulesActive()
const {
- return RenderMultiBandProcessingActive() || echo_canceller_enabled_ ||
- mobile_echo_controller_enabled_ || adaptive_gain_controller_enabled_ ||
- echo_controller_enabled_;
+ return RenderMultiBandProcessingActive() || mobile_echo_controller_enabled_ ||
+ adaptive_gain_controller_enabled_ || echo_controller_enabled_;
}
bool AudioProcessingImpl::SubmoduleStates::RenderFullBandProcessingActive()
@@ -246,8 +241,8 @@
}
bool AudioProcessingImpl::SubmoduleStates::HighPassFilteringRequired() const {
- return high_pass_filter_enabled_ || echo_canceller_enabled_ ||
- mobile_echo_controller_enabled_ || noise_suppressor_enabled_;
+ return high_pass_filter_enabled_ || mobile_echo_controller_enabled_ ||
+ noise_suppressor_enabled_;
}
AudioProcessingBuilder::AudioProcessingBuilder() = default;
@@ -638,12 +633,7 @@
const bool aec_config_changed =
config_.echo_canceller.enabled != config.echo_canceller.enabled ||
- config_.echo_canceller.use_legacy_aec !=
- config.echo_canceller.use_legacy_aec ||
- config_.echo_canceller.mobile_mode != config.echo_canceller.mobile_mode ||
- (config_.echo_canceller.enabled && config.echo_canceller.use_legacy_aec &&
- config_.echo_canceller.legacy_moderate_suppression_level !=
- config.echo_canceller.legacy_moderate_suppression_level);
+ config_.echo_canceller.mobile_mode != config.echo_canceller.mobile_mode;
const bool agc1_config_changed =
config_.gain_controller1.enabled != config.gain_controller1.enabled ||
@@ -668,6 +658,9 @@
config_ = config;
+ // Ensure that this deprecated setting is not used by mistake.
+ RTC_DCHECK(!config_.echo_canceller.use_legacy_aec);
+
if (aec_config_changed) {
InitializeEchoController();
}
@@ -737,13 +730,6 @@
rtc::CritScope cs_render(&crit_render_);
rtc::CritScope cs_capture(&crit_capture_);
- capture_nonlocked_.use_aec2_extended_filter =
- config.Get<ExtendedFilter>().enabled;
- capture_nonlocked_.use_aec2_delay_agnostic =
- config.Get<DelayAgnostic>().enabled;
- capture_nonlocked_.use_aec2_refined_adaptive_filter =
- config.Get<RefinedAdaptiveFilter>().enabled;
-
if (capture_.transient_suppressor_enabled !=
config.Get<ExperimentalNs>().enabled) {
capture_.transient_suppressor_enabled =
@@ -997,23 +983,6 @@
void AudioProcessingImpl::QueueBandedRenderAudio(AudioBuffer* audio) {
RTC_DCHECK_GE(160, audio->num_frames_per_band());
- // Insert the samples into the queue.
- if (submodules_.echo_cancellation) {
- RTC_DCHECK(aec_render_signal_queue_);
- EchoCancellationImpl::PackRenderAudioBuffer(audio, num_output_channels(),
- num_reverse_channels(),
- &aec_render_queue_buffer_);
-
- if (!aec_render_signal_queue_->Insert(&aec_render_queue_buffer_)) {
- // The data queue is full and needs to be emptied.
- EmptyQueuedRenderAudio();
-
- // Retry the insert (should always work).
- bool result = aec_render_signal_queue_->Insert(&aec_render_queue_buffer_);
- RTC_DCHECK(result);
- }
- }
-
if (submodules_.echo_control_mobile) {
EchoControlMobileImpl::PackRenderAudioBuffer(audio, num_output_channels(),
num_reverse_channels(),
@@ -1110,14 +1079,6 @@
void AudioProcessingImpl::EmptyQueuedRenderAudio() {
rtc::CritScope cs_capture(&crit_capture_);
- if (submodules_.echo_cancellation) {
- RTC_DCHECK(aec_render_signal_queue_);
- while (aec_render_signal_queue_->Remove(&aec_capture_queue_buffer_)) {
- submodules_.echo_cancellation->ProcessRenderAudio(
- aec_capture_queue_buffer_);
- }
- }
-
if (submodules_.echo_control_mobile) {
RTC_DCHECK(aecm_render_signal_queue_);
while (aecm_render_signal_queue_->Remove(&aecm_capture_queue_buffer_)) {
@@ -1236,7 +1197,6 @@
// TODO(peah): Simplify once the public API Enable functions for these
// are moved to APM.
RTC_DCHECK_LE(!!submodules_.echo_controller +
- !!submodules_.echo_cancellation +
!!submodules_.echo_control_mobile,
1);
@@ -1350,15 +1310,6 @@
AudioBuffer* linear_aec_buffer = capture_.linear_aec_output.get();
submodules_.echo_controller->ProcessCapture(
capture_buffer, linear_aec_buffer, capture_.echo_path_gain_change);
- } else if (submodules_.echo_cancellation) {
- // Ensure that the stream delay was set before the call to the
- // AEC ProcessCaptureAudio function.
- if (!was_stream_delay_set()) {
- return AudioProcessing::kStreamParameterNotSetError;
- }
-
- RETURN_ON_ERR(submodules_.echo_cancellation->ProcessCaptureAudio(
- capture_buffer, stream_delay_ms()));
}
if (submodules_.noise_suppressor) {
@@ -1387,8 +1338,7 @@
}
// TODO(peah): Add reporting from AEC3 whether there is echo.
RETURN_ON_ERR(submodules_.gain_control->ProcessCaptureAudio(
- capture_buffer, submodules_.echo_cancellation &&
- submodules_.echo_cancellation->stream_has_echo()));
+ capture_buffer, /*stream_has_echo*/ false));
if (submodule_states_.CaptureMultiBandProcessingPresent() &&
SampleRateSupportsMultiBand(
@@ -1754,7 +1704,6 @@
return capture_.stats;
}
AudioProcessingStats stats = capture_.stats;
- EchoCancellationImpl::Metrics metrics;
if (submodules_.echo_controller) {
auto ec_metrics = submodules_.echo_controller->GetMetrics();
stats.echo_return_loss = ec_metrics.echo_return_loss;
@@ -1788,8 +1737,8 @@
bool AudioProcessingImpl::UpdateActiveSubmoduleStates() {
return submodule_states_.Update(
- config_.high_pass_filter.enabled, !!submodules_.echo_cancellation,
- !!submodules_.echo_control_mobile, config_.residual_echo_detector.enabled,
+ config_.high_pass_filter.enabled, !!submodules_.echo_control_mobile,
+ config_.residual_echo_detector.enabled,
!!submodules_.legacy_noise_suppressor || !!submodules_.noise_suppressor,
submodules_.gain_control->is_enabled(), config_.gain_controller2.enabled,
config_.pre_amplifier.enabled, capture_nonlocked_.echo_controller_enabled,
@@ -1831,8 +1780,7 @@
void AudioProcessingImpl::InitializeEchoController() {
bool use_echo_controller =
echo_control_factory_ ||
- (config_.echo_canceller.enabled && !config_.echo_canceller.mobile_mode &&
- !config_.echo_canceller.use_legacy_aec);
+ (config_.echo_canceller.enabled && !config_.echo_canceller.mobile_mode);
if (use_echo_controller) {
// Create and activate the echo controller.
@@ -1863,8 +1811,6 @@
capture_nonlocked_.echo_controller_enabled = true;
- submodules_.echo_cancellation.reset();
- aec_render_signal_queue_.reset();
submodules_.echo_control_mobile.reset();
aecm_render_signal_queue_.reset();
return;
@@ -1875,8 +1821,6 @@
capture_.linear_aec_output.reset();
if (!config_.echo_canceller.enabled) {
- submodules_.echo_cancellation.reset();
- aec_render_signal_queue_.reset();
submodules_.echo_control_mobile.reset();
aecm_render_signal_queue_.reset();
return;
@@ -1905,46 +1849,11 @@
submodules_.echo_control_mobile->Initialize(proc_split_sample_rate_hz(),
num_reverse_channels(),
num_output_channels());
-
- submodules_.echo_cancellation.reset();
- aec_render_signal_queue_.reset();
return;
}
submodules_.echo_control_mobile.reset();
aecm_render_signal_queue_.reset();
-
- // Create and activate AEC2.
- submodules_.echo_cancellation.reset(new EchoCancellationImpl());
- submodules_.echo_cancellation->SetExtraOptions(
- capture_nonlocked_.use_aec2_extended_filter,
- capture_nonlocked_.use_aec2_delay_agnostic,
- capture_nonlocked_.use_aec2_refined_adaptive_filter);
-
- size_t element_max_size =
- std::max(static_cast<size_t>(1),
- kMaxAllowedValuesOfSamplesPerBand *
- EchoCancellationImpl::NumCancellersRequired(
- num_output_channels(), num_reverse_channels()));
-
- std::vector<float> template_queue_element(element_max_size);
-
- aec_render_signal_queue_.reset(
- new SwapQueue<std::vector<float>, RenderQueueItemVerifier<float>>(
- kMaxNumFramesToBuffer, template_queue_element,
- RenderQueueItemVerifier<float>(element_max_size)));
-
- aec_render_queue_buffer_.resize(element_max_size);
- aec_capture_queue_buffer_.resize(element_max_size);
-
- submodules_.echo_cancellation->Initialize(
- proc_sample_rate_hz(), num_reverse_channels(), num_output_channels(),
- num_proc_channels());
-
- submodules_.echo_cancellation->set_suppression_level(
- config_.echo_canceller.legacy_moderate_suppression_level
- ? EchoCancellationImpl::SuppressionLevel::kModerateSuppression
- : EchoCancellationImpl::SuppressionLevel::kHighSuppression);
}
void AudioProcessingImpl::InitializeGainController2() {
@@ -2039,10 +1948,6 @@
}
std::string experiments_description = "";
- if (submodules_.echo_cancellation) {
- experiments_description +=
- submodules_.echo_cancellation->GetExperimentsDescription();
- }
// TODO(peah): Add semicolon-separated concatenations of experiment
// descriptions for other submodules.
if (constants_.agc_clipped_level_min != kClippedLevelMin) {
@@ -2058,19 +1963,9 @@
InternalAPMConfig apm_config;
apm_config.aec_enabled = config_.echo_canceller.enabled;
- apm_config.aec_delay_agnostic_enabled =
- submodules_.echo_cancellation &&
- submodules_.echo_cancellation->is_delay_agnostic_enabled();
- apm_config.aec_drift_compensation_enabled =
- submodules_.echo_cancellation &&
- submodules_.echo_cancellation->is_drift_compensation_enabled();
- apm_config.aec_extended_filter_enabled =
- submodules_.echo_cancellation &&
- submodules_.echo_cancellation->is_extended_filter_enabled();
- apm_config.aec_suppression_level =
- submodules_.echo_cancellation
- ? static_cast<int>(submodules_.echo_cancellation->suppression_level())
- : 0;
+ apm_config.aec_delay_agnostic_enabled = false;
+ apm_config.aec_extended_filter_enabled = false;
+ apm_config.aec_suppression_level = 0;
apm_config.aecm_enabled = !!submodules_.echo_control_mobile;
apm_config.aecm_comfort_noise_enabled =
@@ -2151,10 +2046,7 @@
RTC_DCHECK(aec_dump_);
AecDump::AudioProcessingState audio_proc_state;
audio_proc_state.delay = capture_nonlocked_.stream_delay_ms;
- audio_proc_state.drift =
- submodules_.echo_cancellation
- ? submodules_.echo_cancellation->stream_drift_samples()
- : 0;
+ audio_proc_state.drift = 0;
audio_proc_state.level = recommended_stream_analog_level();
audio_proc_state.keypress = capture_.key_pressed;
aec_dump_->AddAudioProcessingState(audio_proc_state);
diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h
index e5d0573..dcc2fa6 100644
--- a/modules/audio_processing/audio_processing_impl.h
+++ b/modules/audio_processing/audio_processing_impl.h
@@ -20,7 +20,6 @@
#include "modules/audio_processing/agc/agc_manager_direct.h"
#include "modules/audio_processing/agc/gain_control.h"
#include "modules/audio_processing/audio_buffer.h"
-#include "modules/audio_processing/echo_cancellation_impl.h"
#include "modules/audio_processing/echo_control_mobile_impl.h"
#include "modules/audio_processing/gain_control_impl.h"
#include "modules/audio_processing/gain_controller2.h"
@@ -171,7 +170,6 @@
bool capture_analyzer_enabled);
// Updates the submodule state and returns true if it has changed.
bool Update(bool high_pass_filter_enabled,
- bool echo_canceller_enabled,
bool mobile_echo_controller_enabled,
bool residual_echo_detector_enabled,
bool noise_suppressor_enabled,
@@ -196,7 +194,6 @@
const bool render_pre_processor_enabled_ = false;
const bool capture_analyzer_enabled_ = false;
bool high_pass_filter_enabled_ = false;
- bool echo_canceller_enabled_ = false;
bool mobile_echo_controller_enabled_ = false;
bool residual_echo_detector_enabled_ = false;
bool noise_suppressor_enabled_ = false;
@@ -337,7 +334,6 @@
std::unique_ptr<GainController2> gain_controller2;
std::unique_ptr<HighPassFilter> high_pass_filter;
rtc::scoped_refptr<EchoDetector> echo_detector;
- std::unique_ptr<EchoCancellationImpl> echo_cancellation;
std::unique_ptr<EchoControl> echo_controller;
std::unique_ptr<EchoControlMobileImpl> echo_control_mobile;
std::unique_ptr<NoiseSuppression> legacy_noise_suppressor;
@@ -436,9 +432,6 @@
int split_rate;
int stream_delay_ms;
bool echo_controller_enabled = false;
- bool use_aec2_extended_filter = false;
- bool use_aec2_delay_agnostic = false;
- bool use_aec2_refined_adaptive_filter = false;
} capture_nonlocked_;
struct ApmRenderState {
@@ -469,8 +462,6 @@
int capture_rms_interval_counter_ RTC_GUARDED_BY(crit_capture_) = 0;
// Lock protection not needed.
- std::unique_ptr<SwapQueue<std::vector<float>, RenderQueueItemVerifier<float>>>
- aec_render_signal_queue_;
std::unique_ptr<
SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>>
aecm_render_signal_queue_;
diff --git a/modules/audio_processing/audio_processing_impl_locking_unittest.cc b/modules/audio_processing/audio_processing_impl_locking_unittest.cc
index 9aa3f7a..d09e979 100644
--- a/modules/audio_processing/audio_processing_impl_locking_unittest.cc
+++ b/modules/audio_processing/audio_processing_impl_locking_unittest.cc
@@ -551,17 +551,6 @@
apm_config.voice_detection.enabled = true;
apm_config.level_estimation.enabled = true;
apm_->ApplyConfig(apm_config);
-
- Config config;
- config.Set<ExtendedFilter>(
- new ExtendedFilter(test_config_.aec_type ==
- AecType::BasicWebRtcAecSettingsWithExtentedFilter));
-
- config.Set<DelayAgnostic>(
- new DelayAgnostic(test_config_.aec_type ==
- AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec));
-
- apm_->SetExtraOptions(config);
}
void AudioProcessingImplLockTest::TearDown() {
diff --git a/modules/audio_processing/audio_processing_performance_unittest.cc b/modules/audio_processing/audio_processing_performance_unittest.cc
index ebb2480..2ed6f17 100644
--- a/modules/audio_processing/audio_processing_performance_unittest.cc
+++ b/modules/audio_processing/audio_processing_performance_unittest.cc
@@ -483,12 +483,6 @@
apm->ApplyConfig(apm_config);
};
- // Lambda function for adding default desktop APM settings to a config.
- auto add_default_desktop_config = [](Config* config) {
- config->Set<ExtendedFilter>(new ExtendedFilter(true));
- config->Set<DelayAgnostic>(new DelayAgnostic(true));
- };
-
int num_capture_channels = 1;
switch (simulation_config_.simulation_settings) {
case SettingsType::kDefaultApmMobile: {
@@ -499,7 +493,6 @@
}
case SettingsType::kDefaultApmDesktop: {
Config config;
- add_default_desktop_config(&config);
apm_.reset(AudioProcessingBuilder().Create(config));
ASSERT_TRUE(!!apm_);
set_default_desktop_apm_runtime_settings(apm_.get());
@@ -514,8 +507,6 @@
}
case SettingsType::kDefaultApmDesktopWithoutDelayAgnostic: {
Config config;
- config.Set<ExtendedFilter>(new ExtendedFilter(true));
- config.Set<DelayAgnostic>(new DelayAgnostic(false));
apm_.reset(AudioProcessingBuilder().Create(config));
ASSERT_TRUE(!!apm_);
set_default_desktop_apm_runtime_settings(apm_.get());
@@ -524,8 +515,6 @@
}
case SettingsType::kDefaultApmDesktopWithoutExtendedFilter: {
Config config;
- config.Set<ExtendedFilter>(new ExtendedFilter(false));
- config.Set<DelayAgnostic>(new DelayAgnostic(true));
apm_.reset(AudioProcessingBuilder().Create(config));
ASSERT_TRUE(!!apm_);
set_default_desktop_apm_runtime_settings(apm_.get());
diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc
index 8f29a73..0fd07bf 100644
--- a/modules/audio_processing/audio_processing_unittest.cc
+++ b/modules/audio_processing/audio_processing_unittest.cc
@@ -1536,8 +1536,6 @@
Config config;
config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
- config.Set<ExtendedFilter>(
- new ExtendedFilter(test->use_aec_extended_filter()));
apm_.reset(AudioProcessingBuilder().Create(config));
EnableAllComponents();
diff --git a/modules/audio_processing/echo_cancellation_bit_exact_unittest.cc b/modules/audio_processing/echo_cancellation_bit_exact_unittest.cc
deleted file mode 100644
index c8c665e..0000000
--- a/modules/audio_processing/echo_cancellation_bit_exact_unittest.cc
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-#include <vector>
-
-#include "api/array_view.h"
-#include "modules/audio_processing/audio_buffer.h"
-#include "modules/audio_processing/echo_cancellation_impl.h"
-#include "modules/audio_processing/test/audio_buffer_tools.h"
-#include "modules/audio_processing/test/bitexactness_tools.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-namespace {
-
-const int kNumFramesToProcess = 100;
-
-void SetupComponent(int sample_rate_hz,
- EchoCancellationImpl::SuppressionLevel suppression_level,
- bool drift_compensation_enabled,
- EchoCancellationImpl* echo_canceller) {
- echo_canceller->Initialize(sample_rate_hz, 1, 1, 1);
- echo_canceller->set_suppression_level(suppression_level);
- echo_canceller->enable_drift_compensation(drift_compensation_enabled);
-
- Config config;
- config.Set<DelayAgnostic>(new DelayAgnostic(true));
- config.Set<ExtendedFilter>(new ExtendedFilter(true));
- echo_canceller->SetExtraOptions(true, true, false);
-}
-
-void ProcessOneFrame(int sample_rate_hz,
- int stream_delay_ms,
- bool drift_compensation_enabled,
- int stream_drift_samples,
- AudioBuffer* render_audio_buffer,
- AudioBuffer* capture_audio_buffer,
- EchoCancellationImpl* echo_canceller) {
- if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
- render_audio_buffer->SplitIntoFrequencyBands();
- capture_audio_buffer->SplitIntoFrequencyBands();
- }
-
- std::vector<float> render_audio;
- EchoCancellationImpl::PackRenderAudioBuffer(
- render_audio_buffer, 1, render_audio_buffer->num_channels(),
- &render_audio);
- echo_canceller->ProcessRenderAudio(render_audio);
-
- if (drift_compensation_enabled) {
- echo_canceller->set_stream_drift_samples(stream_drift_samples);
- }
-
- echo_canceller->ProcessCaptureAudio(capture_audio_buffer, stream_delay_ms);
-
- if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
- capture_audio_buffer->MergeFrequencyBands();
- }
-}
-
-void RunBitexactnessTest(
- int sample_rate_hz,
- size_t num_channels,
- int stream_delay_ms,
- bool drift_compensation_enabled,
- int stream_drift_samples,
- EchoCancellationImpl::SuppressionLevel suppression_level,
- bool stream_has_echo_reference,
- const rtc::ArrayView<const float>& output_reference) {
- EchoCancellationImpl echo_canceller;
- SetupComponent(sample_rate_hz, suppression_level, drift_compensation_enabled,
- &echo_canceller);
-
- const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
- const StreamConfig render_config(sample_rate_hz, num_channels, false);
- AudioBuffer render_buffer(
- render_config.sample_rate_hz(), render_config.num_channels(),
- render_config.sample_rate_hz(), 1, render_config.sample_rate_hz(), 1);
- test::InputAudioFile render_file(
- test::GetApmRenderTestVectorFileName(sample_rate_hz));
- std::vector<float> render_input(samples_per_channel * num_channels);
-
- const StreamConfig capture_config(sample_rate_hz, num_channels, false);
- AudioBuffer capture_buffer(
- capture_config.sample_rate_hz(), capture_config.num_channels(),
- capture_config.sample_rate_hz(), 1, capture_config.sample_rate_hz(), 1);
- test::InputAudioFile capture_file(
- test::GetApmCaptureTestVectorFileName(sample_rate_hz));
- std::vector<float> capture_input(samples_per_channel * num_channels);
-
- for (int frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) {
- ReadFloatSamplesFromStereoFile(samples_per_channel, num_channels,
- &render_file, render_input);
- ReadFloatSamplesFromStereoFile(samples_per_channel, num_channels,
- &capture_file, capture_input);
-
- test::CopyVectorToAudioBuffer(render_config, render_input, &render_buffer);
- test::CopyVectorToAudioBuffer(capture_config, capture_input,
- &capture_buffer);
-
- ProcessOneFrame(sample_rate_hz, stream_delay_ms, drift_compensation_enabled,
- stream_drift_samples, &render_buffer, &capture_buffer,
- &echo_canceller);
- }
-
- // Extract and verify the test results.
- std::vector<float> capture_output;
- test::ExtractVectorFromAudioBuffer(capture_config, &capture_buffer,
- &capture_output);
-
- EXPECT_EQ(stream_has_echo_reference, echo_canceller.stream_has_echo());
-
- // Compare the output with the reference. Only the first values of the output
- // from last frame processed are compared in order not having to specify all
- // preceeding frames as testvectors. As the algorithm being tested has a
- // memory, testing only the last frame implicitly also tests the preceeding
- // frames.
- const float kElementErrorBound = 1.0f / 32768.0f;
- EXPECT_TRUE(test::VerifyDeinterleavedArray(
- capture_config.num_frames(), capture_config.num_channels(),
- output_reference, capture_output, kElementErrorBound));
-}
-
-const bool kStreamHasEchoReference = true;
-
-} // namespace
-
-// TODO(peah): Activate all these tests for ARM and ARM64 once the issue on the
-// Chromium ARM and ARM64 boths have been identified. This is tracked in the
-// issue https://bugs.chromium.org/p/webrtc/issues/detail?id=5711.
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono8kHz_HighLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono8kHz_HighLevel_NoDrift_StreamDelay0) {
-#endif
- const float kOutputReference[] = {-0.000646f, -0.001525f, 0.002688f};
- RunBitexactnessTest(8000, 1, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono16kHz_HighLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono16kHz_HighLevel_NoDrift_StreamDelay0) {
-#endif
- const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
- RunBitexactnessTest(16000, 1, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono32kHz_HighLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono32kHz_HighLevel_NoDrift_StreamDelay0) {
-#endif
- const float kOutputReference[] = {-0.000671f, 0.000061f, -0.000031f};
- RunBitexactnessTest(32000, 1, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono48kHz_HighLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono48kHz_HighLevel_NoDrift_StreamDelay0) {
-#endif
- const float kOutputReference[] = {-0.001403f, -0.001411f, -0.000755f};
- RunBitexactnessTest(48000, 1, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono16kHz_LowLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono16kHz_LowLevel_NoDrift_StreamDelay0) {
-#endif
-#if defined(WEBRTC_MAC)
- const float kOutputReference[] = {-0.000145f, 0.000179f, 0.000917f};
-#else
- const float kOutputReference[] = {-0.000009f, 0.000363f, 0.001094f};
-#endif
- RunBitexactnessTest(16000, 1, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kLowSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono16kHz_ModerateLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono16kHz_ModerateLevel_NoDrift_StreamDelay0) {
-#endif
- const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
- RunBitexactnessTest(
- 16000, 1, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kModerateSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono16kHz_HighLevel_NoDrift_StreamDelay10) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono16kHz_HighLevel_NoDrift_StreamDelay10) {
-#endif
- const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
- RunBitexactnessTest(16000, 1, 10, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono16kHz_HighLevel_NoDrift_StreamDelay20) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono16kHz_HighLevel_NoDrift_StreamDelay20) {
-#endif
- const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
- RunBitexactnessTest(16000, 1, 20, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono16kHz_HighLevel_Drift0_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono16kHz_HighLevel_Drift0_StreamDelay0) {
-#endif
- const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
- RunBitexactnessTest(16000, 1, 0, true, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Mono16kHz_HighLevel_Drift5_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Mono16kHz_HighLevel_Drift5_StreamDelay0) {
-#endif
- const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
- RunBitexactnessTest(16000, 1, 0, true, 5,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Stereo8kHz_HighLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Stereo8kHz_HighLevel_NoDrift_StreamDelay0) {
-#endif
-#if defined(WEBRTC_MAC)
- const float kOutputReference[] = {-0.000392f, -0.001449f, 0.003004f,
- -0.000392f, -0.001449f, 0.003004f};
-#else
- const float kOutputReference[] = {-0.000464f, -0.001525f, 0.002933f,
- -0.000464f, -0.001525f, 0.002933f};
-#endif
- RunBitexactnessTest(8000, 2, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Stereo16kHz_HighLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Stereo16kHz_HighLevel_NoDrift_StreamDelay0) {
-#endif
- const float kOutputReference[] = {0.000166f, 0.000735f, 0.000841f,
- 0.000166f, 0.000735f, 0.000841f};
- RunBitexactnessTest(16000, 2, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Stereo32kHz_HighLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Stereo32kHz_HighLevel_NoDrift_StreamDelay0) {
-#endif
-#if defined(WEBRTC_MAC)
- const float kOutputReference[] = {-0.000458f, 0.000214f, 0.000122f,
- -0.000458f, 0.000214f, 0.000122f};
-#else
- const float kOutputReference[] = {-0.000427f, 0.000183f, 0.000183f,
- -0.000427f, 0.000183f, 0.000183f};
-#endif
- RunBitexactnessTest(32000, 2, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
- defined(WEBRTC_ANDROID))
-TEST(EchoCancellationBitExactnessTest,
- Stereo48kHz_HighLevel_NoDrift_StreamDelay0) {
-#else
-TEST(EchoCancellationBitExactnessTest,
- DISABLED_Stereo48kHz_HighLevel_NoDrift_StreamDelay0) {
-#endif
- const float kOutputReference[] = {-0.001101f, -0.001101f, -0.000449f,
- -0.001101f, -0.001101f, -0.000449f};
- RunBitexactnessTest(48000, 2, 0, false, 0,
- EchoCancellationImpl::SuppressionLevel::kHighSuppression,
- kStreamHasEchoReference, kOutputReference);
-}
-
-} // namespace webrtc
diff --git a/modules/audio_processing/echo_cancellation_impl.cc b/modules/audio_processing/echo_cancellation_impl.cc
deleted file mode 100644
index 25e8d70..0000000
--- a/modules/audio_processing/echo_cancellation_impl.cc
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "modules/audio_processing/echo_cancellation_impl.h"
-
-#include <stdint.h>
-#include <string.h>
-
-#include "modules/audio_processing/aec/aec_core.h"
-#include "modules/audio_processing/aec/echo_cancellation.h"
-#include "modules/audio_processing/audio_buffer.h"
-#include "rtc_base/checks.h"
-#include "system_wrappers/include/field_trial.h"
-
-namespace webrtc {
-
-namespace {
-int16_t MapSetting(EchoCancellationImpl::SuppressionLevel level) {
- switch (level) {
- case EchoCancellationImpl::kLowSuppression:
- return kAecNlpConservative;
- case EchoCancellationImpl::kModerateSuppression:
- return kAecNlpModerate;
- case EchoCancellationImpl::kHighSuppression:
- return kAecNlpAggressive;
- }
- RTC_NOTREACHED();
- return -1;
-}
-
-AudioProcessing::Error MapError(int err) {
- switch (err) {
- case AEC_UNSUPPORTED_FUNCTION_ERROR:
- return AudioProcessing::kUnsupportedFunctionError;
- case AEC_BAD_PARAMETER_ERROR:
- return AudioProcessing::kBadParameterError;
- case AEC_BAD_PARAMETER_WARNING:
- return AudioProcessing::kBadStreamParameterWarning;
- default:
- // AEC_UNSPECIFIED_ERROR
- // AEC_UNINITIALIZED_ERROR
- // AEC_NULL_POINTER_ERROR
- return AudioProcessing::kUnspecifiedError;
- }
-}
-
-bool EnforceZeroStreamDelay() {
-#if defined(CHROMEOS)
- return !field_trial::IsEnabled("WebRTC-Aec2ZeroStreamDelayKillSwitch");
-#else
- return false;
-#endif
-}
-
-} // namespace
-
-struct EchoCancellationImpl::StreamProperties {
- StreamProperties() = delete;
- StreamProperties(int sample_rate_hz,
- size_t num_reverse_channels,
- size_t num_output_channels,
- size_t num_proc_channels)
- : sample_rate_hz(sample_rate_hz),
- num_reverse_channels(num_reverse_channels),
- num_output_channels(num_output_channels),
- num_proc_channels(num_proc_channels) {}
-
- const int sample_rate_hz;
- const size_t num_reverse_channels;
- const size_t num_output_channels;
- const size_t num_proc_channels;
-};
-
-class EchoCancellationImpl::Canceller {
- public:
- Canceller() {
- state_ = WebRtcAec_Create();
- RTC_DCHECK(state_);
- }
-
- ~Canceller() {
- RTC_CHECK(state_);
- WebRtcAec_Free(state_);
- }
-
- void* state() { return state_; }
-
- void Initialize(int sample_rate_hz) {
- // TODO(ajm): Drift compensation is disabled in practice. If restored, it
- // should be managed internally and not depend on the hardware sample rate.
- // For now, just hardcode a 48 kHz value.
- const int error = WebRtcAec_Init(state_, sample_rate_hz, 48000);
- RTC_DCHECK_EQ(0, error);
- }
-
- private:
- void* state_;
-};
-
-EchoCancellationImpl::EchoCancellationImpl()
- : drift_compensation_enabled_(false),
- metrics_enabled_(true),
- suppression_level_(kHighSuppression),
- stream_drift_samples_(0),
- was_stream_drift_set_(false),
- stream_has_echo_(false),
- delay_logging_enabled_(true),
- extended_filter_enabled_(false),
- delay_agnostic_enabled_(false),
- enforce_zero_stream_delay_(EnforceZeroStreamDelay()) {}
-
-EchoCancellationImpl::~EchoCancellationImpl() = default;
-
-void EchoCancellationImpl::ProcessRenderAudio(
- rtc::ArrayView<const float> packed_render_audio) {
- RTC_DCHECK(stream_properties_);
- size_t handle_index = 0;
- size_t buffer_index = 0;
- const size_t num_frames_per_band =
- packed_render_audio.size() / (stream_properties_->num_output_channels *
- stream_properties_->num_reverse_channels);
- for (size_t i = 0; i < stream_properties_->num_output_channels; i++) {
- for (size_t j = 0; j < stream_properties_->num_reverse_channels; j++) {
- WebRtcAec_BufferFarend(cancellers_[handle_index++]->state(),
- &packed_render_audio[buffer_index],
- num_frames_per_band);
-
- buffer_index += num_frames_per_band;
- }
- }
-}
-
-int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio,
- int stream_delay_ms) {
- const int stream_delay_ms_use =
- enforce_zero_stream_delay_ ? 0 : stream_delay_ms;
-
- if (drift_compensation_enabled_ && !was_stream_drift_set_) {
- return AudioProcessing::kStreamParameterNotSetError;
- }
-
- RTC_DCHECK(stream_properties_);
- RTC_DCHECK_GE(160, audio->num_frames_per_band());
- RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_proc_channels);
-
- int err = AudioProcessing::kNoError;
-
- // The ordering convention must be followed to pass to the correct AEC.
- size_t handle_index = 0;
- stream_has_echo_ = false;
- for (size_t i = 0; i < audio->num_channels(); i++) {
- for (size_t j = 0; j < stream_properties_->num_reverse_channels; j++) {
- err =
- WebRtcAec_Process(cancellers_[handle_index]->state(),
- audio->split_bands_const(i), audio->num_bands(),
- audio->split_bands(i), audio->num_frames_per_band(),
- stream_delay_ms_use, stream_drift_samples_);
-
- if (err != AudioProcessing::kNoError) {
- err = MapError(err);
- // TODO(ajm): Figure out how to return warnings properly.
- if (err != AudioProcessing::kBadStreamParameterWarning) {
- return err;
- }
- }
-
- int status = 0;
- err = WebRtcAec_get_echo_status(cancellers_[handle_index]->state(),
- &status);
- if (err != AudioProcessing::kNoError) {
- return MapError(err);
- }
-
- if (status == 1) {
- stream_has_echo_ = true;
- }
-
- handle_index++;
- }
- }
-
- was_stream_drift_set_ = false;
- return AudioProcessing::kNoError;
-}
-
-int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) {
- if (MapSetting(level) == -1) {
- return AudioProcessing::kBadParameterError;
- }
- suppression_level_ = level;
- return Configure();
-}
-
-EchoCancellationImpl::SuppressionLevel EchoCancellationImpl::suppression_level()
- const {
- return suppression_level_;
-}
-
-int EchoCancellationImpl::enable_drift_compensation(bool enable) {
- drift_compensation_enabled_ = enable;
- return Configure();
-}
-
-bool EchoCancellationImpl::is_drift_compensation_enabled() const {
- return drift_compensation_enabled_;
-}
-
-void EchoCancellationImpl::set_stream_drift_samples(int drift) {
- was_stream_drift_set_ = true;
- stream_drift_samples_ = drift;
-}
-
-int EchoCancellationImpl::stream_drift_samples() const {
- return stream_drift_samples_;
-}
-
-int EchoCancellationImpl::enable_metrics(bool enable) {
- metrics_enabled_ = enable;
- return Configure();
-}
-
-bool EchoCancellationImpl::are_metrics_enabled() const {
- return metrics_enabled_;
-}
-
-// TODO(ajm): we currently just use the metrics from the first AEC. Think more
-// aboue the best way to extend this to multi-channel.
-int EchoCancellationImpl::GetMetrics(Metrics* metrics) {
- if (metrics == NULL) {
- return AudioProcessing::kNullPointerError;
- }
-
- if (!metrics_enabled_) {
- return AudioProcessing::kNotEnabledError;
- }
-
- AecMetrics my_metrics;
- memset(&my_metrics, 0, sizeof(my_metrics));
- memset(metrics, 0, sizeof(Metrics));
-
- const int err = WebRtcAec_GetMetrics(cancellers_[0]->state(), &my_metrics);
- if (err != AudioProcessing::kNoError) {
- return MapError(err);
- }
-
- metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant;
- metrics->residual_echo_return_loss.average = my_metrics.rerl.average;
- metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max;
- metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min;
-
- metrics->echo_return_loss.instant = my_metrics.erl.instant;
- metrics->echo_return_loss.average = my_metrics.erl.average;
- metrics->echo_return_loss.maximum = my_metrics.erl.max;
- metrics->echo_return_loss.minimum = my_metrics.erl.min;
-
- metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant;
- metrics->echo_return_loss_enhancement.average = my_metrics.erle.average;
- metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max;
- metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min;
-
- metrics->a_nlp.instant = my_metrics.aNlp.instant;
- metrics->a_nlp.average = my_metrics.aNlp.average;
- metrics->a_nlp.maximum = my_metrics.aNlp.max;
- metrics->a_nlp.minimum = my_metrics.aNlp.min;
-
- metrics->divergent_filter_fraction = my_metrics.divergent_filter_fraction;
- return AudioProcessing::kNoError;
-}
-
-bool EchoCancellationImpl::stream_has_echo() const {
- return stream_has_echo_;
-}
-
-int EchoCancellationImpl::enable_delay_logging(bool enable) {
- delay_logging_enabled_ = enable;
- return Configure();
-}
-
-bool EchoCancellationImpl::is_delay_logging_enabled() const {
- return delay_logging_enabled_;
-}
-
-bool EchoCancellationImpl::is_delay_agnostic_enabled() const {
- return delay_agnostic_enabled_;
-}
-
-std::string EchoCancellationImpl::GetExperimentsDescription() {
- return refined_adaptive_filter_enabled_ ? "Legacy AEC;RefinedAdaptiveFilter;"
- : "Legacy AEC;";
-}
-
-bool EchoCancellationImpl::is_refined_adaptive_filter_enabled() const {
- return refined_adaptive_filter_enabled_;
-}
-
-bool EchoCancellationImpl::is_extended_filter_enabled() const {
- return extended_filter_enabled_;
-}
-
-// TODO(bjornv): How should we handle the multi-channel case?
-int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) {
- float fraction_poor_delays = 0;
- return GetDelayMetrics(median, std, &fraction_poor_delays);
-}
-
-int EchoCancellationImpl::GetDelayMetrics(int* median,
- int* std,
- float* fraction_poor_delays) {
- if (median == NULL) {
- return AudioProcessing::kNullPointerError;
- }
- if (std == NULL) {
- return AudioProcessing::kNullPointerError;
- }
-
- if (!delay_logging_enabled_) {
- return AudioProcessing::kNotEnabledError;
- }
-
- const int err = WebRtcAec_GetDelayMetrics(cancellers_[0]->state(), median,
- std, fraction_poor_delays);
- if (err != AudioProcessing::kNoError) {
- return MapError(err);
- }
-
- return AudioProcessing::kNoError;
-}
-
-struct AecCore* EchoCancellationImpl::aec_core() const {
- return WebRtcAec_aec_core(cancellers_[0]->state());
-}
-
-void EchoCancellationImpl::Initialize(int sample_rate_hz,
- size_t num_reverse_channels,
- size_t num_output_channels,
- size_t num_proc_channels) {
- stream_properties_.reset(
- new StreamProperties(sample_rate_hz, num_reverse_channels,
- num_output_channels, num_proc_channels));
-
- const size_t num_cancellers_required =
- NumCancellersRequired(stream_properties_->num_output_channels,
- stream_properties_->num_reverse_channels);
- if (num_cancellers_required > cancellers_.size()) {
- const size_t cancellers_old_size = cancellers_.size();
- cancellers_.resize(num_cancellers_required);
-
- for (size_t i = cancellers_old_size; i < cancellers_.size(); ++i) {
- cancellers_[i].reset(new Canceller());
- }
- }
-
- for (auto& canceller : cancellers_) {
- canceller->Initialize(sample_rate_hz);
- }
-
- Configure();
-}
-
-int EchoCancellationImpl::GetSystemDelayInSamples() const {
- // Report the delay for the first AEC component.
- return WebRtcAec_system_delay(WebRtcAec_aec_core(cancellers_[0]->state()));
-}
-
-void EchoCancellationImpl::PackRenderAudioBuffer(
- const AudioBuffer* audio,
- size_t num_output_channels,
- size_t num_channels,
- std::vector<float>* packed_buffer) {
- RTC_DCHECK_GE(160, audio->num_frames_per_band());
- RTC_DCHECK_EQ(num_channels, audio->num_channels());
-
- packed_buffer->clear();
- // The ordering convention must be followed to pass the correct data.
- for (size_t i = 0; i < num_output_channels; i++) {
- for (size_t j = 0; j < audio->num_channels(); j++) {
- // Buffer the samples in the render queue.
- packed_buffer->insert(packed_buffer->end(),
- audio->split_bands_const(j)[kBand0To8kHz],
- (audio->split_bands_const(j)[kBand0To8kHz] +
- audio->num_frames_per_band()));
- }
- }
-}
-
-void EchoCancellationImpl::SetExtraOptions(bool use_extended_filter,
- bool use_delay_agnostic,
- bool use_refined_adaptive_filter) {
- extended_filter_enabled_ = use_extended_filter;
- delay_agnostic_enabled_ = use_delay_agnostic;
- refined_adaptive_filter_enabled_ = use_refined_adaptive_filter;
- Configure();
-}
-
-int EchoCancellationImpl::Configure() {
- AecConfig config;
- config.metricsMode = metrics_enabled_;
- config.nlpMode = MapSetting(suppression_level_);
- config.skewMode = drift_compensation_enabled_;
- config.delay_logging = delay_logging_enabled_;
-
- int error = AudioProcessing::kNoError;
- for (auto& canceller : cancellers_) {
- WebRtcAec_enable_extended_filter(WebRtcAec_aec_core(canceller->state()),
- extended_filter_enabled_ ? 1 : 0);
- WebRtcAec_enable_delay_agnostic(WebRtcAec_aec_core(canceller->state()),
- delay_agnostic_enabled_ ? 1 : 0);
- WebRtcAec_enable_refined_adaptive_filter(
- WebRtcAec_aec_core(canceller->state()),
- refined_adaptive_filter_enabled_);
- const int handle_error = WebRtcAec_set_config(canceller->state(), config);
- if (handle_error != AudioProcessing::kNoError) {
- error = AudioProcessing::kNoError;
- }
- }
- return error;
-}
-
-size_t EchoCancellationImpl::NumCancellersRequired(
- size_t num_output_channels,
- size_t num_reverse_channels) {
- return num_output_channels * num_reverse_channels;
-}
-
-} // namespace webrtc
diff --git a/modules/audio_processing/echo_cancellation_impl.h b/modules/audio_processing/echo_cancellation_impl.h
deleted file mode 100644
index 1df41a7..0000000
--- a/modules/audio_processing/echo_cancellation_impl.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_IMPL_H_
-#define MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_IMPL_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "api/array_view.h"
-#include "rtc_base/constructor_magic.h"
-
-namespace webrtc {
-
-class AudioBuffer;
-
-// The acoustic echo cancellation (AEC) component provides better performance
-// than AECM but also requires more processing power and is dependent on delay
-// stability and reporting accuracy. As such it is well-suited and recommended
-// for PC and IP phone applications.
-class EchoCancellationImpl {
- public:
- explicit EchoCancellationImpl();
- ~EchoCancellationImpl();
-
- void ProcessRenderAudio(rtc::ArrayView<const float> packed_render_audio);
- int ProcessCaptureAudio(AudioBuffer* audio, int stream_delay_ms);
-
- // Differences in clock speed on the primary and reverse streams can impact
- // the AEC performance. On the client-side, this could be seen when different
- // render and capture devices are used, particularly with webcams.
- //
- // This enables a compensation mechanism, and requires that
- // set_stream_drift_samples() be called.
- int enable_drift_compensation(bool enable);
- bool is_drift_compensation_enabled() const;
-
- // Sets the difference between the number of samples rendered and captured by
- // the audio devices since the last call to |ProcessStream()|. Must be called
- // if drift compensation is enabled, prior to |ProcessStream()|.
- void set_stream_drift_samples(int drift);
- int stream_drift_samples() const;
-
- enum SuppressionLevel {
- kLowSuppression,
- kModerateSuppression,
- kHighSuppression
- };
-
- // Sets the aggressiveness of the suppressor. A higher level trades off
- // double-talk performance for increased echo suppression.
- int set_suppression_level(SuppressionLevel level);
- SuppressionLevel suppression_level() const;
-
- // Returns false if the current frame almost certainly contains no echo
- // and true if it _might_ contain echo.
- bool stream_has_echo() const;
-
- // Enables the computation of various echo metrics. These are obtained
- // through |GetMetrics()|.
- int enable_metrics(bool enable);
- bool are_metrics_enabled() const;
-
- // Each statistic is reported in dB.
- // P_far: Far-end (render) signal power.
- // P_echo: Near-end (capture) echo signal power.
- // P_out: Signal power at the output of the AEC.
- // P_a: Internal signal power at the point before the AEC's non-linear
- // processor.
- struct Metrics {
- struct Statistic {
- int instant = 0; // Instantaneous value.
- int average = 0; // Long-term average.
- int maximum = 0; // Long-term maximum.
- int minimum = 0; // Long-term minimum.
- };
- // RERL = ERL + ERLE
- Statistic residual_echo_return_loss;
-
- // ERL = 10log_10(P_far / P_echo)
- Statistic echo_return_loss;
-
- // ERLE = 10log_10(P_echo / P_out)
- Statistic echo_return_loss_enhancement;
-
- // (Pre non-linear processing suppression) A_NLP = 10log_10(P_echo / P_a)
- Statistic a_nlp;
-
- // Fraction of time that the AEC linear filter is divergent, in a 1-second
- // non-overlapped aggregation window.
- float divergent_filter_fraction;
- };
-
- // Provides various statistics about the AEC.
- int GetMetrics(Metrics* metrics);
-
- // Enables computation and logging of delay values. Statistics are obtained
- // through |GetDelayMetrics()|.
- int enable_delay_logging(bool enable);
- bool is_delay_logging_enabled() const;
-
- // Provides delay metrics.
- // The delay metrics consists of the delay |median| and the delay standard
- // deviation |std|. It also consists of the fraction of delay estimates
- // |fraction_poor_delays| that can make the echo cancellation perform poorly.
- // The values are aggregated until the first call to |GetDelayMetrics()| and
- // afterwards aggregated and updated every second.
- // Note that if there are several clients pulling metrics from
- // |GetDelayMetrics()| during a session the first call from any of them will
- // change to one second aggregation window for all.
- int GetDelayMetrics(int* median, int* std);
- int GetDelayMetrics(int* median, int* std, float* fraction_poor_delays);
-
- // Returns a pointer to the low level AEC component. In case of multiple
- // channels, the pointer to the first one is returned. A NULL pointer is
- // returned when the AEC component is disabled or has not been initialized
- // successfully.
- struct AecCore* aec_core() const;
-
- void Initialize(int sample_rate_hz,
- size_t num_reverse_channels_,
- size_t num_output_channels_,
- size_t num_proc_channels_);
- void SetExtraOptions(bool use_extended_filter,
- bool use_delay_agnostic,
- bool use_refined_adaptive_filter);
- bool is_delay_agnostic_enabled() const;
- bool is_extended_filter_enabled() const;
- std::string GetExperimentsDescription();
- bool is_refined_adaptive_filter_enabled() const;
-
- // Returns the system delay of the first AEC component.
- int GetSystemDelayInSamples() const;
-
- static void PackRenderAudioBuffer(const AudioBuffer* audio,
- size_t num_output_channels,
- size_t num_channels,
- std::vector<float>* packed_buffer);
- static size_t NumCancellersRequired(size_t num_output_channels,
- size_t num_reverse_channels);
-
- private:
- class Canceller;
- struct StreamProperties;
-
- void AllocateRenderQueue();
- int Configure();
-
- bool drift_compensation_enabled_;
- bool metrics_enabled_;
- SuppressionLevel suppression_level_;
- int stream_drift_samples_;
- bool was_stream_drift_set_;
- bool stream_has_echo_;
- bool delay_logging_enabled_;
- bool extended_filter_enabled_;
- bool delay_agnostic_enabled_;
- bool refined_adaptive_filter_enabled_ = false;
-
- // Only active on Chrome OS devices.
- const bool enforce_zero_stream_delay_;
-
- std::vector<std::unique_ptr<Canceller>> cancellers_;
- std::unique_ptr<StreamProperties> stream_properties_;
-};
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_IMPL_H_
diff --git a/modules/audio_processing/echo_cancellation_impl_unittest.cc b/modules/audio_processing/echo_cancellation_impl_unittest.cc
deleted file mode 100644
index a970a4e..0000000
--- a/modules/audio_processing/echo_cancellation_impl_unittest.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "modules/audio_processing/echo_cancellation_impl.h"
-
-#include <memory>
-
-#include "modules/audio_processing/aec/aec_core.h"
-#include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/critical_section.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-TEST(EchoCancellationInternalTest, ExtendedFilter) {
- EchoCancellationImpl echo_canceller;
- echo_canceller.Initialize(AudioProcessing::kSampleRate32kHz, 2, 2, 2);
-
- AecCore* aec_core = echo_canceller.aec_core();
- ASSERT_TRUE(aec_core != NULL);
- // Disabled by default.
- EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(aec_core));
-
- Config config;
- echo_canceller.SetExtraOptions(true, false, false);
- EXPECT_EQ(1, WebRtcAec_extended_filter_enabled(aec_core));
-
- // Retains setting after initialization.
- echo_canceller.Initialize(AudioProcessing::kSampleRate16kHz, 2, 2, 2);
- EXPECT_EQ(1, WebRtcAec_extended_filter_enabled(aec_core));
-
- echo_canceller.SetExtraOptions(false, false, false);
- EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(aec_core));
-
- // Retains setting after initialization.
- echo_canceller.Initialize(AudioProcessing::kSampleRate16kHz, 1, 1, 1);
- EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(aec_core));
-}
-
-TEST(EchoCancellationInternalTest, DelayAgnostic) {
- EchoCancellationImpl echo_canceller;
- echo_canceller.Initialize(AudioProcessing::kSampleRate32kHz, 1, 1, 1);
-
- AecCore* aec_core = echo_canceller.aec_core();
- ASSERT_TRUE(aec_core != NULL);
- // Enabled by default.
- EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(aec_core));
-
- Config config;
- echo_canceller.SetExtraOptions(false, true, false);
- EXPECT_EQ(1, WebRtcAec_delay_agnostic_enabled(aec_core));
-
- // Retains setting after initialization.
- echo_canceller.Initialize(AudioProcessing::kSampleRate32kHz, 2, 2, 2);
- EXPECT_EQ(1, WebRtcAec_delay_agnostic_enabled(aec_core));
-
- config.Set<DelayAgnostic>(new DelayAgnostic(false));
- echo_canceller.SetExtraOptions(false, false, false);
- EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(aec_core));
-
- // Retains setting after initialization.
- echo_canceller.Initialize(AudioProcessing::kSampleRate16kHz, 2, 2, 2);
- EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(aec_core));
-}
-
-TEST(EchoCancellationInternalTest, InterfaceConfiguration) {
- EchoCancellationImpl echo_canceller;
- echo_canceller.Initialize(AudioProcessing::kSampleRate16kHz, 1, 1, 1);
-
- EXPECT_EQ(0, echo_canceller.enable_drift_compensation(true));
- EXPECT_TRUE(echo_canceller.is_drift_compensation_enabled());
- EXPECT_EQ(0, echo_canceller.enable_drift_compensation(false));
- EXPECT_FALSE(echo_canceller.is_drift_compensation_enabled());
-
- EchoCancellationImpl::SuppressionLevel level[] = {
- EchoCancellationImpl::kLowSuppression,
- EchoCancellationImpl::kModerateSuppression,
- EchoCancellationImpl::kHighSuppression,
- };
- for (size_t i = 0; i < arraysize(level); i++) {
- EXPECT_EQ(0, echo_canceller.set_suppression_level(level[i]));
- EXPECT_EQ(level[i], echo_canceller.suppression_level());
- }
-
- EchoCancellationImpl::Metrics metrics;
- EXPECT_EQ(0, echo_canceller.enable_metrics(true));
- EXPECT_TRUE(echo_canceller.are_metrics_enabled());
- EXPECT_EQ(0, echo_canceller.enable_metrics(false));
- EXPECT_FALSE(echo_canceller.are_metrics_enabled());
-
- EXPECT_EQ(0, echo_canceller.enable_delay_logging(true));
- EXPECT_TRUE(echo_canceller.is_delay_logging_enabled());
- EXPECT_EQ(0, echo_canceller.enable_delay_logging(false));
- EXPECT_FALSE(echo_canceller.is_delay_logging_enabled());
-
- int median = 0;
- int std = 0;
- float poor_fraction = 0;
- EXPECT_EQ(AudioProcessing::kNotEnabledError,
- echo_canceller.GetDelayMetrics(&median, &std, &poor_fraction));
-
- EXPECT_TRUE(echo_canceller.aec_core() != NULL);
-}
-
-} // namespace webrtc
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index e8ecd6e..2340834 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -37,8 +37,6 @@
namespace webrtc {
-struct AecCore;
-
class AecDump;
class AudioBuffer;
class AudioFrame;
@@ -50,53 +48,6 @@
class CustomAudioAnalyzer;
class CustomProcessing;
-// Use to enable the extended filter mode in the AEC, along with robustness
-// measures around the reported system delays. It comes with a significant
-// increase in AEC complexity, but is much more robust to unreliable reported
-// delays.
-//
-// Detailed changes to the algorithm:
-// - The filter length is changed from 48 to 128 ms. This comes with tuning of
-// several parameters: i) filter adaptation stepsize and error threshold;
-// ii) non-linear processing smoothing and overdrive.
-// - Option to ignore the reported delays on platforms which we deem
-// sufficiently unreliable. See WEBRTC_UNTRUSTED_DELAY in echo_cancellation.c.
-// - Faster startup times by removing the excessive "startup phase" processing
-// of reported delays.
-// - Much more conservative adjustments to the far-end read pointer. We smooth
-// the delay difference more heavily, and back off from the difference more.
-// Adjustments force a readaptation of the filter, so they should be avoided
-// except when really necessary.
-struct ExtendedFilter {
- ExtendedFilter() : enabled(false) {}
- explicit ExtendedFilter(bool enabled) : enabled(enabled) {}
- static const ConfigOptionID identifier = ConfigOptionID::kExtendedFilter;
- bool enabled;
-};
-
-// Enables the refined linear filter adaptation in the echo canceller.
-// This configuration only applies to non-mobile echo cancellation.
-// It can be set in the constructor or using AudioProcessing::SetExtraOptions().
-struct RefinedAdaptiveFilter {
- RefinedAdaptiveFilter() : enabled(false) {}
- explicit RefinedAdaptiveFilter(bool enabled) : enabled(enabled) {}
- static const ConfigOptionID identifier =
- ConfigOptionID::kAecRefinedAdaptiveFilter;
- bool enabled;
-};
-
-// Enables delay-agnostic echo cancellation. This feature relies on internally
-// estimated delays between the process and reverse streams, thus not relying
-// on reported system delays. This configuration only applies to non-mobile echo
-// cancellation. It can be set in the constructor or using
-// AudioProcessing::SetExtraOptions().
-struct DelayAgnostic {
- DelayAgnostic() : enabled(false) {}
- explicit DelayAgnostic(bool enabled) : enabled(enabled) {}
- static const ConfigOptionID identifier = ConfigOptionID::kDelayAgnostic;
- bool enabled;
-};
-
// Use to enable experimental gain control (AGC). At startup the experimental
// AGC moves the microphone volume up to |startup_min_volume| if the current
// microphone volume is set too low. The value is clamped to its operating range
@@ -279,9 +230,10 @@
bool enabled = false;
bool mobile_mode = false;
// Recommended not to use. Will be removed in the future.
- // APM components are not fine-tuned for legacy suppression levels.
+ // TODO(peah): Remove.
bool legacy_moderate_suppression_level = false;
// Recommended not to use. Will be removed in the future.
+ // TODO(webrtc:11165): Remove.
bool use_legacy_aec = false;
bool export_linear_aec_output = false;
// Enforce the highpass filter to be on (has no effect for the mobile
diff --git a/modules/audio_processing/include/config.h b/modules/audio_processing/include/config.h
index 930cf7e..8a24586 100644
--- a/modules/audio_processing/include/config.h
+++ b/modules/audio_processing/include/config.h
@@ -27,15 +27,15 @@
kNetEqCapacityConfig, // Deprecated
kNetEqFastAccelerate, // Deprecated
kVoicePacing, // Deprecated
- kExtendedFilter,
- kDelayAgnostic,
+ kExtendedFilter, // Deprecated
+ kDelayAgnostic, // Deprecated
kExperimentalAgc,
kExperimentalNs,
- kBeamforming, // Deprecated
- kIntelligibility, // Deprecated
- kEchoCanceller3, // Deprecated
- kAecRefinedAdaptiveFilter,
- kLevelControl // Deprecated
+ kBeamforming, // Deprecated
+ kIntelligibility, // Deprecated
+ kEchoCanceller3, // Deprecated
+ kAecRefinedAdaptiveFilter, // Deprecated
+ kLevelControl // Deprecated
};
// Class Config is designed to ease passing a set of options across webrtc code.
diff --git a/modules/audio_processing/test/aec_dump_based_simulator.cc b/modules/audio_processing/test/aec_dump_based_simulator.cc
index d9bd5bc..e050f48 100644
--- a/modules/audio_processing/test/aec_dump_based_simulator.cc
+++ b/modules/audio_processing/test/aec_dump_based_simulator.cc
@@ -13,7 +13,6 @@
#include <iostream>
#include <memory>
-#include "modules/audio_processing/echo_cancellation_impl.h"
#include "modules/audio_processing/echo_control_mobile_impl.h"
#include "modules/audio_processing/test/protobuf_utils.h"
#include "rtc_base/checks.h"
@@ -300,57 +299,6 @@
}
}
- if (msg.has_aec_delay_agnostic_enabled() || settings_.use_delay_agnostic) {
- bool enable = settings_.use_delay_agnostic
- ? *settings_.use_delay_agnostic
- : msg.aec_delay_agnostic_enabled();
- config.Set<DelayAgnostic>(new DelayAgnostic(enable));
- if (settings_.use_verbose_logging) {
- std::cout << " aec_delay_agnostic_enabled: "
- << (enable ? "true" : "false") << std::endl;
- }
- }
-
- if (msg.has_aec_drift_compensation_enabled() ||
- settings_.use_drift_compensation) {
- if (settings_.use_drift_compensation
- ? *settings_.use_drift_compensation
- : msg.aec_drift_compensation_enabled()) {
- RTC_LOG(LS_ERROR)
- << "Ignoring deprecated setting: AEC2 drift compensation";
- }
- }
-
- if (msg.has_aec_extended_filter_enabled() ||
- settings_.use_extended_filter) {
- bool enable = settings_.use_extended_filter
- ? *settings_.use_extended_filter
- : msg.aec_extended_filter_enabled();
- config.Set<ExtendedFilter>(new ExtendedFilter(enable));
- if (settings_.use_verbose_logging) {
- std::cout << " aec_extended_filter_enabled: "
- << (enable ? "true" : "false") << std::endl;
- }
- }
-
- if (msg.has_aec_suppression_level() || settings_.aec_suppression_level) {
- auto level = static_cast<webrtc::EchoCancellationImpl::SuppressionLevel>(
- settings_.aec_suppression_level ? *settings_.aec_suppression_level
- : msg.aec_suppression_level());
- if (level ==
- webrtc::EchoCancellationImpl::SuppressionLevel::kLowSuppression) {
- RTC_LOG(LS_ERROR)
- << "Ignoring deprecated setting: AEC2 low suppression";
- } else {
- apm_config.echo_canceller.legacy_moderate_suppression_level =
- (level == webrtc::EchoCancellationImpl::SuppressionLevel::
- kModerateSuppression);
- if (settings_.use_verbose_logging) {
- std::cout << " aec_suppression_level: " << level << std::endl;
- }
- }
- }
-
if (msg.has_aecm_enabled() || settings_.use_aecm) {
bool enable =
settings_.use_aecm ? *settings_.use_aecm : msg.aecm_enabled();
@@ -486,11 +434,6 @@
<< msg.experiments_description() << std::endl;
}
- if (settings_.use_refined_adaptive_filter) {
- config.Set<RefinedAdaptiveFilter>(
- new RefinedAdaptiveFilter(*settings_.use_refined_adaptive_filter));
- }
-
if (settings_.use_ed) {
apm_config.residual_echo_detector.enabled = *settings_.use_ed;
}
diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc
index cb1d1ed..5677600 100644
--- a/modules/audio_processing/test/audio_processing_simulator.cc
+++ b/modules/audio_processing/test/audio_processing_simulator.cc
@@ -22,7 +22,6 @@
#include "api/audio/echo_canceller3_factory.h"
#include "common_audio/include/audio_util.h"
#include "modules/audio_processing/aec_dump/aec_dump_factory.h"
-#include "modules/audio_processing/echo_cancellation_impl.h"
#include "modules/audio_processing/echo_control_mobile_impl.h"
#include "modules/audio_processing/include/audio_processing.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
@@ -433,23 +432,17 @@
}
}
- const bool use_legacy_aec = settings_.use_aec && *settings_.use_aec &&
- settings_.use_legacy_aec &&
- *settings_.use_legacy_aec;
const bool use_aec = settings_.use_aec && *settings_.use_aec;
const bool use_aecm = settings_.use_aecm && *settings_.use_aecm;
- if (use_legacy_aec || use_aec || use_aecm) {
+ if (use_aec || use_aecm) {
apm_config.echo_canceller.enabled = true;
apm_config.echo_canceller.mobile_mode = use_aecm;
- apm_config.echo_canceller.use_legacy_aec = use_legacy_aec;
+ apm_config.echo_canceller.use_legacy_aec = false;
}
apm_config.echo_canceller.export_linear_aec_output =
!!settings_.linear_aec_output_filename;
- RTC_CHECK(!(use_legacy_aec && settings_.aec_settings_filename))
- << "The legacy AEC cannot be configured using settings";
-
- if (use_aec && !use_legacy_aec) {
+ if (use_aec) {
EchoCanceller3Config cfg;
if (settings_.aec_settings_filename) {
if (settings_.use_verbose_logging) {
@@ -472,22 +465,6 @@
}
}
- if (settings_.use_drift_compensation && *settings_.use_drift_compensation) {
- RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AEC2 drift compensation";
- }
- if (settings_.aec_suppression_level) {
- auto level = static_cast<webrtc::EchoCancellationImpl::SuppressionLevel>(
- *settings_.aec_suppression_level);
- if (level ==
- webrtc::EchoCancellationImpl::SuppressionLevel::kLowSuppression) {
- RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AEC2 low suppression";
- } else {
- apm_config.echo_canceller.legacy_moderate_suppression_level =
- (level == webrtc::EchoCancellationImpl::SuppressionLevel::
- kModerateSuppression);
- }
- }
-
if (settings_.use_hpf) {
apm_config.high_pass_filter.enabled = *settings_.use_hpf;
}
@@ -519,14 +496,6 @@
*settings_.agc_compression_gain;
}
- if (settings_.use_refined_adaptive_filter) {
- config.Set<RefinedAdaptiveFilter>(
- new RefinedAdaptiveFilter(*settings_.use_refined_adaptive_filter));
- }
- config.Set<ExtendedFilter>(new ExtendedFilter(
- !settings_.use_extended_filter || *settings_.use_extended_filter));
- config.Set<DelayAgnostic>(new DelayAgnostic(!settings_.use_delay_agnostic ||
- *settings_.use_delay_agnostic));
config.Set<ExperimentalAgc>(new ExperimentalAgc(
!settings_.use_experimental_agc || *settings_.use_experimental_agc,
!!settings_.use_experimental_agc_agc2_level_estimator &&
diff --git a/modules/audio_processing/test/audio_processing_simulator.h b/modules/audio_processing/test/audio_processing_simulator.h
index 5b26b5f..abef2fa 100644
--- a/modules/audio_processing/test/audio_processing_simulator.h
+++ b/modules/audio_processing/test/audio_processing_simulator.h
@@ -37,7 +37,6 @@
~SimulationSettings();
absl::optional<int> stream_delay;
absl::optional<bool> use_stream_delay;
- absl::optional<int> stream_drift_samples;
absl::optional<int> output_sample_rate_hz;
absl::optional<int> output_num_channels;
absl::optional<int> reverse_output_sample_rate_hz;
@@ -61,11 +60,6 @@
absl::optional<bool> use_vad;
absl::optional<bool> use_le;
absl::optional<bool> use_all;
- absl::optional<int> aec_suppression_level;
- absl::optional<bool> use_delay_agnostic;
- absl::optional<bool> use_extended_filter;
- absl::optional<bool> use_drift_compensation;
- absl::optional<bool> use_legacy_aec;
absl::optional<bool> use_legacy_ns;
absl::optional<bool> use_experimental_agc;
absl::optional<bool> use_experimental_agc_agc2_level_estimator;
@@ -82,7 +76,6 @@
absl::optional<float> pre_amplifier_gain_factor;
absl::optional<int> ns_level;
absl::optional<int> maximum_internal_processing_rate;
- absl::optional<bool> use_refined_adaptive_filter;
int initial_mic_level;
bool simulate_mic_gain = false;
absl::optional<bool> multi_channel_render;
diff --git a/modules/audio_processing/test/audioproc_float_impl.cc b/modules/audio_processing/test/audioproc_float_impl.cc
index 4902acb..6cfcef2 100644
--- a/modules/audio_processing/test/audioproc_float_impl.cc
+++ b/modules/audio_processing/test/audioproc_float_impl.cc
@@ -115,25 +115,9 @@
"Activate all of the default components (will be overridden by any "
"other settings)");
ABSL_FLAG(int,
- aec_suppression_level,
- kParameterNotSpecifiedValue,
- "Set the aec suppression level (0-2)");
-ABSL_FLAG(int,
- delay_agnostic,
- kParameterNotSpecifiedValue,
- "Activate (1) or deactivate(0) the AEC delay agnostic mode");
-ABSL_FLAG(int,
- extended_filter,
- kParameterNotSpecifiedValue,
- "Activate (1) or deactivate(0) the AEC extended filter mode");
-ABSL_FLAG(int,
- use_legacy_aec,
- kParameterNotSpecifiedValue,
- "Activate (1) or deactivate(0) the legacy AEC");
-ABSL_FLAG(int,
use_legacy_ns,
kParameterNotSpecifiedValue,
- "Activate (1) or deactivate(0) the legacy AEC");
+ "Activate (1) or deactivate(0) the legacy NS");
ABSL_FLAG(int,
experimental_agc,
kParameterNotSpecifiedValue,
@@ -153,11 +137,6 @@
kParameterNotSpecifiedValue,
"AGC2 level estimation"
" in the experimental AGC. AGC1 level estimation is the default (0)");
-ABSL_FLAG(
- int,
- refined_adaptive_filter,
- kParameterNotSpecifiedValue,
- "Activate (1) or deactivate(0) the refined adaptive filter functionality");
ABSL_FLAG(int,
agc_mode,
kParameterNotSpecifiedValue,
@@ -395,17 +374,6 @@
SetSettingIfFlagSet(absl::GetFlag(FLAGS_ts), &settings.use_ts);
SetSettingIfFlagSet(absl::GetFlag(FLAGS_vad), &settings.use_vad);
SetSettingIfFlagSet(absl::GetFlag(FLAGS_le), &settings.use_le);
- SetSettingIfSpecified(absl::GetFlag(FLAGS_aec_suppression_level),
- &settings.aec_suppression_level);
- SetSettingIfFlagSet(absl::GetFlag(FLAGS_delay_agnostic),
- &settings.use_delay_agnostic);
- SetSettingIfFlagSet(absl::GetFlag(FLAGS_extended_filter),
- &settings.use_extended_filter);
- SetSettingIfFlagSet(absl::GetFlag(FLAGS_refined_adaptive_filter),
- &settings.use_refined_adaptive_filter);
-
- SetSettingIfFlagSet(absl::GetFlag(FLAGS_use_legacy_aec),
- &settings.use_legacy_aec);
SetSettingIfFlagSet(absl::GetFlag(FLAGS_use_legacy_ns),
&settings.use_legacy_ns);
SetSettingIfFlagSet(absl::GetFlag(FLAGS_experimental_agc),
@@ -440,8 +408,6 @@
&settings.stream_delay);
SetSettingIfFlagSet(absl::GetFlag(FLAGS_use_stream_delay),
&settings.use_stream_delay);
- SetSettingIfSpecified(absl::GetFlag(FLAGS_stream_drift_samples),
- &settings.stream_drift_samples);
SetSettingIfSpecified(absl::GetFlag(FLAGS_custom_call_order_file),
&settings.call_order_input_filename);
SetSettingIfSpecified(absl::GetFlag(FLAGS_output_custom_call_order_file),
@@ -525,14 +491,6 @@
"be specified without the AEC being active");
ReportConditionalErrorAndExit(
- ((settings.use_aec && *settings.use_aec && settings.use_legacy_aec &&
- *settings.use_legacy_aec) ||
- (settings.use_aecm && *settings.use_aecm)) &&
- !!settings.linear_aec_output_filename,
- "Error: The linear AEC ouput filename cannot be specified when the "
- "legacy AEC or the AECm are used");
-
- ReportConditionalErrorAndExit(
settings.use_aec && *settings.use_aec && settings.use_aecm &&
*settings.use_aecm,
"Error: The AEC and the AECM cannot be activated at the same time!\n");
@@ -556,13 +514,6 @@
*settings.reverse_output_num_channels <= 0,
"Error: --reverse_output_num_channels must be positive!\n");
- ReportConditionalErrorAndExit(settings.aec_suppression_level &&
- ((*settings.aec_suppression_level) < 1 ||
- (*settings.aec_suppression_level) > 2),
- "Error: --aec_suppression_level must be "
- "specified between 1 and 2. 0 is "
- "deprecated.\n");
-
ReportConditionalErrorAndExit(
settings.agc_target_level && ((*settings.agc_target_level) < 0 ||
(*settings.agc_target_level) > 31),
diff --git a/modules/audio_processing/test/debug_dump_replayer.cc b/modules/audio_processing/test/debug_dump_replayer.cc
index 45600f0..7cb6ec8 100644
--- a/modules/audio_processing/test/debug_dump_replayer.cc
+++ b/modules/audio_processing/test/debug_dump_replayer.cc
@@ -10,7 +10,6 @@
#include "modules/audio_processing/test/debug_dump_replayer.h"
-#include "modules/audio_processing/echo_cancellation_impl.h"
#include "modules/audio_processing/test/protobuf_utils.h"
#include "modules/audio_processing/test/runtime_setting_util.h"
#include "rtc_base/checks.h"
@@ -181,8 +180,6 @@
// These configurations cannot be changed on the fly.
Config config;
RTC_CHECK(msg.has_aec_delay_agnostic_enabled());
- config.Set<DelayAgnostic>(
- new DelayAgnostic(msg.aec_delay_agnostic_enabled()));
RTC_CHECK(msg.has_noise_robust_agc_enabled());
config.Set<ExperimentalAgc>(
@@ -193,8 +190,6 @@
new ExperimentalNs(msg.transient_suppression_enabled()));
RTC_CHECK(msg.has_aec_extended_filter_enabled());
- config.Set<ExtendedFilter>(
- new ExtendedFilter(msg.aec_extended_filter_enabled()));
// We only create APM once, since changes on these fields should not
// happen in current implementation.
@@ -212,12 +207,6 @@
apm_config.echo_canceller.enabled = msg.aec_enabled() || msg.aecm_enabled();
apm_config.echo_canceller.mobile_mode = msg.aecm_enabled();
- RTC_CHECK(msg.has_aec_suppression_level());
- apm_config.echo_canceller.legacy_moderate_suppression_level =
- static_cast<EchoCancellationImpl::SuppressionLevel>(
- msg.aec_suppression_level()) ==
- EchoCancellationImpl::SuppressionLevel::kModerateSuppression;
-
// HPF configs.
RTC_CHECK(msg.has_hpf_enabled());
apm_config.high_pass_filter.enabled = msg.hpf_enabled();
diff --git a/modules/audio_processing/test/debug_dump_test.cc b/modules/audio_processing/test/debug_dump_test.cc
index 9561091..2828091 100644
--- a/modules/audio_processing/test/debug_dump_test.cc
+++ b/modules/audio_processing/test/debug_dump_test.cc
@@ -354,35 +354,6 @@
VerifyDebugDump(generator.dump_file_name());
}
-TEST_F(DebugDumpTest, VerifyRefinedAdaptiveFilterExperimentalString) {
- Config config;
- AudioProcessing::Config apm_config;
- apm_config.echo_canceller.enabled = true;
- apm_config.echo_canceller.use_legacy_aec = true;
- config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(true));
- DebugDumpGenerator generator(config, apm_config);
- generator.StartRecording();
- generator.Process(100);
- generator.StopRecording();
-
- DebugDumpReplayer debug_dump_replayer_;
-
- ASSERT_TRUE(debug_dump_replayer_.SetDumpFile(generator.dump_file_name()));
-
- while (const absl::optional<audioproc::Event> event =
- debug_dump_replayer_.GetNextEvent()) {
- debug_dump_replayer_.RunNextEvent();
- if (event->type() == audioproc::Event::CONFIG) {
- const audioproc::Config* msg = &event->config();
- ASSERT_TRUE(msg->has_experiments_description());
- EXPECT_PRED_FORMAT2(::testing::IsSubstring, "RefinedAdaptiveFilter",
- msg->experiments_description().c_str());
- EXPECT_PRED_FORMAT2(::testing::IsSubstring, "Legacy AEC",
- msg->experiments_description().c_str());
- }
- }
-}
-
TEST_F(DebugDumpTest, VerifyCombinedExperimentalStringInclusive) {
Config config;
AudioProcessing::Config apm_config;
@@ -406,8 +377,6 @@
ASSERT_TRUE(msg->has_experiments_description());
EXPECT_PRED_FORMAT2(::testing::IsSubstring, "EchoController",
msg->experiments_description().c_str());
- EXPECT_PRED_FORMAT2(::testing::IsNotSubstring, "Legacy AEC",
- msg->experiments_description().c_str());
EXPECT_PRED_FORMAT2(::testing::IsSubstring, "AgcClippingLevelExperiment",
msg->experiments_description().c_str());
}
@@ -418,7 +387,6 @@
Config config;
AudioProcessing::Config apm_config;
apm_config.echo_canceller.enabled = true;
- apm_config.echo_canceller.use_legacy_aec = true;
DebugDumpGenerator generator(config, apm_config);
generator.StartRecording();
generator.Process(100);
@@ -434,8 +402,6 @@
if (event->type() == audioproc::Event::CONFIG) {
const audioproc::Config* msg = &event->config();
ASSERT_TRUE(msg->has_experiments_description());
- EXPECT_PRED_FORMAT2(::testing::IsNotSubstring, "EchoController",
- msg->experiments_description().c_str());
EXPECT_PRED_FORMAT2(::testing::IsNotSubstring,
"AgcClippingLevelExperiment",
msg->experiments_description().c_str());
@@ -462,8 +428,6 @@
if (event->type() == audioproc::Event::CONFIG) {
const audioproc::Config* msg = &event->config();
ASSERT_TRUE(msg->has_experiments_description());
- EXPECT_PRED_FORMAT2(::testing::IsNotSubstring, "Legacy AEC",
- msg->experiments_description().c_str());
EXPECT_PRED_FORMAT2(::testing::IsSubstring, "EchoController",
msg->experiments_description().c_str());
}
diff --git a/modules/audio_processing/utility/BUILD.gn b/modules/audio_processing/utility/BUILD.gn
index 745775e..a808625 100644
--- a/modules/audio_processing/utility/BUILD.gn
+++ b/modules/audio_processing/utility/BUILD.gn
@@ -19,17 +19,6 @@
]
}
-rtc_library("block_mean_calculator") {
- sources = [
- "block_mean_calculator.cc",
- "block_mean_calculator.h",
- ]
- deps = [
- "../../../rtc_base:checks",
- "../../../rtc_base:rtc_base_approved",
- ]
-}
-
rtc_library("legacy_delay_estimator") {
sources = [
"delay_estimator.cc",
@@ -113,20 +102,6 @@
]
}
- rtc_library("block_mean_calculator_unittest") {
- testonly = true
-
- sources = [
- "block_mean_calculator_unittest.cc",
- ]
- deps = [
- ":block_mean_calculator",
- "../../../rtc_base:rtc_base_approved",
- "../../../test:test_support",
- "//testing/gtest",
- ]
- }
-
rtc_library("legacy_delay_estimator_unittest") {
testonly = true
diff --git a/modules/audio_processing/utility/block_mean_calculator.cc b/modules/audio_processing/utility/block_mean_calculator.cc
deleted file mode 100644
index 82c1c0f..0000000
--- a/modules/audio_processing/utility/block_mean_calculator.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2016 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "modules/audio_processing/utility/block_mean_calculator.h"
-
-#include "rtc_base/checks.h"
-
-namespace webrtc {
-
-BlockMeanCalculator::BlockMeanCalculator(size_t block_length)
- : block_length_(block_length), count_(0), sum_(0.0), mean_(0.0) {
- RTC_DCHECK(block_length_ != 0);
-}
-
-void BlockMeanCalculator::Reset() {
- Clear();
- mean_ = 0.0;
-}
-
-void BlockMeanCalculator::AddValue(float value) {
- sum_ += value;
- ++count_;
- if (count_ == block_length_) {
- mean_ = sum_ / block_length_;
- Clear();
- }
-}
-
-bool BlockMeanCalculator::EndOfBlock() const {
- return count_ == 0;
-}
-
-float BlockMeanCalculator::GetLatestMean() const {
- return mean_;
-}
-
-// Flush all samples added.
-void BlockMeanCalculator::Clear() {
- count_ = 0;
- sum_ = 0.0;
-}
-
-} // namespace webrtc
diff --git a/modules/audio_processing/utility/block_mean_calculator.h b/modules/audio_processing/utility/block_mean_calculator.h
deleted file mode 100644
index 5ccdbef..0000000
--- a/modules/audio_processing/utility/block_mean_calculator.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_UTILITY_BLOCK_MEAN_CALCULATOR_H_
-#define MODULES_AUDIO_PROCESSING_UTILITY_BLOCK_MEAN_CALCULATOR_H_
-
-#include <stddef.h>
-
-#include "rtc_base/constructor_magic.h"
-
-namespace webrtc {
-
-// BlockMeanCalculator calculates the mean of a block of values. Values are
-// added one after another, and the mean is updated at the end of every block.
-class BlockMeanCalculator {
- public:
- explicit BlockMeanCalculator(size_t block_length);
-
- // Reset.
- void Reset();
-
- // Add one value to the sequence.
- void AddValue(float value);
-
- // Return whether the latest added value was at the end of a block.
- bool EndOfBlock() const;
-
- // Return the latest mean.
- float GetLatestMean() const;
-
- private:
- // Clear all values added.
- void Clear();
-
- const size_t block_length_;
- size_t count_;
- float sum_;
- float mean_;
-
- RTC_DISALLOW_COPY_AND_ASSIGN(BlockMeanCalculator);
-};
-
-} // namespace webrtc
-
-#endif // MODULES_AUDIO_PROCESSING_UTILITY_BLOCK_MEAN_CALCULATOR_H_
diff --git a/modules/audio_processing/utility/block_mean_calculator_unittest.cc b/modules/audio_processing/utility/block_mean_calculator_unittest.cc
deleted file mode 100644
index e829f69..0000000
--- a/modules/audio_processing/utility/block_mean_calculator_unittest.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "modules/audio_processing/utility/block_mean_calculator.h"
-
-#include "test/gtest.h"
-
-namespace webrtc {
-
-TEST(MeanCalculatorTest, Correctness) {
- const size_t kBlockLength = 10;
- BlockMeanCalculator mean_calculator(kBlockLength);
- size_t i = 0;
- float reference = 0.0;
-
- for (; i < kBlockLength - 1; ++i) {
- mean_calculator.AddValue(static_cast<float>(i));
- EXPECT_FALSE(mean_calculator.EndOfBlock());
- }
- mean_calculator.AddValue(static_cast<float>(i++));
- EXPECT_TRUE(mean_calculator.EndOfBlock());
-
- for (; i < 3 * kBlockLength; ++i) {
- const bool end_of_block = i % kBlockLength == 0;
- if (end_of_block) {
- // Sum of (i - kBlockLength) ... (i - 1)
- reference = i - 0.5 * (1 + kBlockLength);
- }
- EXPECT_EQ(mean_calculator.EndOfBlock(), end_of_block);
- EXPECT_EQ(reference, mean_calculator.GetLatestMean());
- mean_calculator.AddValue(static_cast<float>(i));
- }
-}
-
-TEST(MeanCalculatorTest, Reset) {
- const size_t kBlockLength = 10;
- BlockMeanCalculator mean_calculator(kBlockLength);
- for (size_t i = 0; i < kBlockLength - 1; ++i) {
- mean_calculator.AddValue(static_cast<float>(i));
- }
- mean_calculator.Reset();
- size_t i = 0;
- for (; i < kBlockLength - 1; ++i) {
- mean_calculator.AddValue(static_cast<float>(i));
- EXPECT_FALSE(mean_calculator.EndOfBlock());
- }
- mean_calculator.AddValue(static_cast<float>(i));
- EXPECT_TRUE(mean_calculator.EndOfBlock());
- EXPECT_EQ(mean_calculator.GetLatestMean(), 0.5 * (kBlockLength - 1));
-}
-
-} // namespace webrtc