Added support in the AEC for refined filter adaptation.

The following algorithmic functionality was added:
-Add support for an exact regressor power to be computed
 which avoids the issue with the updating of the filter
 sometimes being unstable.
-Lowered the fixed step size of the adaptive filter to 0.05
 which significantly reduces the sensitivity of the
 adaptive filter to near-end noise, nonlinearities,
 doubletalk and the unmodelled echo path tail. It also
 reduces the tracking speed of the adaptive filter but the
 chosen value proved to give a sufficient tradeoff for the
 requirements on the adaptive filter.

To allow the new functionality to be selectively applied the following was done:
-A new Config was added for selectively activating the functionality.
-Functionality was added in the audioprocessing  and echocancellationimpl classes
 for passing the activation of the functionality down to the AEC algorithms.

To make the code for the introduction of the functionality clean,
the following refactoring was done:
-The selection of the step size was moved to a single place.
-The constant for the step size of the adaptive filter in extended filter mode was
 made local.
-The state variable storing the step-size was renamed to a more describing name.

When the new functionality is not activated, the changes
have been tested for bitexactness on Linux.

TBR=minyue@webrtc.org
BUG=webrtc:5778, webrtc:5777

Review URL: https://codereview.webrtc.org/1887003002

Cr-Commit-Position: refs/heads/master@{#12384}
This commit is contained in:
peah
2016-04-15 11:23:33 -07:00
committed by Commit bot
parent 62a216ee1e
commit 0332c2db39
12 changed files with 243 additions and 67 deletions

View File

@ -32,7 +32,8 @@ enum class ConfigOptionID {
kExperimentalNs, kExperimentalNs,
kBeamforming, kBeamforming,
kIntelligibility, kIntelligibility,
kEchoCanceller3 kEchoCanceller3,
kAecRefinedAdaptiveFilter
}; };
// Class Config is designed to ease passing a set of options across webrtc code. // Class Config is designed to ease passing a set of options across webrtc code.

View File

