From 05a700444239861ef1b702919f83f16b5b95daaa Mon Sep 17 00:00:00 2001 From: Sam Zackrisson Date: Fri, 28 Sep 2018 13:39:13 +0000 Subject: [PATCH] Revert "Remove APM-internal usage of EchoControlMobile" This reverts commit 2fbb83b16b4c2c1712cbe898ca3ba42d6da3e96f. Reason for revert: Speculative revert over failing Chromium bot: https://ci.chromium.org/p/chromium/builders/luci.chromium.webrtc.fyi/WebRTC%20Chromium%20FYI%20Android%20Tests%20%28dbg%29%20%28M%20Nexus5X%29/117 Original change's description: > Remove APM-internal usage of EchoControlMobile > > This is a sibling CL to a similar one for EchoCancellation: > https://webrtc-review.googlesource.com/c/src/+/97603 > > - EchoControlMobileImpl will no longer inherit EchoControlMobile. > - Removes usage of AudioProcessing::echo_control_mobile() inside most of > the audio processing module and unit tests. > > The CL breaks audioproc_f backwards compatibility: It can no longer > use all recorded settings (comfort noise, routing mode), but prints an > error message when unsupported settings are encountered. > > Tested: audioproc_f with .wav and aecdump inputs. > Bug: webrtc:9535 > Change-Id: I63c3c81bcaf44021315978e1a0f3e42173b988ce > Reviewed-on: https://webrtc-review.googlesource.com/101621 > Reviewed-by: Alex Loiko > Commit-Queue: Sam Zackrisson > Cr-Commit-Position: refs/heads/master@{#24888} TBR=saza@webrtc.org,aleloi@webrtc.org Change-Id: I1f8a27ac291f2cdc16c8daa32e399b74d489dbb9 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: webrtc:9535 Reviewed-on: https://webrtc-review.googlesource.com/102642 Reviewed-by: Sam Zackrisson Commit-Queue: Sam Zackrisson Cr-Commit-Position: refs/heads/master@{#24895} --- modules/audio_processing/BUILD.gn | 3 +- .../audio_processing/audio_processing_impl.cc | 5 +- .../audio_processing_unittest.cc | 68 +++++ modules/audio_processing/debug.proto | 4 +- .../echo_control_mobile_bit_exact_unittest.cc | 224 ---------------- .../echo_control_mobile_impl.cc | 16 +- .../echo_control_mobile_impl.h | 60 +---- .../echo_control_mobile_proxy.cc | 22 +- .../echo_control_mobile_proxy.h | 5 +- .../echo_control_mobile_unittest.cc | 250 ++++++++++++++---- .../test/aec_dump_based_simulator.cc | 34 ++- .../test/audio_processing_simulator.cc | 14 +- .../test/audio_processing_simulator.h | 2 + .../test/audioproc_float_impl.cc | 14 + .../test/debug_dump_replayer.cc | 11 + 15 files changed, 372 insertions(+), 360 deletions(-) delete mode 100644 modules/audio_processing/echo_control_mobile_bit_exact_unittest.cc diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn index 84b89066be..78e00917f7 100644 --- a/modules/audio_processing/BUILD.gn +++ b/modules/audio_processing/BUILD.gn @@ -345,7 +345,6 @@ if (rtc_include_tests) { "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", "test/fake_recording_device_unittest.cc", @@ -432,7 +431,7 @@ if (rtc_include_tests) { "audio_processing_impl_unittest.cc", "audio_processing_unittest.cc", "echo_cancellation_bit_exact_unittest.cc", - "echo_control_mobile_bit_exact_unittest.cc", + "echo_control_mobile_unittest.cc", "echo_detector/circular_buffer_unittest.cc", "echo_detector/mean_variance_estimator_unittest.cc", "echo_detector/moving_max_unittest.cc", diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc index ac28096108..a60cd7ebc3 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc @@ -679,8 +679,9 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) { public_submodules_->echo_cancellation->Enable( config_.echo_canceller.enabled && !config_.echo_canceller.mobile_mode); - public_submodules_->echo_control_mobile->Enable( - config_.echo_canceller.enabled && config_.echo_canceller.mobile_mode); + static_cast(public_submodules_->echo_control_mobile.get()) + ->Enable(config_.echo_canceller.enabled && + config_.echo_canceller.mobile_mode); public_submodules_->echo_cancellation->set_suppression_level( config.echo_canceller.legacy_moderate_suppression_level diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc index 3f0decc957..869f576f2a 100644 --- a/modules/audio_processing/audio_processing_unittest.cc +++ b/modules/audio_processing/audio_processing_unittest.cc @@ -943,6 +943,74 @@ TEST_F(ApmTest, DISABLED_EchoCancellationReportsCorrectDelays) { } } +TEST_F(ApmTest, EchoControlMobile) { + // Turn AECM on (and AEC off) + Init(16000, 16000, 16000, 2, 2, 2, false); + EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true)); + EXPECT_TRUE(apm_->echo_control_mobile()->is_enabled()); + + // Toggle routing modes + EchoControlMobile::RoutingMode mode[] = { + EchoControlMobile::kQuietEarpieceOrHeadset, + EchoControlMobile::kEarpiece, + EchoControlMobile::kLoudEarpiece, + EchoControlMobile::kSpeakerphone, + EchoControlMobile::kLoudSpeakerphone, + }; + for (size_t i = 0; i < arraysize(mode); i++) { + EXPECT_EQ(apm_->kNoError, + apm_->echo_control_mobile()->set_routing_mode(mode[i])); + EXPECT_EQ(mode[i], + apm_->echo_control_mobile()->routing_mode()); + } + // Turn comfort noise off/on + EXPECT_EQ(apm_->kNoError, + apm_->echo_control_mobile()->enable_comfort_noise(false)); + EXPECT_FALSE(apm_->echo_control_mobile()->is_comfort_noise_enabled()); + EXPECT_EQ(apm_->kNoError, + apm_->echo_control_mobile()->enable_comfort_noise(true)); + EXPECT_TRUE(apm_->echo_control_mobile()->is_comfort_noise_enabled()); + // Set and get echo path + const size_t echo_path_size = + apm_->echo_control_mobile()->echo_path_size_bytes(); + std::unique_ptr echo_path_in(new char[echo_path_size]); + std::unique_ptr echo_path_out(new char[echo_path_size]); + EXPECT_EQ(apm_->kNullPointerError, + apm_->echo_control_mobile()->SetEchoPath(NULL, echo_path_size)); + EXPECT_EQ(apm_->kNullPointerError, + apm_->echo_control_mobile()->GetEchoPath(NULL, echo_path_size)); + EXPECT_EQ(apm_->kBadParameterError, + apm_->echo_control_mobile()->GetEchoPath(echo_path_out.get(), 1)); + EXPECT_EQ(apm_->kNoError, + apm_->echo_control_mobile()->GetEchoPath(echo_path_out.get(), + echo_path_size)); + for (size_t i = 0; i < echo_path_size; i++) { + echo_path_in[i] = echo_path_out[i] + 1; + } + EXPECT_EQ(apm_->kBadParameterError, + apm_->echo_control_mobile()->SetEchoPath(echo_path_in.get(), 1)); + EXPECT_EQ(apm_->kNoError, + apm_->echo_control_mobile()->SetEchoPath(echo_path_in.get(), + echo_path_size)); + EXPECT_EQ(apm_->kNoError, + apm_->echo_control_mobile()->GetEchoPath(echo_path_out.get(), + echo_path_size)); + for (size_t i = 0; i < echo_path_size; i++) { + EXPECT_EQ(echo_path_in[i], echo_path_out[i]); + } + + // Process a few frames with NS in the default disabled state. This exercises + // a different codepath than with it enabled. + EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0)); + EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); + EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0)); + EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); + + // Turn AECM off + EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false)); + EXPECT_FALSE(apm_->echo_control_mobile()->is_enabled()); +} + TEST_F(ApmTest, GainControl) { // Testing gain modes EXPECT_EQ(apm_->kNoError, diff --git a/modules/audio_processing/debug.proto b/modules/audio_processing/debug.proto index 40bd5d516e..10a98d53f6 100644 --- a/modules/audio_processing/debug.proto +++ b/modules/audio_processing/debug.proto @@ -55,8 +55,8 @@ message Config { optional int32 aec_suppression_level = 5; // Mobile AEC. optional bool aecm_enabled = 6; - optional bool aecm_comfort_noise_enabled = 7 [deprecated = true]; - optional int32 aecm_routing_mode = 8 [deprecated = true]; + optional bool aecm_comfort_noise_enabled = 7; + optional int32 aecm_routing_mode = 8; // Automatic gain controller. optional bool agc_enabled = 9; optional int32 agc_mode = 10; diff --git a/modules/audio_processing/echo_control_mobile_bit_exact_unittest.cc b/modules/audio_processing/echo_control_mobile_bit_exact_unittest.cc deleted file mode 100644 index 8b8369260a..0000000000 --- a/modules/audio_processing/echo_control_mobile_bit_exact_unittest.cc +++ /dev/null @@ -1,224 +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. - */ -#include - -#include "api/array_view.h" -#include "modules/audio_processing/audio_buffer.h" -#include "modules/audio_processing/echo_control_mobile_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 { - -// TODO(peah): Increase the number of frames to proces when the issue of -// non repeatable test results have been found. -const int kNumFramesToProcess = 200; - -void SetupComponent(int sample_rate_hz, - EchoControlMobileImpl::RoutingMode routing_mode, - bool comfort_noise_enabled, - EchoControlMobileImpl* echo_control_mobile) { - echo_control_mobile->Initialize( - sample_rate_hz > 16000 ? 16000 : sample_rate_hz, 1, 1); - echo_control_mobile->Enable(true); - echo_control_mobile->set_routing_mode(routing_mode); - echo_control_mobile->enable_comfort_noise(comfort_noise_enabled); -} - -void ProcessOneFrame(int sample_rate_hz, - int stream_delay_ms, - AudioBuffer* render_audio_buffer, - AudioBuffer* capture_audio_buffer, - EchoControlMobileImpl* echo_control_mobile) { - if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) { - render_audio_buffer->SplitIntoFrequencyBands(); - capture_audio_buffer->SplitIntoFrequencyBands(); - } - - std::vector render_audio; - EchoControlMobileImpl::PackRenderAudioBuffer( - render_audio_buffer, 1, render_audio_buffer->num_channels(), - &render_audio); - echo_control_mobile->ProcessRenderAudio(render_audio); - - echo_control_mobile->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, - EchoControlMobileImpl::RoutingMode routing_mode, - bool comfort_noise_enabled, - const rtc::ArrayView& output_reference) { - rtc::CriticalSection crit_render; - rtc::CriticalSection crit_capture; - EchoControlMobileImpl echo_control_mobile(&crit_render, &crit_capture); - SetupComponent(sample_rate_hz, routing_mode, comfort_noise_enabled, - &echo_control_mobile); - - 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.num_frames(), render_config.num_channels(), - render_config.num_frames(), 1, render_config.num_frames()); - test::InputAudioFile render_file( - test::GetApmRenderTestVectorFileName(sample_rate_hz)); - std::vector render_input(samples_per_channel * num_channels); - - const StreamConfig capture_config(sample_rate_hz, num_channels, false); - AudioBuffer capture_buffer( - capture_config.num_frames(), capture_config.num_channels(), - capture_config.num_frames(), 1, capture_config.num_frames()); - test::InputAudioFile capture_file( - test::GetApmCaptureTestVectorFileName(sample_rate_hz)); - std::vector 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, &render_buffer, - &capture_buffer, &echo_control_mobile); - } - - // Extract and verify the test results. - std::vector capture_output; - test::ExtractVectorFromAudioBuffer(capture_config, &capture_buffer, - &capture_output); - - // 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)); -} - -} // namespace - -// TODO(peah): Renable once the integer overflow issue in aecm_core.c:932:69 -// has been solved. -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono8kHz_LoudSpeakerPhone_CngOn_StreamDelay0) { - const float kOutputReference[] = {0.005280f, 0.002380f, -0.000427f}; - - RunBitexactnessTest(8000, 1, 0, - EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone, - true, kOutputReference); -} - -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay0) { - const float kOutputReference[] = {0.003601f, 0.002991f, 0.001923f}; - RunBitexactnessTest(16000, 1, 0, - EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone, - true, kOutputReference); -} - -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono32kHz_LoudSpeakerPhone_CngOn_StreamDelay0) { - const float kOutputReference[] = {0.002258f, 0.002899f, 0.003906f}; - - RunBitexactnessTest(32000, 1, 0, - EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone, - true, kOutputReference); -} - -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono48kHz_LoudSpeakerPhone_CngOn_StreamDelay0) { - const float kOutputReference[] = {-0.000046f, 0.000041f, 0.000249f}; - - RunBitexactnessTest(48000, 1, 0, - EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone, - true, kOutputReference); -} - -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono16kHz_LoudSpeakerPhone_CngOff_StreamDelay0) { - const float kOutputReference[] = {0.000000f, 0.000000f, 0.000000f}; - - RunBitexactnessTest(16000, 1, 0, - EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone, - false, kOutputReference); -} - -// TODO(peah): Renable once the integer overflow issue in aecm_core.c:932:69 -// has been solved. -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay5) { - const float kOutputReference[] = {0.003693f, 0.002930f, 0.001801f}; - - RunBitexactnessTest(16000, 1, 5, - EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone, - true, kOutputReference); -} - -TEST(EchoControlMobileBitExactnessTest, - Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay10) { - const float kOutputReference[] = {-0.002380f, -0.002533f, -0.002563f}; - - RunBitexactnessTest(16000, 1, 10, - EchoControlMobileImpl::RoutingMode::kLoudSpeakerphone, - true, kOutputReference); -} - -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono16kHz_QuietEarpieceOrHeadset_CngOn_StreamDelay0) { - const float kOutputReference[] = {0.000397f, 0.000000f, -0.000305f}; - - RunBitexactnessTest( - 16000, 1, 0, EchoControlMobileImpl::RoutingMode::kQuietEarpieceOrHeadset, - true, kOutputReference); -} - -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono16kHz_Earpiece_CngOn_StreamDelay0) { - const float kOutputReference[] = {0.002167f, 0.001617f, 0.001038f}; - - RunBitexactnessTest(16000, 1, 0, - EchoControlMobileImpl::RoutingMode::kEarpiece, true, - kOutputReference); -} - -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono16kHz_LoudEarpiece_CngOn_StreamDelay0) { - const float kOutputReference[] = {0.003540f, 0.002899f, 0.001862f}; - - RunBitexactnessTest(16000, 1, 0, - EchoControlMobileImpl::RoutingMode::kLoudEarpiece, true, - kOutputReference); -} - -TEST(EchoControlMobileBitExactnessTest, - DISABLED_Mono16kHz_SpeakerPhone_CngOn_StreamDelay0) { - const float kOutputReference[] = {0.003632f, 0.003052f, 0.001984f}; - - RunBitexactnessTest(16000, 1, 0, - EchoControlMobileImpl::RoutingMode::kSpeakerphone, true, - kOutputReference); -} - -} // namespace webrtc diff --git a/modules/audio_processing/echo_control_mobile_impl.cc b/modules/audio_processing/echo_control_mobile_impl.cc index bd125c6e0d..272da7a71e 100644 --- a/modules/audio_processing/echo_control_mobile_impl.cc +++ b/modules/audio_processing/echo_control_mobile_impl.cc @@ -20,17 +20,17 @@ namespace webrtc { namespace { -int16_t MapSetting(EchoControlMobileImpl::RoutingMode mode) { +int16_t MapSetting(EchoControlMobile::RoutingMode mode) { switch (mode) { - case EchoControlMobileImpl::kQuietEarpieceOrHeadset: + case EchoControlMobile::kQuietEarpieceOrHeadset: return 0; - case EchoControlMobileImpl::kEarpiece: + case EchoControlMobile::kEarpiece: return 1; - case EchoControlMobileImpl::kLoudEarpiece: + case EchoControlMobile::kLoudEarpiece: return 2; - case EchoControlMobileImpl::kSpeakerphone: + case EchoControlMobile::kSpeakerphone: return 3; - case EchoControlMobileImpl::kLoudSpeakerphone: + case EchoControlMobile::kLoudSpeakerphone: return 4; } RTC_NOTREACHED(); @@ -55,7 +55,7 @@ AudioProcessing::Error MapError(int err) { } } // namespace -size_t EchoControlMobileImpl::echo_path_size_bytes() { +size_t EchoControlMobile::echo_path_size_bytes() { return WebRtcAecm_echo_path_size_bytes(); } @@ -268,7 +268,7 @@ int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) { return Configure(); } -EchoControlMobileImpl::RoutingMode EchoControlMobileImpl::routing_mode() const { +EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode() const { rtc::CritScope cs(crit_capture_); return routing_mode_; } diff --git a/modules/audio_processing/echo_control_mobile_impl.h b/modules/audio_processing/echo_control_mobile_impl.h index 3341ec56b6..a03ab4d486 100644 --- a/modules/audio_processing/echo_control_mobile_impl.h +++ b/modules/audio_processing/echo_control_mobile_impl.h @@ -24,60 +24,21 @@ namespace webrtc { class AudioBuffer; -class EchoControlMobileImpl { +class EchoControlMobileImpl : public EchoControlMobile { public: EchoControlMobileImpl(rtc::CriticalSection* crit_render, rtc::CriticalSection* crit_capture); - ~EchoControlMobileImpl(); - - int Enable(bool enable); - bool is_enabled() const; - - // Recommended settings for particular audio routes. In general, the louder - // the echo is expected to be, the higher this value should be set. The - // preferred setting may vary from device to device. - enum RoutingMode { - kQuietEarpieceOrHeadset, - kEarpiece, - kLoudEarpiece, - kSpeakerphone, - kLoudSpeakerphone - }; - - // Sets echo control appropriate for the audio routing |mode| on the device. - // It can and should be updated during a call if the audio routing changes. - int set_routing_mode(RoutingMode mode); - RoutingMode routing_mode() const; - - // Comfort noise replaces suppressed background noise to maintain a - // consistent signal level. - int enable_comfort_noise(bool enable); - bool is_comfort_noise_enabled() const; - - // A typical use case is to initialize the component with an echo path from a - // previous call. The echo path is retrieved using |GetEchoPath()|, typically - // at the end of a call. The data can then be stored for later use as an - // initializer before the next call, using |SetEchoPath()|. - // - // Controlling the echo path this way requires the data |size_bytes| to match - // the internal echo path size. This size can be acquired using - // |echo_path_size_bytes()|. |SetEchoPath()| causes an entire reset, worth - // noting if it is to be called during an ongoing call. - // - // It is possible that version incompatibilities may result in a stored echo - // path of the incorrect size. In this case, the stored path should be - // discarded. - int SetEchoPath(const void* echo_path, size_t size_bytes); - int GetEchoPath(void* echo_path, size_t size_bytes) const; - - // The returned path size is guaranteed not to change for the lifetime of - // the application. - static size_t echo_path_size_bytes(); + ~EchoControlMobileImpl() override; void ProcessRenderAudio(rtc::ArrayView packed_render_audio); int ProcessCaptureAudio(AudioBuffer* audio, int stream_delay_ms); + // EchoControlMobile implementation. + bool is_enabled() const override; + RoutingMode routing_mode() const override; + bool is_comfort_noise_enabled() const override; + void Initialize(int sample_rate_hz, size_t num_reverse_channels, size_t num_output_channels); @@ -94,6 +55,13 @@ class EchoControlMobileImpl { class Canceller; struct StreamProperties; + // EchoControlMobile implementation. + int Enable(bool enable) override; + int set_routing_mode(RoutingMode mode) override; + int enable_comfort_noise(bool enable) override; + int SetEchoPath(const void* echo_path, size_t size_bytes) override; + int GetEchoPath(void* echo_path, size_t size_bytes) const override; + int Configure(); rtc::CriticalSection* const crit_render_ RTC_ACQUIRED_BEFORE(crit_capture_); diff --git a/modules/audio_processing/echo_control_mobile_proxy.cc b/modules/audio_processing/echo_control_mobile_proxy.cc index e3909db333..fd298348f4 100644 --- a/modules/audio_processing/echo_control_mobile_proxy.cc +++ b/modules/audio_processing/echo_control_mobile_proxy.cc @@ -10,19 +10,20 @@ #include "modules/audio_processing/echo_control_mobile_proxy.h" -#include "rtc_base/logging.h" - namespace webrtc { EchoControlMobileProxy::EchoControlMobileProxy( AudioProcessing* audio_processing, - EchoControlMobileImpl* echo_control_mobile) + EchoControlMobile* echo_control_mobile) : audio_processing_(audio_processing), echo_control_mobile_(echo_control_mobile) {} EchoControlMobileProxy::~EchoControlMobileProxy() = default; int EchoControlMobileProxy::Enable(bool enable) { + // Change the config in APM to mirror the applied settings. + // TODO(bugs.webrtc.org/9535): Remove the call to EchoControlMobile::Enable + // when APM starts taking the config into account. AudioProcessing::Config apm_config = audio_processing_->GetConfig(); bool aecm_enabled = apm_config.echo_canceller.enabled && apm_config.echo_canceller.mobile_mode; @@ -31,6 +32,7 @@ int EchoControlMobileProxy::Enable(bool enable) { apm_config.echo_canceller.mobile_mode = true; audio_processing_->ApplyConfig(apm_config); } + echo_control_mobile_->Enable(enable); return AudioProcessing::kNoError; } @@ -39,31 +41,29 @@ bool EchoControlMobileProxy::is_enabled() const { } int EchoControlMobileProxy::set_routing_mode(RoutingMode mode) { - RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AECM routing mode"; - return AudioProcessing::kUnsupportedFunctionError; + return echo_control_mobile_->set_routing_mode(mode); } EchoControlMobile::RoutingMode EchoControlMobileProxy::routing_mode() const { - return EchoControlMobile::kSpeakerphone; + return echo_control_mobile_->routing_mode(); } int EchoControlMobileProxy::enable_comfort_noise(bool enable) { - RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AECM comfort noise"; - return AudioProcessing::kUnsupportedFunctionError; + return echo_control_mobile_->enable_comfort_noise(enable); } bool EchoControlMobileProxy::is_comfort_noise_enabled() const { - return false; + return echo_control_mobile_->is_comfort_noise_enabled(); } int EchoControlMobileProxy::SetEchoPath(const void* echo_path, size_t size_bytes) { - return AudioProcessing::kUnsupportedFunctionError; + return echo_control_mobile_->SetEchoPath(echo_path, size_bytes); } int EchoControlMobileProxy::GetEchoPath(void* echo_path, size_t size_bytes) const { - return AudioProcessing::kUnsupportedFunctionError; + return echo_control_mobile_->GetEchoPath(echo_path, size_bytes); } } // namespace webrtc diff --git a/modules/audio_processing/echo_control_mobile_proxy.h b/modules/audio_processing/echo_control_mobile_proxy.h index 13be65988d..eb5908a4e0 100644 --- a/modules/audio_processing/echo_control_mobile_proxy.h +++ b/modules/audio_processing/echo_control_mobile_proxy.h @@ -11,7 +11,6 @@ #ifndef MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_PROXY_H_ #define MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_PROXY_H_ -#include "modules/audio_processing/echo_control_mobile_impl.h" #include "modules/audio_processing/include/audio_processing.h" #include "rtc_base/constructormagic.h" #include "rtc_base/scoped_ref_ptr.h" @@ -22,7 +21,7 @@ namespace webrtc { class EchoControlMobileProxy : public EchoControlMobile { public: EchoControlMobileProxy(AudioProcessing* audio_processing, - EchoControlMobileImpl* echo_control_mobile); + EchoControlMobile* echo_control_mobile); ~EchoControlMobileProxy() override; bool is_enabled() const override; @@ -36,7 +35,7 @@ class EchoControlMobileProxy : public EchoControlMobile { private: AudioProcessing* audio_processing_; - EchoControlMobileImpl* echo_control_mobile_; + EchoControlMobile* echo_control_mobile_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EchoControlMobileProxy); }; diff --git a/modules/audio_processing/echo_control_mobile_unittest.cc b/modules/audio_processing/echo_control_mobile_unittest.cc index d7e470ca12..fb58a5b870 100644 --- a/modules/audio_processing/echo_control_mobile_unittest.cc +++ b/modules/audio_processing/echo_control_mobile_unittest.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * 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 @@ -7,70 +7,218 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ - -#include #include +#include "api/array_view.h" +#include "modules/audio_processing/audio_buffer.h" #include "modules/audio_processing/echo_control_mobile_impl.h" -#include "modules/audio_processing/include/audio_processing.h" -#include "rtc_base/criticalsection.h" +#include "modules/audio_processing/test/audio_buffer_tools.h" +#include "modules/audio_processing/test/bitexactness_tools.h" #include "test/gtest.h" namespace webrtc { -TEST(EchoControlMobileTest, InterfaceConfiguration) { +namespace { + +// TODO(peah): Increase the number of frames to proces when the issue of +// non repeatable test results have been found. +const int kNumFramesToProcess = 200; + +void SetupComponent(int sample_rate_hz, + EchoControlMobile::RoutingMode routing_mode, + bool comfort_noise_enabled, + EchoControlMobileImpl* echo_control_mobile) { + echo_control_mobile->Initialize( + sample_rate_hz > 16000 ? 16000 : sample_rate_hz, 1, 1); + EchoControlMobile* ec = static_cast(echo_control_mobile); + ec->Enable(true); + ec->set_routing_mode(routing_mode); + ec->enable_comfort_noise(comfort_noise_enabled); +} + +void ProcessOneFrame(int sample_rate_hz, + int stream_delay_ms, + AudioBuffer* render_audio_buffer, + AudioBuffer* capture_audio_buffer, + EchoControlMobileImpl* echo_control_mobile) { + if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) { + render_audio_buffer->SplitIntoFrequencyBands(); + capture_audio_buffer->SplitIntoFrequencyBands(); + } + + std::vector render_audio; + EchoControlMobileImpl::PackRenderAudioBuffer( + render_audio_buffer, 1, render_audio_buffer->num_channels(), + &render_audio); + echo_control_mobile->ProcessRenderAudio(render_audio); + + echo_control_mobile->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, + EchoControlMobile::RoutingMode routing_mode, + bool comfort_noise_enabled, + const rtc::ArrayView& output_reference) { rtc::CriticalSection crit_render; rtc::CriticalSection crit_capture; - EchoControlMobileImpl aecm(&crit_render, &crit_capture); - aecm.Initialize(AudioProcessing::kSampleRate16kHz, 2, 2); + EchoControlMobileImpl echo_control_mobile(&crit_render, &crit_capture); + SetupComponent(sample_rate_hz, routing_mode, comfort_noise_enabled, + &echo_control_mobile); - // Turn AECM on - EXPECT_EQ(0, aecm.Enable(true)); - EXPECT_TRUE(aecm.is_enabled()); + 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.num_frames(), render_config.num_channels(), + render_config.num_frames(), 1, render_config.num_frames()); + test::InputAudioFile render_file( + test::GetApmRenderTestVectorFileName(sample_rate_hz)); + std::vector render_input(samples_per_channel * num_channels); - // Toggle routing modes - std::array routing_modes = { - EchoControlMobileImpl::kQuietEarpieceOrHeadset, - EchoControlMobileImpl::kEarpiece, - EchoControlMobileImpl::kLoudEarpiece, - EchoControlMobileImpl::kSpeakerphone, - EchoControlMobileImpl::kLoudSpeakerphone, - }; - for (auto mode : routing_modes) { - EXPECT_EQ(0, aecm.set_routing_mode(mode)); - EXPECT_EQ(mode, aecm.routing_mode()); + const StreamConfig capture_config(sample_rate_hz, num_channels, false); + AudioBuffer capture_buffer( + capture_config.num_frames(), capture_config.num_channels(), + capture_config.num_frames(), 1, capture_config.num_frames()); + test::InputAudioFile capture_file( + test::GetApmCaptureTestVectorFileName(sample_rate_hz)); + std::vector 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, &render_buffer, + &capture_buffer, &echo_control_mobile); } - // Turn comfort noise off/on - EXPECT_EQ(0, aecm.enable_comfort_noise(false)); - EXPECT_FALSE(aecm.is_comfort_noise_enabled()); - EXPECT_EQ(0, aecm.enable_comfort_noise(true)); - EXPECT_TRUE(aecm.is_comfort_noise_enabled()); + // Extract and verify the test results. + std::vector capture_output; + test::ExtractVectorFromAudioBuffer(capture_config, &capture_buffer, + &capture_output); - // Set and get echo path - const size_t echo_path_size = aecm.echo_path_size_bytes(); - std::vector echo_path_in(echo_path_size); - std::vector echo_path_out(echo_path_size); - EXPECT_EQ(AudioProcessing::kNullPointerError, - aecm.SetEchoPath(nullptr, echo_path_size)); - EXPECT_EQ(AudioProcessing::kNullPointerError, - aecm.GetEchoPath(nullptr, echo_path_size)); - EXPECT_EQ(AudioProcessing::kBadParameterError, - aecm.GetEchoPath(echo_path_out.data(), 1)); - EXPECT_EQ(0, aecm.GetEchoPath(echo_path_out.data(), echo_path_size)); - for (size_t i = 0; i < echo_path_size; i++) { - echo_path_in[i] = echo_path_out[i] + 1; - } - EXPECT_EQ(AudioProcessing::kBadParameterError, - aecm.SetEchoPath(echo_path_in.data(), 1)); - EXPECT_EQ(0, aecm.SetEchoPath(echo_path_in.data(), echo_path_size)); - EXPECT_EQ(0, aecm.GetEchoPath(echo_path_out.data(), echo_path_size)); - for (size_t i = 0; i < echo_path_size; i++) { - EXPECT_EQ(echo_path_in[i], echo_path_out[i]); - } + // 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)); +} - // Turn AECM off - EXPECT_EQ(0, aecm.Enable(false)); - EXPECT_FALSE(aecm.is_enabled()); +} // namespace + +// TODO(peah): Renable once the integer overflow issue in aecm_core.c:932:69 +// has been solved. +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono8kHz_LoudSpeakerPhone_CngOn_StreamDelay0) { + const float kOutputReference[] = {0.005280f, 0.002380f, -0.000427f}; + + RunBitexactnessTest(8000, 1, 0, + EchoControlMobile::RoutingMode::kLoudSpeakerphone, true, + kOutputReference); +} + +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay0) { + const float kOutputReference[] = {0.003601f, 0.002991f, 0.001923f}; + RunBitexactnessTest(16000, 1, 0, + EchoControlMobile::RoutingMode::kLoudSpeakerphone, true, + kOutputReference); +} + +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono32kHz_LoudSpeakerPhone_CngOn_StreamDelay0) { + const float kOutputReference[] = {0.002258f, 0.002899f, 0.003906f}; + + RunBitexactnessTest(32000, 1, 0, + EchoControlMobile::RoutingMode::kLoudSpeakerphone, true, + kOutputReference); +} + +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono48kHz_LoudSpeakerPhone_CngOn_StreamDelay0) { + const float kOutputReference[] = {-0.000046f, 0.000041f, 0.000249f}; + + RunBitexactnessTest(48000, 1, 0, + EchoControlMobile::RoutingMode::kLoudSpeakerphone, true, + kOutputReference); +} + +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono16kHz_LoudSpeakerPhone_CngOff_StreamDelay0) { + const float kOutputReference[] = {0.000000f, 0.000000f, 0.000000f}; + + RunBitexactnessTest(16000, 1, 0, + EchoControlMobile::RoutingMode::kLoudSpeakerphone, false, + kOutputReference); +} + +// TODO(peah): Renable once the integer overflow issue in aecm_core.c:932:69 +// has been solved. +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay5) { + const float kOutputReference[] = {0.003693f, 0.002930f, 0.001801f}; + + RunBitexactnessTest(16000, 1, 5, + EchoControlMobile::RoutingMode::kLoudSpeakerphone, true, + kOutputReference); +} + +TEST(EchoControlMobileBitExactnessTest, + Mono16kHz_LoudSpeakerPhone_CngOn_StreamDelay10) { + const float kOutputReference[] = {-0.002380f, -0.002533f, -0.002563f}; + + RunBitexactnessTest(16000, 1, 10, + EchoControlMobile::RoutingMode::kLoudSpeakerphone, true, + kOutputReference); +} + +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono16kHz_QuietEarpieceOrHeadset_CngOn_StreamDelay0) { + const float kOutputReference[] = {0.000397f, 0.000000f, -0.000305f}; + + RunBitexactnessTest(16000, 1, 0, + EchoControlMobile::RoutingMode::kQuietEarpieceOrHeadset, + true, kOutputReference); +} + +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono16kHz_Earpiece_CngOn_StreamDelay0) { + const float kOutputReference[] = {0.002167f, 0.001617f, 0.001038f}; + + RunBitexactnessTest(16000, 1, 0, EchoControlMobile::RoutingMode::kEarpiece, + true, kOutputReference); +} + +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono16kHz_LoudEarpiece_CngOn_StreamDelay0) { + const float kOutputReference[] = {0.003540f, 0.002899f, 0.001862f}; + + RunBitexactnessTest(16000, 1, 0, + EchoControlMobile::RoutingMode::kLoudEarpiece, true, + kOutputReference); +} + +TEST(EchoControlMobileBitExactnessTest, + DISABLED_Mono16kHz_SpeakerPhone_CngOn_StreamDelay0) { + const float kOutputReference[] = {0.003632f, 0.003052f, 0.001984f}; + + RunBitexactnessTest(16000, 1, 0, + EchoControlMobile::RoutingMode::kSpeakerphone, true, + kOutputReference); } } // namespace webrtc diff --git a/modules/audio_processing/test/aec_dump_based_simulator.cc b/modules/audio_processing/test/aec_dump_based_simulator.cc index 94ebc6a43b..2d4f12f11d 100644 --- a/modules/audio_processing/test/aec_dump_based_simulator.cc +++ b/modules/audio_processing/test/aec_dump_based_simulator.cc @@ -10,10 +10,10 @@ #include -#include "modules/audio_processing/echo_control_mobile_impl.h" #include "modules/audio_processing/test/aec_dump_based_simulator.h" -#include "modules/audio_processing/test/protobuf_utils.h" #include "modules/audio_processing/test/runtime_setting_util.h" + +#include "modules/audio_processing/test/protobuf_utils.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" @@ -347,16 +347,30 @@ void AecDumpBasedSimulator::HandleMessage( } } - if (msg.has_aecm_comfort_noise_enabled() && - msg.aecm_comfort_noise_enabled()) { - RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AECM comfort noise"; + if (msg.has_aecm_comfort_noise_enabled() || + settings_.use_aecm_comfort_noise) { + bool enable = settings_.use_aecm_comfort_noise + ? *settings_.use_aecm_comfort_noise + : msg.aecm_comfort_noise_enabled(); + RTC_CHECK_EQ(AudioProcessing::kNoError, + ap_->echo_control_mobile()->enable_comfort_noise(enable)); + if (settings_.use_verbose_logging) { + std::cout << " aecm_comfort_noise_enabled: " + << (enable ? "true" : "false") << std::endl; + } } - if (msg.has_aecm_routing_mode() && - static_cast( - msg.aecm_routing_mode()) != EchoControlMobileImpl::kSpeakerphone) { - RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AECM routing mode: " - << msg.aecm_routing_mode(); + if (msg.has_aecm_routing_mode() || settings_.aecm_routing_mode) { + int routing_mode = settings_.aecm_routing_mode + ? *settings_.aecm_routing_mode + : msg.aecm_routing_mode(); + RTC_CHECK_EQ(AudioProcessing::kNoError, + ap_->echo_control_mobile()->set_routing_mode( + static_cast( + routing_mode))); + if (settings_.use_verbose_logging) { + std::cout << " aecm_routing_mode: " << routing_mode << std::endl; + } } if (msg.has_agc_enabled() || settings_.use_agc) { diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc index 608e35c10f..4ac92ee796 100644 --- a/modules/audio_processing/test/audio_processing_simulator.cc +++ b/modules/audio_processing/test/audio_processing_simulator.cc @@ -21,7 +21,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_control_mobile_impl.h" #include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/test/fake_recording_device.h" #include "rtc_base/checks.h" @@ -1035,6 +1034,19 @@ void AudioProcessingSimulator::CreateAudioProcessor() { static_cast(*settings_.agc_mode))); } + if (settings_.aecm_routing_mode) { + RTC_CHECK_EQ(AudioProcessing::kNoError, + ap_->echo_control_mobile()->set_routing_mode( + static_cast( + *settings_.aecm_routing_mode))); + } + + if (settings_.use_aecm_comfort_noise) { + RTC_CHECK_EQ(AudioProcessing::kNoError, + ap_->echo_control_mobile()->enable_comfort_noise( + *settings_.use_aecm_comfort_noise)); + } + if (settings_.vad_likelihood) { RTC_CHECK_EQ(AudioProcessing::kNoError, ap_->voice_detection()->set_likelihood( diff --git a/modules/audio_processing/test/audio_processing_simulator.h b/modules/audio_processing/test/audio_processing_simulator.h index 81349e69b2..68b35b2539 100644 --- a/modules/audio_processing/test/audio_processing_simulator.h +++ b/modules/audio_processing/test/audio_processing_simulator.h @@ -69,6 +69,8 @@ struct SimulationSettings { absl::optional use_experimental_agc_agc2_level_estimator; absl::optional experimental_agc_disable_digital_adaptive; absl::optional experimental_agc_analyze_before_aec; + absl::optional aecm_routing_mode; + absl::optional use_aecm_comfort_noise; absl::optional agc_mode; absl::optional agc_target_level; absl::optional use_agc_limiter; diff --git a/modules/audio_processing/test/audioproc_float_impl.cc b/modules/audio_processing/test/audioproc_float_impl.cc index 8bb078e9e8..bd77b96ea9 100644 --- a/modules/audio_processing/test/audioproc_float_impl.cc +++ b/modules/audio_processing/test/audioproc_float_impl.cc @@ -129,6 +129,12 @@ DEFINE_int( refined_adaptive_filter, kParameterNotSpecifiedValue, "Activate (1) or deactivate(0) the refined adaptive filter functionality"); +DEFINE_int(aecm_routing_mode, + kParameterNotSpecifiedValue, + "Specify the AECM routing mode (0-4)"); +DEFINE_int(aecm_comfort_noise, + kParameterNotSpecifiedValue, + "Activate (1) or deactivate(0) the AECM comfort noise"); DEFINE_int(agc_mode, kParameterNotSpecifiedValue, "Specify the AGC mode (0-2)"); DEFINE_int(agc_target_level, kParameterNotSpecifiedValue, @@ -264,6 +270,9 @@ SimulationSettings CreateSettings() { &settings.experimental_agc_analyze_before_aec); SetSettingIfFlagSet(FLAG_experimental_agc_agc2_level_estimator, &settings.use_experimental_agc_agc2_level_estimator); + SetSettingIfSpecified(FLAG_aecm_routing_mode, &settings.aecm_routing_mode); + SetSettingIfFlagSet(FLAG_aecm_comfort_noise, + &settings.use_aecm_comfort_noise); SetSettingIfSpecified(FLAG_agc_mode, &settings.agc_mode); SetSettingIfSpecified(FLAG_agc_target_level, &settings.agc_target_level); SetSettingIfFlagSet(FLAG_agc_limiter, &settings.use_agc_limiter); @@ -358,6 +367,11 @@ void PerformBasicParameterSanityChecks(const SimulationSettings& settings) { "specified between 1 and 2. 0 is " "deprecated.\n"); + ReportConditionalErrorAndExit( + settings.aecm_routing_mode && ((*settings.aecm_routing_mode) < 0 || + (*settings.aecm_routing_mode) > 4), + "Error: --aecm_routing_mode must be specified between 0 and 4.\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 e3ca5915d8..94d03d3dbf 100644 --- a/modules/audio_processing/test/debug_dump_replayer.cc +++ b/modules/audio_processing/test/debug_dump_replayer.cc @@ -218,6 +218,17 @@ void DebugDumpReplayer::ConfigureApm(const audioproc::Config& msg) { msg.aec_suppression_level()) == EchoCancellation::SuppressionLevel::kModerateSuppression; + RTC_CHECK(msg.has_aecm_comfort_noise_enabled()); + RTC_CHECK_EQ(AudioProcessing::kNoError, + apm_->echo_control_mobile()->enable_comfort_noise( + msg.aecm_comfort_noise_enabled())); + + RTC_CHECK(msg.has_aecm_routing_mode()); + RTC_CHECK_EQ(AudioProcessing::kNoError, + apm_->echo_control_mobile()->set_routing_mode( + static_cast( + msg.aecm_routing_mode()))); + // AGC configs. RTC_CHECK(msg.has_agc_enabled()); RTC_CHECK_EQ(AudioProcessing::kNoError,