APM unit test: echo path gain change events notified.

This CL adds two unit tests to make sure that, when an echo path gain
change occurs, the echo canceller is notified.
Such a change can be caused by (i) a pre-amplifier gain change or
(ii) an analog gain change.

Bug: webrtc:7494
Change-Id: Ia47cfbbc5694340cd3e760d8d3c3393f79897a9d
Reviewed-on: https://webrtc-review.googlesource.com/c/111780
Commit-Queue: Alessio Bazzica <alessiob@webrtc.org>
Reviewed-by: Per Åhgren <peah@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26190}
This commit is contained in:
Alessio Bazzica 2018-12-17 09:44:06 +01:00 committed by Commit Bot
parent 949099d50d
commit e449805f42
3 changed files with 147 additions and 2 deletions

View File

@ -459,6 +459,8 @@ if (rtc_include_tests) {
":audioproc_unittest_proto",
":runtime_settings_protobuf_utils",
"../../api/audio:audio_frame_api",
"../../api/audio:echo_control",
"../../rtc_base:rtc_base_tests_utils",
"../../rtc_base:rtc_task_queue",
"aec_dump",
"aec_dump:aec_dump_unittests",
@ -485,6 +487,7 @@ if (rtc_include_tests) {
"test/echo_canceller_test_tools.cc",
"test/echo_canceller_test_tools.h",
"test/echo_canceller_test_tools_unittest.cc",
"test/echo_control_mock.h",
"test/test_utils.h",
"voice_detection_unittest.cc",
]

View File

@ -10,18 +10,24 @@
#include "modules/audio_processing/audio_processing_impl.h"
#include <memory>
#include "absl/memory/memory.h"
#include "modules/audio_processing/include/audio_processing.h"
#include "modules/audio_processing/test/echo_control_mock.h"
#include "modules/audio_processing/test/test_utils.h"
#include "rtc_base/checks.h"
#include "rtc_base/refcountedobject.h"
#include "rtc_base/scoped_ref_ptr.h"
#include "test/gmock.h"
#include "test/gtest.h"
using ::testing::Invoke;
namespace webrtc {
namespace {
using ::testing::Invoke;
using ::testing::NotNull;
class MockInitialize : public AudioProcessingImpl {
public:
explicit MockInitialize(const webrtc::Config& config)
@ -36,6 +42,28 @@ class MockInitialize : public AudioProcessingImpl {
MOCK_CONST_METHOD0(Release, rtc::RefCountReleaseStatus());
};
// Creates MockEchoControl instances and provides a raw pointer access to
// the next created one. The raw pointer is meant to be used with gmock.
// Returning a pointer of the next created MockEchoControl instance is necessary
// for the following reasons: (i) gmock expectations must be set before any call
// occurs, (ii) APM is initialized the first time that
// AudioProcessingImpl::ProcessStream() is called and the initialization leads
// to the creation of a new EchoControl object.
class MockEchoControlFactory : public EchoControlFactory {
public:
MockEchoControlFactory() : next_mock_(absl::make_unique<MockEchoControl>()) {}
// Returns a pointer to the next MockEchoControl that this factory creates.
MockEchoControl* GetNext() const { return next_mock_.get(); }
std::unique_ptr<EchoControl> Create(int sample_rate_hz) override {
std::unique_ptr<EchoControl> mock = std::move(next_mock_);
next_mock_ = absl::make_unique<MockEchoControl>();
return mock;
}
private:
std::unique_ptr<MockEchoControl> next_mock_;
};
void InitializeAudioFrame(size_t input_rate,
size_t num_channels,
AudioFrame* frame) {
@ -183,6 +211,87 @@ TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
<< "Frame should be amplified.";
}
TEST(AudioProcessingImplTest,
EchoControllerObservesPreAmplifierEchoPathGainChange) {
// Tests that the echo controller observes an echo path gain change when the
// pre-amplifier submodule changes the gain.
auto echo_control_factory = absl::make_unique<MockEchoControlFactory>();
const auto* echo_control_factory_ptr = echo_control_factory.get();
std::unique_ptr<AudioProcessing> apm(
AudioProcessingBuilder()
.SetEchoControlFactory(std::move(echo_control_factory))
.Create());
apm->gain_control()->Enable(false); // Disable AGC.
apm->gain_control()->set_mode(GainControl::Mode::kFixedDigital);
webrtc::AudioProcessing::Config apm_config;
apm_config.gain_controller2.enabled = false;
apm_config.pre_amplifier.enabled = true;
apm_config.pre_amplifier.fixed_gain_factor = 1.f;
apm->ApplyConfig(apm_config);
AudioFrame frame;
constexpr int16_t kAudioLevel = 10000;
constexpr size_t kSampleRateHz = 48000;
constexpr size_t kNumChannels = 2;
InitializeAudioFrame(kSampleRateHz, kNumChannels, &frame);
FillFixedFrame(kAudioLevel, &frame);
MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
EXPECT_CALL(*echo_control_mock, AnalyzeCapture(NotNull())).Times(1);
EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), false)).Times(1);
apm->ProcessStream(&frame);
EXPECT_CALL(*echo_control_mock, AnalyzeCapture(NotNull())).Times(1);
EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), true)).Times(1);
apm->SetRuntimeSetting(
AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
apm->ProcessStream(&frame);
}
TEST(AudioProcessingImplTest,
EchoControllerObservesAnalogAgc1EchoPathGainChange) {
// Tests that the echo controller observes an echo path gain change when the
// AGC1 analog adaptive submodule changes the analog gain.
auto echo_control_factory = absl::make_unique<MockEchoControlFactory>();
const auto* echo_control_factory_ptr = echo_control_factory.get();
std::unique_ptr<AudioProcessing> apm(
AudioProcessingBuilder()
.SetEchoControlFactory(std::move(echo_control_factory))
.Create());
apm->gain_control()->Enable(true); // Enable AGC.
apm->gain_control()->set_mode(GainControl::Mode::kAdaptiveAnalog);
webrtc::AudioProcessing::Config apm_config;
apm_config.gain_controller2.enabled = false;
apm_config.pre_amplifier.enabled = false;
apm->ApplyConfig(apm_config);
AudioFrame frame;
constexpr int16_t kAudioLevel = 1000;
constexpr size_t kSampleRateHz = 48000;
constexpr size_t kNumChannels = 2;
InitializeAudioFrame(kSampleRateHz, kNumChannels, &frame);
FillFixedFrame(kAudioLevel, &frame);
MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
const int initial_analog_gain = apm->gain_control()->stream_analog_level();
EXPECT_CALL(*echo_control_mock, AnalyzeCapture(NotNull())).Times(1);
EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), false)).Times(1);
apm->ProcessStream(&frame);
// Force an analog gain change if it did not happen.
if (initial_analog_gain == apm->gain_control()->stream_analog_level()) {
apm->gain_control()->set_stream_analog_level(initial_analog_gain + 1);
}
EXPECT_CALL(*echo_control_mock, AnalyzeCapture(NotNull())).Times(1);
EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), true)).Times(1);
apm->ProcessStream(&frame);
}
TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
// Make sure that signal changes caused by a render pre-processing sub-module
// take place before any echo detector analysis.

View File

@ -0,0 +1,33 @@
/*
* 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.
*/
#ifndef MODULES_AUDIO_PROCESSING_TEST_ECHO_CONTROL_MOCK_H_
#define MODULES_AUDIO_PROCESSING_TEST_ECHO_CONTROL_MOCK_H_
#include "api/audio/echo_control.h"
#include "test/gmock.h"
namespace webrtc {
class AudioBuffer;
class MockEchoControl : public EchoControl {
public:
MOCK_METHOD1(AnalyzeRender, void(AudioBuffer* render));
MOCK_METHOD1(AnalyzeCapture, void(AudioBuffer* capture));
MOCK_METHOD2(ProcessCapture,
void(AudioBuffer* capture, bool echo_path_change));
MOCK_CONST_METHOD0(GetMetrics, EchoControl::Metrics());
MOCK_METHOD1(SetAudioBufferDelay, void(size_t delay_ms));
};
} // namespace webrtc
#endif // MODULES_AUDIO_PROCESSING_TEST_ECHO_CONTROL_MOCK_H_