@ -25,6 +25,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "webrtc/base/checks.h"
extern "C" { extern "C" {
#include "webrtc/common_audio/ring_buffer.h" #include "webrtc/common_audio/ring_buffer.h"
} }
@ -238,15 +239,10 @@ static void FilterFar(int num_partitions,
} }
} }
static void ScaleErrorSignal(int extended_filter_enabled, static void ScaleErrorSignal(float mu,
float normal_mu, float error_threshold,
float normal_error_threshold,
float x_pow[PART_LEN1], float x_pow[PART_LEN1],
float ef[2][PART_LEN1]) { float ef[2][PART_LEN1]) {
const float mu = extended_filter_enabled ? kExtendedMu : normal_mu;
const float error_threshold = extended_filter_enabled
? kExtendedErrorThreshold
: normal_error_threshold;
int i; int i;
float abs_ef; float abs_ef;
for (i = 0; i < (PART_LEN1); i++) { for (i = 0; i < (PART_LEN1); i++) {
@ -936,11 +932,38 @@ static int SignalBasedDelayCorrection(AecCore* self) {
return 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(AecCore* aec, static void EchoSubtraction(AecCore* aec,
int num_partitions, int num_partitions,
int extended_filter_enabled, int extended_filter_enabled,
float normal_mu, float filter_step_size,
float normal_error_threshold, float error_threshold,
float* x_fft, float* x_fft,
int* x_fft_buf_block_pos, int* x_fft_buf_block_pos,
float x_fft_buf[2] float x_fft_buf[2]
@ -1001,8 +1024,7 @@ static void EchoSubtraction(AecCore* aec,
sizeof(e_fft[0][0]) * PART_LEN1 * 2); sizeof(e_fft[0][0]) * PART_LEN1 * 2);
// Scale error signal inversely with far power. // Scale error signal inversely with far power.
WebRtcAec_ScaleErrorSignal(extended_filter_enabled, normal_mu, WebRtcAec_ScaleErrorSignal(filter_step_size, error_threshold, x_pow, e_fft);
normal_error_threshold, x_pow, e_fft);
WebRtcAec_FilterAdaptation(num_partitions, *x_fft_buf_block_pos, x_fft_buf, WebRtcAec_FilterAdaptation(num_partitions, *x_fft_buf_block_pos, x_fft_buf,
e_fft, h_fft_buf); e_fft, h_fft_buf);
memcpy(echo_subtractor_output, e, sizeof(float) * PART_LEN); memcpy(echo_subtractor_output, e, sizeof(float) * PART_LEN);
@ -1315,18 +1337,31 @@ static void ProcessBlock(AecCore* aec) {
memcpy(fft, aec->dBuf, sizeof(float) * PART_LEN2); memcpy(fft, aec->dBuf, sizeof(float) * PART_LEN2);
Fft(fft, df); Fft(fft, df);
// Power smoothing // Power smoothing.
for (i = 0; i < PART_LEN1; i++) { if (aec->refined_adaptive_filter_enabled) {
for (i = 0; i < PART_LEN1; ++i) {
far_spectrum = (x_fft_ptr[i] * x_fft_ptr[i]) +
(x_fft_ptr[PART_LEN1 + i] * x_fft_ptr[PART_LEN1 + 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 = (x_fft_ptr[i] * x_fft_ptr[i]) + far_spectrum = (x_fft_ptr[i] * x_fft_ptr[i]) +
(x_fft_ptr[PART_LEN1 + i] * x_fft_ptr[PART_LEN1 + i]); (x_fft_ptr[PART_LEN1 + i] * x_fft_ptr[PART_LEN1 + i]);
aec->xPow[i] = aec->xPow[i] =
gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum; gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum;
// Calculate absolute spectra // Calculate the magnitude spectrum.
abs_far_spectrum[i] = sqrtf(far_spectrum); abs_far_spectrum[i] = sqrtf(far_spectrum);
}
}
for (i = 0; i < PART_LEN1; ++i) {
near_spectrum = df[0][i] * df[0][i] + df[1][i] * df[1][i]; near_spectrum = df[0][i] * df[0][i] + df[1][i] * df[1][i];
aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum; aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum;
// Calculate absolute spectra // Calculate the magnitude spectrum.
abs_near_spectrum[i] = sqrtf(near_spectrum); abs_near_spectrum[i] = sqrtf(near_spectrum);
} }
@ -1379,7 +1414,7 @@ static void ProcessBlock(AecCore* aec) {
// Perform echo subtraction. // Perform echo subtraction.
EchoSubtraction(aec, aec->num_partitions, aec->extended_filter_enabled, EchoSubtraction(aec, aec->num_partitions, aec->extended_filter_enabled,
aec->normal_mu, aec->normal_error_threshold, &x_fft[0][0], aec->filter_step_size, aec->error_threshold, &x_fft[0][0],
&aec->xfBufBlockPos, aec->xfBuf, nearend_ptr, aec->xPow, &aec->xfBufBlockPos, aec->xfBuf, nearend_ptr, aec->xPow,
aec->wfBuf, echo_subtractor_output); aec->wfBuf, echo_subtractor_output);
@ -1485,6 +1520,7 @@ AecCore* WebRtcAec_CreateAec() {
#endif #endif
aec->extended_filter_enabled = 0; aec->extended_filter_enabled = 0;
aec->aec3_enabled = 0; aec->aec3_enabled = 0;
aec->refined_adaptive_filter_enabled = false;
// Assembly optimization // Assembly optimization
WebRtcAec_FilterFar = FilterFar; WebRtcAec_FilterFar = FilterFar;
@ -1548,18 +1584,53 @@ void WebRtcAec_FreeAec(AecCore* aec) {
delete aec; 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 WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
int i; int i;
aec->sampFreq = sampFreq; aec->sampFreq = sampFreq;
SetAdaptiveFilterStepSize(aec);
SetErrorThreshold(aec);
if (sampFreq == 8000) { if (sampFreq == 8000) {
aec->normal_mu = 0.6f;
aec->normal_error_threshold = 2e-6f;
aec->num_bands = 1; aec->num_bands = 1;
} else { } else {
aec->normal_mu = 0.5f;
aec->normal_error_threshold = 1.5e-6f;
aec->num_bands = (size_t)(sampFreq / 16000); aec->num_bands = (size_t)(sampFreq / 16000);
} }
@ -1930,9 +2001,20 @@ int WebRtcAec_aec3_enabled(AecCore* self) {
return self->aec3_enabled; return self->aec3_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) { void WebRtcAec_enable_extended_filter(AecCore* self, int enable) {
self->extended_filter_enabled = enable; self->extended_filter_enabled = enable;
SetAdaptiveFilterStepSize(self);
SetErrorThreshold(self);
self->num_partitions = enable ? kExtendedNumPartitions : kNormalNumPartitions; self->num_partitions = enable ? kExtendedNumPartitions : kNormalNumPartitions;
// Update the delay estimator with filter length. See InitAEC() for details. // Update the delay estimator with filter length. See InitAEC() for details.
WebRtc_set_allowed_offset(self->delay_estimator, self->num_partitions / 2); WebRtc_set_allowed_offset(self->delay_estimator, self->num_partitions / 2);

View File

@ -120,6 +120,12 @@ void WebRtcAec_enable_aec3(AecCore* self, int enable);
// Returns 1 if the next generation aec is enabled and zero if disabled. // Returns 1 if the next generation aec is enabled and zero if disabled.
int WebRtcAec_aec3_enabled(AecCore* self); int WebRtcAec_aec3_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. // Enables or disables extended filter mode. Non-zero enables, zero disables.
void WebRtcAec_enable_extended_filter(AecCore* self, int enable); void WebRtcAec_enable_extended_filter(AecCore* self, int enable);

View File

@ -35,11 +35,6 @@ enum {
kHistorySizeBlocks = 125 kHistorySizeBlocks = 125
}; };
// Extended filter adaptation parameters.
// TODO(ajm): No narrowband tuning yet.
static const float kExtendedMu = 0.4f;
static const float kExtendedErrorThreshold = 1.0e-6f;
typedef struct PowerLevel { typedef struct PowerLevel {
PowerLevel(); PowerLevel();
@ -126,12 +121,12 @@ struct AecCore {
int system_delay; // Current system delay buffered in AEC. int system_delay; // Current system delay buffered in AEC.
int mult; // sampling frequency multiple int mult; // sampling frequency multiple
int sampFreq; int sampFreq = 16000;
size_t num_bands; size_t num_bands;
uint32_t seed; uint32_t seed;
float normal_mu; // stepsize float filter_step_size; // stepsize
float normal_error_threshold; // error threshold float error_threshold; // error threshold
int noiseEstCtr; int noiseEstCtr;
@ -178,6 +173,7 @@ struct AecCore {
int extended_filter_enabled; int extended_filter_enabled;
// 1 = next generation aec mode enabled, 0 = disabled. // 1 = next generation aec mode enabled, 0 = disabled.
int aec3_enabled; int aec3_enabled;
bool refined_adaptive_filter_enabled;
// Runtime selection of number of filter partitions. // Runtime selection of number of filter partitions.
int num_partitions; int num_partitions;
@ -210,9 +206,8 @@ typedef void (*WebRtcAecFilterFar)(
float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1], float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
float y_fft[2][PART_LEN1]); float y_fft[2][PART_LEN1]);
extern WebRtcAecFilterFar WebRtcAec_FilterFar; extern WebRtcAecFilterFar WebRtcAec_FilterFar;
typedef void (*WebRtcAecScaleErrorSignal)(int extended_filter_enabled, typedef void (*WebRtcAecScaleErrorSignal)(float mu,
float normal_mu, float error_threshold,
float normal_error_threshold,
float x_pow[PART_LEN1], float x_pow[PART_LEN1],
float ef[2][PART_LEN1]); float ef[2][PART_LEN1]);
extern WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal; extern WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal;

View File

@ -707,15 +707,10 @@ void WebRtcAec_OverdriveAndSuppress_mips(AecCore* aec,
} }
} }
void WebRtcAec_ScaleErrorSignal_mips(int extended_filter_enabled, void WebRtcAec_ScaleErrorSignal_mips(float mu,
float normal_mu, float error_threshold,
float normal_error_threshold,
float x_pow[PART_LEN1], float x_pow[PART_LEN1],
float ef[2][PART_LEN1]) { float ef[2][PART_LEN1]) {
const float mu = extended_filter_enabled ? kExtendedMu : normal_mu;
const float error_threshold = extended_filter_enabled
? kExtendedErrorThreshold
: normal_error_threshold;
int len = (PART_LEN1); int len = (PART_LEN1);
float* ef0 = ef[0]; float* ef0 = ef[0];
float* ef1 = ef[1]; float* ef1 = ef[1];

View File

@ -127,15 +127,10 @@ static float32x4_t vsqrtq_f32(float32x4_t s) {
} }
#endif // WEBRTC_ARCH_ARM64 #endif // WEBRTC_ARCH_ARM64
static void ScaleErrorSignalNEON(int extended_filter_enabled, static void ScaleErrorSignalNEON(float mu,
float normal_mu, float error_threshold,
float normal_error_threshold,
float x_pow[PART_LEN1], float x_pow[PART_LEN1],
float ef[2][PART_LEN1]) { float ef[2][PART_LEN1]) {
const float mu = extended_filter_enabled ? kExtendedMu : normal_mu;
const float error_threshold = extended_filter_enabled
? kExtendedErrorThreshold
: normal_error_threshold;
const float32x4_t k1e_10f = vdupq_n_f32(1e-10f); const float32x4_t k1e_10f = vdupq_n_f32(1e-10f);
const float32x4_t kMu = vmovq_n_f32(mu); const float32x4_t kMu = vmovq_n_f32(mu);
const float32x4_t kThresh = vmovq_n_f32(error_threshold); const float32x4_t kThresh = vmovq_n_f32(error_threshold);

View File

@ -79,17 +79,13 @@ static void FilterFarSSE2(int num_partitions,
} }
} }
static void ScaleErrorSignalSSE2(int extended_filter_enabled, static void ScaleErrorSignalSSE2(float mu,
float normal_mu, float error_threshold,
float normal_error_threshold,
float x_pow[PART_LEN1], float x_pow[PART_LEN1],
float ef[2][PART_LEN1]) { float ef[2][PART_LEN1]) {
const __m128 k1e_10f = _mm_set1_ps(1e-10f); const __m128 k1e_10f = _mm_set1_ps(1e-10f);
const __m128 kMu = extended_filter_enabled ? _mm_set1_ps(kExtendedMu) const __m128 kMu = _mm_set1_ps(mu);
: _mm_set1_ps(normal_mu); const __m128 kThresh = _mm_set1_ps(error_threshold);
const __m128 kThresh = extended_filter_enabled
? _mm_set1_ps(kExtendedErrorThreshold)
: _mm_set1_ps(normal_error_threshold);
int i; int i;
// vectorized code (four at once) // vectorized code (four at once)
@ -124,10 +120,6 @@ static void ScaleErrorSignalSSE2(int extended_filter_enabled,
} }
// scalar code for the remaining items. // scalar code for the remaining items.
{ {
const float mu = extended_filter_enabled ? kExtendedMu : normal_mu;
const float error_threshold = extended_filter_enabled
? kExtendedErrorThreshold
: normal_error_threshold;
for (; i < (PART_LEN1); i++) { for (; i < (PART_LEN1); i++) {
float abs_ef; float abs_ef;
ef[0][i] /= (x_pow[i] + 1e-10f); ef[0][i] /= (x_pow[i] + 1e-10f);

View File

@ -415,7 +415,16 @@ bool EchoCancellationImpl::is_aec3_enabled() const {
std::string EchoCancellationImpl::GetExperimentsDescription() { std::string EchoCancellationImpl::GetExperimentsDescription() {
rtc::CritScope cs(crit_capture_); rtc::CritScope cs(crit_capture_);
return aec3_enabled_ ? "AEC3" : ""; std::string description = (aec3_enabled_ ? "AEC3" : "");
if (refined_adaptive_filter_enabled_) {
description += ";RefinedAdaptiveFilter";
}
return description;
}
bool EchoCancellationImpl::is_refined_adaptive_filter_enabled() const {
rtc::CritScope cs(crit_capture_);
return refined_adaptive_filter_enabled_;
} }
bool EchoCancellationImpl::is_extended_filter_enabled() const { bool EchoCancellationImpl::is_extended_filter_enabled() const {
@ -534,6 +543,8 @@ void EchoCancellationImpl::SetExtraOptions(const Config& config) {
rtc::CritScope cs(crit_capture_); rtc::CritScope cs(crit_capture_);
extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled; extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled;
delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled; delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled;
refined_adaptive_filter_enabled_ =
config.Get<RefinedAdaptiveFilter>().enabled;
aec3_enabled_ = config.Get<EchoCanceller3>().enabled; aec3_enabled_ = config.Get<EchoCanceller3>().enabled;
} }
Configure(); Configure();
@ -556,6 +567,9 @@ int EchoCancellationImpl::Configure() {
delay_agnostic_enabled_ ? 1 : 0); delay_agnostic_enabled_ ? 1 : 0);
WebRtcAec_enable_aec3(WebRtcAec_aec_core(canceller->state()), WebRtcAec_enable_aec3(WebRtcAec_aec_core(canceller->state()),
aec3_enabled_ ? 1 : 0); aec3_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); const int handle_error = WebRtcAec_set_config(canceller->state(), config);
if (handle_error != AudioProcessing::kNoError) { if (handle_error != AudioProcessing::kNoError) {
error = AudioProcessing::kNoError; error = AudioProcessing::kNoError;

View File

@ -48,6 +48,7 @@ class EchoCancellationImpl : public EchoCancellation {
bool is_extended_filter_enabled() const; bool is_extended_filter_enabled() const;
bool is_aec3_enabled() const; bool is_aec3_enabled() const;
std::string GetExperimentsDescription(); std::string GetExperimentsDescription();
bool is_refined_adaptive_filter_enabled() const;
// Checks whether the module is enabled. Must only be // Checks whether the module is enabled. Must only be
// called from the render side of APM as otherwise // called from the render side of APM as otherwise
@ -102,6 +103,7 @@ class EchoCancellationImpl : public EchoCancellation {
bool extended_filter_enabled_ GUARDED_BY(crit_capture_); bool extended_filter_enabled_ GUARDED_BY(crit_capture_);
bool delay_agnostic_enabled_ GUARDED_BY(crit_capture_); bool delay_agnostic_enabled_ GUARDED_BY(crit_capture_);
bool aec3_enabled_ GUARDED_BY(crit_capture_); bool aec3_enabled_ GUARDED_BY(crit_capture_);
bool refined_adaptive_filter_enabled_ GUARDED_BY(crit_capture_) = false;
size_t render_queue_element_max_size_ GUARDED_BY(crit_render_) size_t render_queue_element_max_size_ GUARDED_BY(crit_render_)
GUARDED_BY(crit_capture_); GUARDED_BY(crit_capture_);

View File

@ -80,6 +80,18 @@ struct EchoCanceller3 {
bool enabled; bool enabled;
}; };
// Enables the refined linear filter adaptation in the echo canceller.
// This configuration only applies to EchoCancellation and not
// EchoControlMobile. 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 // Enables delay-agnostic echo cancellation. This feature relies on internally
// estimated delays between the process and reverse streams, thus not relying // estimated delays between the process and reverse streams, thus not relying
// on reported system delays. This configuration only applies to // on reported system delays. This configuration only applies to

View File

@ -341,6 +341,83 @@ TEST_F(DebugDumpTest, ToggleDelayAgnosticAec) {
VerifyDebugDump(generator.dump_file_name()); VerifyDebugDump(generator.dump_file_name());
} }
TEST_F(DebugDumpTest, VerifyRefinedAdaptiveFilterExperimentalString) {
Config config;
config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(true));
DebugDumpGenerator generator(config);
generator.StartRecording();
generator.Process(100);
generator.StopRecording();
DebugDumpReplayer debug_dump_replayer_;
ASSERT_TRUE(debug_dump_replayer_.SetDumpFile(generator.dump_file_name()));
while (const rtc::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());
}
}
}
TEST_F(DebugDumpTest, VerifyCombinedExperimentalStringInclusive) {
Config config;
config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(true));
config.Set<EchoCanceller3>(new EchoCanceller3(true));
DebugDumpGenerator generator(config);
generator.StartRecording();
generator.Process(100);
generator.StopRecording();
DebugDumpReplayer debug_dump_replayer_;
ASSERT_TRUE(debug_dump_replayer_.SetDumpFile(generator.dump_file_name()));
while (const rtc::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, "AEC3",
msg->experiments_description().c_str());
}
}
}
TEST_F(DebugDumpTest, VerifyCombinedExperimentalStringExclusive) {
Config config;
config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(true));
DebugDumpGenerator generator(config);
generator.StartRecording();
generator.Process(100);
generator.StopRecording();
DebugDumpReplayer debug_dump_replayer_;
ASSERT_TRUE(debug_dump_replayer_.SetDumpFile(generator.dump_file_name()));
while (const rtc::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::IsNotSubstring, "AEC3",
msg->experiments_description().c_str());
}
}
}
TEST_F(DebugDumpTest, VerifyAec3ExperimentalString) { TEST_F(DebugDumpTest, VerifyAec3ExperimentalString) {
Config config; Config config;
config.Set<EchoCanceller3>(new EchoCanceller3(true)); config.Set<EchoCanceller3>(new EchoCanceller3(true));
@ -358,8 +435,9 @@ TEST_F(DebugDumpTest, VerifyAec3ExperimentalString) {
debug_dump_replayer_.RunNextEvent(); debug_dump_replayer_.RunNextEvent();
if (event->type() == audioproc::Event::CONFIG) { if (event->type() == audioproc::Event::CONFIG) {
const audioproc::Config* msg = &event->config(); const audioproc::Config* msg = &event->config();
EXPECT_TRUE(msg->has_experiments_description()); ASSERT_TRUE(msg->has_experiments_description());
EXPECT_NE(std::string::npos, msg->experiments_description().find("AEC3")); EXPECT_PRED_FORMAT2(testing::IsSubstring, "AEC3",
msg->experiments_description().c_str());
} }
} }
} }
@ -380,7 +458,7 @@ TEST_F(DebugDumpTest, VerifyEmptyExperimentalString) {
debug_dump_replayer_.RunNextEvent(); debug_dump_replayer_.RunNextEvent();
if (event->type() == audioproc::Event::CONFIG) { if (event->type() == audioproc::Event::CONFIG) {
const audioproc::Config* msg = &event->config(); const audioproc::Config* msg = &event->config();
EXPECT_TRUE(msg->has_experiments_description()); ASSERT_TRUE(msg->has_experiments_description());
EXPECT_EQ(0u, msg->experiments_description().size()); EXPECT_EQ(0u, msg->experiments_description().size());
} }
} }

View File

@ -82,6 +82,7 @@ void usage() {
printf(" --extended_filter\n"); printf(" --extended_filter\n");
printf(" --no_reported_delay\n"); printf(" --no_reported_delay\n");
printf(" --aec3\n"); printf(" --aec3\n");
printf(" --refined_adaptive_filter\n");
printf("\n -aecm Echo control mobile\n"); printf("\n -aecm Echo control mobile\n");
printf(" --aecm_echo_path_in_file FILE\n"); printf(" --aecm_echo_path_in_file FILE\n");
printf(" --aecm_echo_path_out_file FILE\n"); printf(" --aecm_echo_path_out_file FILE\n");
@ -271,6 +272,9 @@ void void_main(int argc, char* argv[]) {
} else if (strcmp(argv[i], "--aec3") == 0) { } else if (strcmp(argv[i], "--aec3") == 0) {
config.Set<EchoCanceller3>(new EchoCanceller3(true)); config.Set<EchoCanceller3>(new EchoCanceller3(true));
} else if (strcmp(argv[i], "--refined_adaptive_filter") == 0) {
config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(true));
} else if (strcmp(argv[i], "-aecm") == 0) { } else if (strcmp(argv[i], "-aecm") == 0) {
ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true)); ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));