Added the ability to adjust the AEC3 performance for large rooms
This CL exposes the parameter for adjusting the AEC3 performance for large rooms. Bug: webrtc:7519 Review-Url: https://codereview.webrtc.org/2967603002 Cr-Commit-Position: refs/heads/master@{#18862}
This commit is contained in:
parent
4583db4967
commit
697a590314
@ -305,7 +305,7 @@ TEST(AdaptiveFirFilter, FilterAndAdapt) {
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> n(kBlockSize, 0.f);
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
AecState aec_state;
|
||||
AecState aec_state(0.f);
|
||||
RenderSignalAnalyzer render_signal_analyzer;
|
||||
std::vector<float> e(kBlockSize, 0.f);
|
||||
std::array<float, kFftLength> s;
|
||||
|
||||
@ -78,10 +78,11 @@ constexpr int kEchoPathChangeCounterMax = 2 * kNumBlocksPerSecond;
|
||||
|
||||
int AecState::instance_count_ = 0;
|
||||
|
||||
AecState::AecState()
|
||||
AecState::AecState(float echo_decay)
|
||||
: data_dumper_(
|
||||
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
||||
echo_path_change_counter_(kEchoPathChangeCounterInitial) {}
|
||||
echo_path_change_counter_(kEchoPathChangeCounterInitial),
|
||||
echo_decay_factor_(echo_decay) {}
|
||||
|
||||
AecState::~AecState() = default;
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ class ApmDataDumper;
|
||||
// Handles the state and the conditions for the echo removal functionality.
|
||||
class AecState {
|
||||
public:
|
||||
AecState();
|
||||
explicit AecState(float echo_decay);
|
||||
~AecState();
|
||||
|
||||
// Returns whether the linear filter estimate is usable.
|
||||
@ -79,7 +79,7 @@ class AecState {
|
||||
|
||||
// Returns the decay factor for the echo reverberation.
|
||||
// TODO(peah): Make this adaptive.
|
||||
float ReverbDecayFactor() const { return 0.f; }
|
||||
float ReverbDecayFactor() const { return echo_decay_factor_; }
|
||||
|
||||
// Returns whether the echo suppression gain should be forced to zero.
|
||||
bool ForcedZeroGain() const { return force_zero_gain_; }
|
||||
@ -113,8 +113,8 @@ class AecState {
|
||||
rtc::Optional<size_t> filter_delay_;
|
||||
rtc::Optional<size_t> external_delay_;
|
||||
size_t blocks_since_last_saturation_ = 1000;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AecState);
|
||||
const float echo_decay_factor_;
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AecState);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -18,7 +18,7 @@ namespace webrtc {
|
||||
// Verify the general functionality of AecState
|
||||
TEST(AecState, NormalUsage) {
|
||||
ApmDataDumper data_dumper(42);
|
||||
AecState state;
|
||||
AecState state(0.f);
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 30,
|
||||
std::vector<size_t>(1, 30));
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main = {};
|
||||
@ -148,7 +148,7 @@ TEST(AecState, NormalUsage) {
|
||||
|
||||
// Verifies the a non-significant delay is correctly identified.
|
||||
TEST(AecState, NonSignificantDelay) {
|
||||
AecState state;
|
||||
AecState state(0.f);
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 30,
|
||||
std::vector<size_t>(1, 30));
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
@ -172,7 +172,7 @@ TEST(AecState, NonSignificantDelay) {
|
||||
// Verifies the delay for a converged filter is correctly identified.
|
||||
TEST(AecState, ConvergedFilterDelay) {
|
||||
constexpr int kFilterLength = 10;
|
||||
AecState state;
|
||||
AecState state(0.f);
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 30,
|
||||
std::vector<size_t>(1, 30));
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
@ -203,7 +203,7 @@ TEST(AecState, ConvergedFilterDelay) {
|
||||
|
||||
// Verify that the externally reported delay is properly reported and converted.
|
||||
TEST(AecState, ExternalDelay) {
|
||||
AecState state;
|
||||
AecState state(0.f);
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
std::array<float, kFftLengthBy2Plus1> E2_shadow;
|
||||
std::array<float, kFftLengthBy2Plus1> Y2;
|
||||
|
||||
@ -168,29 +168,33 @@ void BlockProcessorImpl::UpdateEchoLeakageStatus(bool leakage_detected) {
|
||||
|
||||
} // namespace
|
||||
|
||||
BlockProcessor* BlockProcessor::Create(int sample_rate_hz) {
|
||||
BlockProcessor* BlockProcessor::Create(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz) {
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer(
|
||||
RenderDelayBuffer::Create(NumBandsForRate(sample_rate_hz)));
|
||||
std::unique_ptr<RenderDelayController> delay_controller(
|
||||
RenderDelayController::Create(sample_rate_hz));
|
||||
std::unique_ptr<EchoRemover> echo_remover(
|
||||
EchoRemover::Create(sample_rate_hz));
|
||||
return Create(sample_rate_hz, std::move(render_buffer),
|
||||
EchoRemover::Create(config, sample_rate_hz));
|
||||
return Create(config, sample_rate_hz, std::move(render_buffer),
|
||||
std::move(delay_controller), std::move(echo_remover));
|
||||
}
|
||||
|
||||
BlockProcessor* BlockProcessor::Create(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz,
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer) {
|
||||
std::unique_ptr<RenderDelayController> delay_controller(
|
||||
RenderDelayController::Create(sample_rate_hz));
|
||||
std::unique_ptr<EchoRemover> echo_remover(
|
||||
EchoRemover::Create(sample_rate_hz));
|
||||
return Create(sample_rate_hz, std::move(render_buffer),
|
||||
EchoRemover::Create(config, sample_rate_hz));
|
||||
return Create(config, sample_rate_hz, std::move(render_buffer),
|
||||
std::move(delay_controller), std::move(echo_remover));
|
||||
}
|
||||
|
||||
BlockProcessor* BlockProcessor::Create(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz,
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer,
|
||||
std::unique_ptr<RenderDelayController> delay_controller,
|
||||
|
||||
@ -23,12 +23,16 @@ namespace webrtc {
|
||||
// Class for performing echo cancellation on 64 sample blocks of audio data.
|
||||
class BlockProcessor {
|
||||
public:
|
||||
static BlockProcessor* Create(int sample_rate_hz);
|
||||
static BlockProcessor* Create(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz);
|
||||
// Only used for testing purposes.
|
||||
static BlockProcessor* Create(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz,
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer);
|
||||
static BlockProcessor* Create(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz,
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer,
|
||||
std::unique_ptr<RenderDelayController> delay_controller,
|
||||
|
||||
@ -36,8 +36,8 @@ using testing::_;
|
||||
// Verifies that the basic BlockProcessor functionality works and that the API
|
||||
// methods are callable.
|
||||
void RunBasicSetupAndApiCallTest(int sample_rate_hz) {
|
||||
std::unique_ptr<BlockProcessor> block_processor(
|
||||
BlockProcessor::Create(sample_rate_hz));
|
||||
std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create(
|
||||
AudioProcessing::Config::EchoCanceller3(), sample_rate_hz));
|
||||
std::vector<std::vector<float>> block(NumBandsForRate(sample_rate_hz),
|
||||
std::vector<float>(kBlockSize, 0.f));
|
||||
|
||||
@ -48,8 +48,8 @@ void RunBasicSetupAndApiCallTest(int sample_rate_hz) {
|
||||
|
||||
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||
void RunRenderBlockSizeVerificationTest(int sample_rate_hz) {
|
||||
std::unique_ptr<BlockProcessor> block_processor(
|
||||
BlockProcessor::Create(sample_rate_hz));
|
||||
std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create(
|
||||
AudioProcessing::Config::EchoCanceller3(), sample_rate_hz));
|
||||
std::vector<std::vector<float>> block(
|
||||
NumBandsForRate(sample_rate_hz), std::vector<float>(kBlockSize - 1, 0.f));
|
||||
|
||||
@ -57,8 +57,8 @@ void RunRenderBlockSizeVerificationTest(int sample_rate_hz) {
|
||||
}
|
||||
|
||||
void RunCaptureBlockSizeVerificationTest(int sample_rate_hz) {
|
||||
std::unique_ptr<BlockProcessor> block_processor(
|
||||
BlockProcessor::Create(sample_rate_hz));
|
||||
std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create(
|
||||
AudioProcessing::Config::EchoCanceller3(), sample_rate_hz));
|
||||
std::vector<std::vector<float>> block(
|
||||
NumBandsForRate(sample_rate_hz), std::vector<float>(kBlockSize - 1, 0.f));
|
||||
|
||||
@ -69,8 +69,8 @@ void RunRenderNumBandsVerificationTest(int sample_rate_hz) {
|
||||
const size_t wrong_num_bands = NumBandsForRate(sample_rate_hz) < 3
|
||||
? NumBandsForRate(sample_rate_hz) + 1
|
||||
: 1;
|
||||
std::unique_ptr<BlockProcessor> block_processor(
|
||||
BlockProcessor::Create(sample_rate_hz));
|
||||
std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create(
|
||||
AudioProcessing::Config::EchoCanceller3(), sample_rate_hz));
|
||||
std::vector<std::vector<float>> block(wrong_num_bands,
|
||||
std::vector<float>(kBlockSize, 0.f));
|
||||
|
||||
@ -81,8 +81,8 @@ void RunCaptureNumBandsVerificationTest(int sample_rate_hz) {
|
||||
const size_t wrong_num_bands = NumBandsForRate(sample_rate_hz) < 3
|
||||
? NumBandsForRate(sample_rate_hz) + 1
|
||||
: 1;
|
||||
std::unique_ptr<BlockProcessor> block_processor(
|
||||
BlockProcessor::Create(sample_rate_hz));
|
||||
std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create(
|
||||
AudioProcessing::Config::EchoCanceller3(), sample_rate_hz));
|
||||
std::vector<std::vector<float>> block(wrong_num_bands,
|
||||
std::vector<float>(kBlockSize, 0.f));
|
||||
|
||||
@ -126,7 +126,8 @@ TEST(BlockProcessor, DISABLED_DelayControllerIntegration) {
|
||||
.Times(kNumBlocks + 1)
|
||||
.WillRepeatedly(Return(0));
|
||||
std::unique_ptr<BlockProcessor> block_processor(
|
||||
BlockProcessor::Create(rate, std::move(render_delay_buffer_mock)));
|
||||
BlockProcessor::Create(AudioProcessing::Config::EchoCanceller3(), rate,
|
||||
std::move(render_delay_buffer_mock)));
|
||||
|
||||
std::vector<std::vector<float>> render_block(
|
||||
NumBandsForRate(rate), std::vector<float>(kBlockSize, 0.f));
|
||||
@ -180,7 +181,8 @@ TEST(BlockProcessor, DISABLED_SubmoduleIntegration) {
|
||||
.Times(kNumBlocks);
|
||||
|
||||
std::unique_ptr<BlockProcessor> block_processor(BlockProcessor::Create(
|
||||
rate, std::move(render_delay_buffer_mock),
|
||||
AudioProcessing::Config::EchoCanceller3(), rate,
|
||||
std::move(render_delay_buffer_mock),
|
||||
std::move(render_delay_controller_mock), std::move(echo_remover_mock)));
|
||||
|
||||
std::vector<std::vector<float>> render_block(
|
||||
@ -238,7 +240,9 @@ TEST(BlockProcessor, VerifyCaptureNumBandsCheck) {
|
||||
|
||||
// Verifiers that the verification for null ProcessCapture input works.
|
||||
TEST(BlockProcessor, NullProcessCaptureParameter) {
|
||||
EXPECT_DEATH(std::unique_ptr<BlockProcessor>(BlockProcessor::Create(8000))
|
||||
EXPECT_DEATH(std::unique_ptr<BlockProcessor>(
|
||||
BlockProcessor::Create(
|
||||
AudioProcessing::Config::EchoCanceller3(), 8000))
|
||||
->ProcessCapture(false, false, nullptr),
|
||||
"");
|
||||
}
|
||||
@ -247,7 +251,8 @@ TEST(BlockProcessor, NullProcessCaptureParameter) {
|
||||
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
|
||||
// tests on test bots has been fixed.
|
||||
TEST(BlockProcessor, DISABLED_WrongSampleRate) {
|
||||
EXPECT_DEATH(std::unique_ptr<BlockProcessor>(BlockProcessor::Create(8001)),
|
||||
EXPECT_DEATH(std::unique_ptr<BlockProcessor>(BlockProcessor::Create(
|
||||
AudioProcessing::Config::EchoCanceller3(), 8001)),
|
||||
"");
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ TEST(ComfortNoiseGenerator, NullLowerBandNoise) {
|
||||
std::array<float, kFftLengthBy2Plus1> N2;
|
||||
FftData noise;
|
||||
EXPECT_DEATH(ComfortNoiseGenerator(DetectOptimization())
|
||||
.Compute(AecState(), N2, nullptr, &noise),
|
||||
.Compute(AecState(0.f), N2, nullptr, &noise),
|
||||
"");
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ TEST(ComfortNoiseGenerator, NullUpperBandNoise) {
|
||||
std::array<float, kFftLengthBy2Plus1> N2;
|
||||
FftData noise;
|
||||
EXPECT_DEATH(ComfortNoiseGenerator(DetectOptimization())
|
||||
.Compute(AecState(), N2, &noise, nullptr),
|
||||
.Compute(AecState(0.f), N2, &noise, nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ TEST(ComfortNoiseGenerator, TestOptimizations) {
|
||||
|
||||
TEST(ComfortNoiseGenerator, CorrectLevel) {
|
||||
ComfortNoiseGenerator cng(DetectOptimization());
|
||||
AecState aec_state;
|
||||
AecState aec_state(0.f);
|
||||
|
||||
std::array<float, kFftLengthBy2Plus1> N2;
|
||||
N2.fill(1000.f * 1000.f);
|
||||
|
||||
@ -200,11 +200,14 @@ void EchoCanceller3::RenderWriter::Insert(AudioBuffer* input) {
|
||||
|
||||
int EchoCanceller3::instance_count_ = 0;
|
||||
|
||||
EchoCanceller3::EchoCanceller3(int sample_rate_hz, bool use_highpass_filter)
|
||||
EchoCanceller3::EchoCanceller3(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz,
|
||||
bool use_highpass_filter)
|
||||
: EchoCanceller3(sample_rate_hz,
|
||||
use_highpass_filter,
|
||||
std::unique_ptr<BlockProcessor>(
|
||||
BlockProcessor::Create(sample_rate_hz))) {}
|
||||
BlockProcessor::Create(config, sample_rate_hz))) {}
|
||||
EchoCanceller3::EchoCanceller3(int sample_rate_hz,
|
||||
bool use_highpass_filter,
|
||||
std::unique_ptr<BlockProcessor> block_processor)
|
||||
@ -331,7 +334,7 @@ std::string EchoCanceller3::ToString(
|
||||
|
||||
bool EchoCanceller3::Validate(
|
||||
const AudioProcessing::Config::EchoCanceller3& config) {
|
||||
return true;
|
||||
return (config.echo_decay >= 0.f && config.echo_decay < 1.f);
|
||||
}
|
||||
|
||||
void EchoCanceller3::EmptyRenderQueue() {
|
||||
|
||||
@ -63,7 +63,9 @@ class Aec3RenderQueueItemVerifier {
|
||||
class EchoCanceller3 {
|
||||
public:
|
||||
// Normal c-tor to use.
|
||||
EchoCanceller3(int sample_rate_hz, bool use_highpass_filter);
|
||||
EchoCanceller3(const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz,
|
||||
bool use_highpass_filter);
|
||||
// Testing c-tor that is used only for testing purposes.
|
||||
EchoCanceller3(int sample_rate_hz,
|
||||
bool use_highpass_filter,
|
||||
|
||||
@ -495,7 +495,8 @@ class EchoCanceller3Tester {
|
||||
// This test verifies that a buffer overrun in the render swapqueue is
|
||||
// properly reported.
|
||||
void RunRenderPipelineSwapQueueOverrunReturnValueTest() {
|
||||
EchoCanceller3 aec3(sample_rate_hz_, false);
|
||||
EchoCanceller3 aec3(AudioProcessing::Config::EchoCanceller3(),
|
||||
sample_rate_hz_, false);
|
||||
|
||||
constexpr size_t kRenderTransferQueueSize = 30;
|
||||
for (size_t k = 0; k < 2; ++k) {
|
||||
@ -524,7 +525,8 @@ class EchoCanceller3Tester {
|
||||
// Set aec3_sample_rate_hz to be different from sample_rate_hz_ in such a
|
||||
// way that the number of bands for the rates are different.
|
||||
const int aec3_sample_rate_hz = sample_rate_hz_ == 48000 ? 32000 : 48000;
|
||||
EchoCanceller3 aec3(aec3_sample_rate_hz, false);
|
||||
EchoCanceller3 aec3(AudioProcessing::Config::EchoCanceller3(),
|
||||
aec3_sample_rate_hz, false);
|
||||
PopulateInputFrame(frame_length_, 0, &render_buffer_.channels_f()[0][0], 0);
|
||||
|
||||
EXPECT_DEATH(aec3.AnalyzeRender(&render_buffer_), "");
|
||||
@ -537,7 +539,8 @@ class EchoCanceller3Tester {
|
||||
// Set aec3_sample_rate_hz to be different from sample_rate_hz_ in such a
|
||||
// way that the number of bands for the rates are different.
|
||||
const int aec3_sample_rate_hz = sample_rate_hz_ == 48000 ? 32000 : 48000;
|
||||
EchoCanceller3 aec3(aec3_sample_rate_hz, false);
|
||||
EchoCanceller3 aec3(AudioProcessing::Config::EchoCanceller3(),
|
||||
aec3_sample_rate_hz, false);
|
||||
PopulateInputFrame(frame_length_, num_bands_, 0,
|
||||
&capture_buffer_.split_bands_f(0)[0], 100);
|
||||
EXPECT_DEATH(aec3.ProcessCapture(&capture_buffer_, false), "");
|
||||
@ -550,7 +553,8 @@ class EchoCanceller3Tester {
|
||||
// Set aec3_sample_rate_hz to be different from sample_rate_hz_ in such a
|
||||
// way that the band frame lengths are different.
|
||||
const int aec3_sample_rate_hz = sample_rate_hz_ == 8000 ? 16000 : 8000;
|
||||
EchoCanceller3 aec3(aec3_sample_rate_hz, false);
|
||||
EchoCanceller3 aec3(AudioProcessing::Config::EchoCanceller3(),
|
||||
aec3_sample_rate_hz, false);
|
||||
|
||||
OptionalBandSplit();
|
||||
PopulateInputFrame(frame_length_, 0, &render_buffer_.channels_f()[0][0], 0);
|
||||
@ -565,7 +569,8 @@ class EchoCanceller3Tester {
|
||||
// Set aec3_sample_rate_hz to be different from sample_rate_hz_ in such a
|
||||
// way that the band frame lengths are different.
|
||||
const int aec3_sample_rate_hz = sample_rate_hz_ == 8000 ? 16000 : 8000;
|
||||
EchoCanceller3 aec3(aec3_sample_rate_hz, false);
|
||||
EchoCanceller3 aec3(AudioProcessing::Config::EchoCanceller3(),
|
||||
aec3_sample_rate_hz, false);
|
||||
|
||||
OptionalBandSplit();
|
||||
PopulateInputFrame(frame_length_, num_bands_, 0,
|
||||
@ -677,6 +682,21 @@ TEST(EchoCanceller3Messaging, EchoLeakage) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EchoCanceller3, ConfigValidation) {
|
||||
AudioProcessing::Config::EchoCanceller3 config;
|
||||
|
||||
config.echo_decay = 0.f;
|
||||
EXPECT_TRUE(EchoCanceller3::Validate(config));
|
||||
config.echo_decay = 0.9f;
|
||||
EXPECT_TRUE(EchoCanceller3::Validate(config));
|
||||
config.echo_decay = -0.1f;
|
||||
EXPECT_FALSE(EchoCanceller3::Validate(config));
|
||||
config.echo_decay = 1.0f;
|
||||
EXPECT_FALSE(EchoCanceller3::Validate(config));
|
||||
config.echo_decay = 1.1f;
|
||||
EXPECT_FALSE(EchoCanceller3::Validate(config));
|
||||
}
|
||||
|
||||
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||
|
||||
TEST(EchoCanceller3InputCheck, WrongCaptureNumBandsCheckVerification) {
|
||||
@ -706,19 +726,28 @@ TEST(EchoCanceller3InputCheck, WrongCaptureFrameLengthCheckVerification) {
|
||||
// Verifiers that the verification for null input to the render analysis api
|
||||
// call works.
|
||||
TEST(EchoCanceller3InputCheck, NullRenderAnalysisParameter) {
|
||||
EXPECT_DEATH(EchoCanceller3(8000, false).AnalyzeRender(nullptr), "");
|
||||
EXPECT_DEATH(
|
||||
EchoCanceller3(AudioProcessing::Config::EchoCanceller3(), 8000, false)
|
||||
.AnalyzeRender(nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
// Verifiers that the verification for null input to the capture analysis api
|
||||
// call works.
|
||||
TEST(EchoCanceller3InputCheck, NullCaptureAnalysisParameter) {
|
||||
EXPECT_DEATH(EchoCanceller3(8000, false).AnalyzeCapture(nullptr), "");
|
||||
EXPECT_DEATH(
|
||||
EchoCanceller3(AudioProcessing::Config::EchoCanceller3(), 8000, false)
|
||||
.AnalyzeCapture(nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
// Verifiers that the verification for null input to the capture processing api
|
||||
// call works.
|
||||
TEST(EchoCanceller3InputCheck, NullCaptureProcessingParameter) {
|
||||
EXPECT_DEATH(EchoCanceller3(8000, false).ProcessCapture(nullptr, false), "");
|
||||
EXPECT_DEATH(
|
||||
EchoCanceller3(AudioProcessing::Config::EchoCanceller3(), 8000, false)
|
||||
.ProcessCapture(nullptr, false),
|
||||
"");
|
||||
}
|
||||
|
||||
// Verifies the check for correct sample rate.
|
||||
@ -726,7 +755,9 @@ TEST(EchoCanceller3InputCheck, NullCaptureProcessingParameter) {
|
||||
// tests on test bots has been fixed.
|
||||
TEST(EchoCanceller3InputCheck, DISABLED_WrongSampleRate) {
|
||||
ApmDataDumper data_dumper(0);
|
||||
EXPECT_DEATH(EchoCanceller3(8001, false), "");
|
||||
EXPECT_DEATH(
|
||||
EchoCanceller3(AudioProcessing::Config::EchoCanceller3(), 8001, false),
|
||||
"");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -49,7 +49,9 @@ void LinearEchoPower(const FftData& E,
|
||||
// Class for removing the echo from the capture signal.
|
||||
class EchoRemoverImpl final : public EchoRemover {
|
||||
public:
|
||||
explicit EchoRemoverImpl(int sample_rate_hz);
|
||||
explicit EchoRemoverImpl(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz);
|
||||
~EchoRemoverImpl() override;
|
||||
|
||||
// Removes the echo from a block of samples from the capture signal. The
|
||||
@ -90,7 +92,9 @@ class EchoRemoverImpl final : public EchoRemover {
|
||||
|
||||
int EchoRemoverImpl::instance_count_ = 0;
|
||||
|
||||
EchoRemoverImpl::EchoRemoverImpl(int sample_rate_hz)
|
||||
EchoRemoverImpl::EchoRemoverImpl(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz)
|
||||
: fft_(),
|
||||
data_dumper_(
|
||||
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
||||
@ -99,7 +103,8 @@ EchoRemoverImpl::EchoRemoverImpl(int sample_rate_hz)
|
||||
subtractor_(data_dumper_.get(), optimization_),
|
||||
suppression_gain_(optimization_),
|
||||
cng_(optimization_),
|
||||
suppression_filter_(sample_rate_hz_) {
|
||||
suppression_filter_(sample_rate_hz_),
|
||||
aec_state_(config.echo_decay) {
|
||||
RTC_DCHECK(ValidFullBandRate(sample_rate_hz));
|
||||
}
|
||||
|
||||
@ -221,8 +226,10 @@ void EchoRemoverImpl::ProcessCapture(
|
||||
|
||||
} // namespace
|
||||
|
||||
EchoRemover* EchoRemover::Create(int sample_rate_hz) {
|
||||
return new EchoRemoverImpl(sample_rate_hz);
|
||||
EchoRemover* EchoRemover::Create(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz) {
|
||||
return new EchoRemoverImpl(config, sample_rate_hz);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -16,13 +16,16 @@
|
||||
#include "webrtc/base/optional.h"
|
||||
#include "webrtc/modules/audio_processing/aec3/echo_path_variability.h"
|
||||
#include "webrtc/modules/audio_processing/aec3/render_buffer.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Class for removing the echo from the capture signal.
|
||||
class EchoRemover {
|
||||
public:
|
||||
static EchoRemover* Create(int sample_rate_hz);
|
||||
static EchoRemover* Create(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz);
|
||||
virtual ~EchoRemover() = default;
|
||||
|
||||
// Removes the echo from a block of samples from the capture signal. The
|
||||
|
||||
@ -126,7 +126,7 @@ TEST(DbMetric, Constructor) {
|
||||
// Verify the general functionality of EchoRemoverMetrics.
|
||||
TEST(EchoRemoverMetrics, NormalUsage) {
|
||||
EchoRemoverMetrics metrics;
|
||||
AecState aec_state;
|
||||
AecState aec_state(0.f);
|
||||
std::array<float, kFftLengthBy2Plus1> comfort_noise_spectrum;
|
||||
std::array<float, kFftLengthBy2Plus1> suppressor_gain;
|
||||
comfort_noise_spectrum.fill(10.f);
|
||||
|
||||
@ -45,7 +45,8 @@ std::string ProduceDebugText(int sample_rate_hz, int delay) {
|
||||
TEST(EchoRemover, BasicApiCalls) {
|
||||
for (auto rate : {8000, 16000, 32000, 48000}) {
|
||||
SCOPED_TRACE(ProduceDebugText(rate));
|
||||
std::unique_ptr<EchoRemover> remover(EchoRemover::Create(rate));
|
||||
std::unique_ptr<EchoRemover> remover(
|
||||
EchoRemover::Create(AudioProcessing::Config::EchoCanceller3(), rate));
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer(
|
||||
RenderDelayBuffer::Create(NumBandsForRate(rate)));
|
||||
|
||||
@ -74,14 +75,17 @@ TEST(EchoRemover, BasicApiCalls) {
|
||||
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
|
||||
// tests on test bots has been fixed.
|
||||
TEST(EchoRemover, DISABLED_WrongSampleRate) {
|
||||
EXPECT_DEATH(std::unique_ptr<EchoRemover>(EchoRemover::Create(8001)), "");
|
||||
EXPECT_DEATH(std::unique_ptr<EchoRemover>(EchoRemover::Create(
|
||||
AudioProcessing::Config::EchoCanceller3(), 8001)),
|
||||
"");
|
||||
}
|
||||
|
||||
// Verifies the check for the capture block size.
|
||||
TEST(EchoRemover, WrongCaptureBlockSize) {
|
||||
for (auto rate : {8000, 16000, 32000, 48000}) {
|
||||
SCOPED_TRACE(ProduceDebugText(rate));
|
||||
std::unique_ptr<EchoRemover> remover(EchoRemover::Create(rate));
|
||||
std::unique_ptr<EchoRemover> remover(
|
||||
EchoRemover::Create(AudioProcessing::Config::EchoCanceller3(), rate));
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer(
|
||||
RenderDelayBuffer::Create(NumBandsForRate(rate)));
|
||||
std::vector<std::vector<float>> capture(
|
||||
@ -101,7 +105,8 @@ TEST(EchoRemover, WrongCaptureBlockSize) {
|
||||
TEST(EchoRemover, DISABLED_WrongCaptureNumBands) {
|
||||
for (auto rate : {16000, 32000, 48000}) {
|
||||
SCOPED_TRACE(ProduceDebugText(rate));
|
||||
std::unique_ptr<EchoRemover> remover(EchoRemover::Create(rate));
|
||||
std::unique_ptr<EchoRemover> remover(
|
||||
EchoRemover::Create(AudioProcessing::Config::EchoCanceller3(), rate));
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer(
|
||||
RenderDelayBuffer::Create(NumBandsForRate(rate)));
|
||||
std::vector<std::vector<float>> capture(
|
||||
@ -118,7 +123,8 @@ TEST(EchoRemover, DISABLED_WrongCaptureNumBands) {
|
||||
|
||||
// Verifies the check for non-null capture block.
|
||||
TEST(EchoRemover, NullCapture) {
|
||||
std::unique_ptr<EchoRemover> remover(EchoRemover::Create(8000));
|
||||
std::unique_ptr<EchoRemover> remover(
|
||||
EchoRemover::Create(AudioProcessing::Config::EchoCanceller3(), 8000));
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer(
|
||||
RenderDelayBuffer::Create(3));
|
||||
EchoPathVariability echo_path_variability(false, false);
|
||||
@ -144,7 +150,8 @@ TEST(EchoRemover, BasicEchoRemoval) {
|
||||
EchoPathVariability echo_path_variability(false, false);
|
||||
for (size_t delay_samples : {0, 64, 150, 200, 301}) {
|
||||
SCOPED_TRACE(ProduceDebugText(rate, delay_samples));
|
||||
std::unique_ptr<EchoRemover> remover(EchoRemover::Create(rate));
|
||||
std::unique_ptr<EchoRemover> remover(
|
||||
EchoRemover::Create(AudioProcessing::Config::EchoCanceller3(), rate));
|
||||
std::unique_ptr<RenderDelayBuffer> render_buffer(
|
||||
RenderDelayBuffer::Create(NumBandsForRate(rate)));
|
||||
std::vector<std::unique_ptr<DelayBuffer<float>>> delay_buffers(x.size());
|
||||
|
||||
@ -53,7 +53,7 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
||||
Random random_generator(42U);
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
AecState aec_state;
|
||||
AecState aec_state(0.f);
|
||||
RenderSignalAnalyzer render_signal_analyzer;
|
||||
std::array<float, kFftLength> s;
|
||||
FftData S;
|
||||
|
||||
@ -22,7 +22,7 @@ namespace webrtc {
|
||||
|
||||
// Verifies that the check for non-null output residual echo power works.
|
||||
TEST(ResidualEchoEstimator, NullResidualEchoPowerOutput) {
|
||||
AecState aec_state;
|
||||
AecState aec_state(0.f);
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 10,
|
||||
std::vector<size_t>(1, 10));
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>> H2;
|
||||
@ -37,7 +37,7 @@ TEST(ResidualEchoEstimator, NullResidualEchoPowerOutput) {
|
||||
|
||||
TEST(ResidualEchoEstimator, BasicTest) {
|
||||
ResidualEchoEstimator estimator;
|
||||
AecState aec_state;
|
||||
AecState aec_state(0.f);
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 10,
|
||||
std::vector<size_t>(1, 10));
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
|
||||
@ -47,7 +47,7 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
||||
Random random_generator(42U);
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
AecState aec_state;
|
||||
AecState aec_state(0.f);
|
||||
RenderSignalAnalyzer render_signal_analyzer;
|
||||
std::array<float, kFftLength> s;
|
||||
FftData S;
|
||||
|
||||
@ -40,7 +40,7 @@ float RunSubtractorTest(int num_blocks_to_process,
|
||||
std::array<float, kFftLengthBy2Plus1> Y2;
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
std::array<float, kFftLengthBy2Plus1> E2_shadow;
|
||||
AecState aec_state;
|
||||
AecState aec_state(0.f);
|
||||
x_old.fill(0.f);
|
||||
Y2.fill(0.f);
|
||||
E2_main.fill(0.f);
|
||||
@ -109,7 +109,7 @@ TEST(Subtractor, DISABLED_NullOutput) {
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
|
||||
EXPECT_DEATH(subtractor.Process(render_buffer, y, render_signal_analyzer,
|
||||
AecState(), nullptr),
|
||||
AecState(0.f), nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ TEST(Subtractor, WrongCaptureSize) {
|
||||
SubtractorOutput output;
|
||||
|
||||
EXPECT_DEATH(subtractor.Process(render_buffer, y, render_signal_analyzer,
|
||||
AecState(), &output),
|
||||
AecState(0.f), &output),
|
||||
"");
|
||||
}
|
||||
|
||||
|
||||
@ -1881,8 +1881,8 @@ void AudioProcessingImpl::InitializeLowCutFilter() {
|
||||
|
||||
void AudioProcessingImpl::InitializeEchoCanceller3() {
|
||||
if (capture_nonlocked_.echo_canceller3_enabled) {
|
||||
private_submodules_->echo_canceller3.reset(
|
||||
new EchoCanceller3(proc_sample_rate_hz(), true));
|
||||
private_submodules_->echo_canceller3.reset(new EchoCanceller3(
|
||||
config_.echo_canceller3, proc_sample_rate_hz(), true));
|
||||
} else {
|
||||
private_submodules_->echo_canceller3.reset();
|
||||
}
|
||||
|
||||
@ -268,6 +268,7 @@ class AudioProcessing : public rtc::RefCountInterface {
|
||||
// does not yet have the desired behavior.
|
||||
struct EchoCanceller3 {
|
||||
bool enabled = false;
|
||||
float echo_decay = 0.f;
|
||||
} echo_canceller3;
|
||||
|
||||
// Enables the next generation AGC functionality. This feature replaces the
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user