diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn index 78e00917f7..84b89066be 100644 --- a/modules/audio_processing/BUILD.gn +++ b/modules/audio_processing/BUILD.gn @@ -345,6 +345,7 @@ 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", @@ -431,7 +432,7 @@ if (rtc_include_tests) { "audio_processing_impl_unittest.cc", "audio_processing_unittest.cc", "echo_cancellation_bit_exact_unittest.cc", - "echo_control_mobile_unittest.cc", + "echo_control_mobile_bit_exact_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 d5bb046964..0772936f63 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc @@ -674,9 +674,8 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) { public_submodules_->echo_cancellation->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_control_mobile->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 d22669a745..adee5a9c89 100644 --- a/modules/audio_processing/audio_processing_unittest.cc +++ b/modules/audio_processing/audio_processing_unittest.cc @@ -943,74 +943,6 @@ 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 10a98d53f6..40bd5d516e 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; - optional int32 aecm_routing_mode = 8; + optional bool aecm_comfort_noise_enabled = 7 [deprecated = true]; + optional int32 aecm_routing_mode = 8 [deprecated = true]; // 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 new file mode 100644 index 0000000000..8b8369260a --- /dev/null +++ b/modules/audio_processing/echo_control_mobile_bit_exact_unittest.cc @@ -0,0 +1,224 @@ +/* + * 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 272da7a71e..bd125c6e0d 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(EchoControlMobile::RoutingMode mode) { +int16_t MapSetting(EchoControlMobileImpl::RoutingMode mode) { switch (mode) { - case EchoControlMobile::kQuietEarpieceOrHeadset: + case EchoControlMobileImpl::kQuietEarpieceOrHeadset: return 0; - case EchoControlMobile::kEarpiece: + case EchoControlMobileImpl::kEarpiece: return 1; - case EchoControlMobile::kLoudEarpiece: + case EchoControlMobileImpl::kLoudEarpiece: return 2; - case EchoControlMobile::kSpeakerphone: + case EchoControlMobileImpl::kSpeakerphone: return 3; - case EchoControlMobile::kLoudSpeakerphone: + case EchoControlMobileImpl::kLoudSpeakerphone: return 4; } RTC_NOTREACHED(); @@ -55,7 +55,7 @@ AudioProcessing::Error MapError(int err) { } } // namespace -size_t EchoControlMobile::echo_path_size_bytes() { +size_t EchoControlMobileImpl::echo_path_size_bytes() { return WebRtcAecm_echo_path_size_bytes(); } @@ -268,7 +268,7 @@ int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) { return Configure(); } -EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode() const { +EchoControlMobileImpl::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 a03ab4d486..3341ec56b6 100644 --- a/modules/audio_processing/echo_control_mobile_impl.h +++ b/modules/audio_processing/echo_control_mobile_impl.h @@ -24,21 +24,60 @@ namespace webrtc { class AudioBuffer; -class EchoControlMobileImpl : public EchoControlMobile { +class EchoControlMobileImpl { public: EchoControlMobileImpl(rtc::CriticalSection* crit_render, rtc::CriticalSection* crit_capture); - ~EchoControlMobileImpl() override; + ~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(); 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); @@ -55,13 +94,6 @@ class EchoControlMobileImpl : public EchoControlMobile { 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 fd298348f4..e3909db333 100644 --- a/modules/audio_processing/echo_control_mobile_proxy.cc +++ b/modules/audio_processing/echo_control_mobile_proxy.cc @@ -10,20 +10,19 @@ #include "modules/audio_processing/echo_control_mobile_proxy.h" +#include "rtc_base/logging.h" + namespace webrtc { EchoControlMobileProxy::EchoControlMobileProxy( AudioProcessing* audio_processing, - EchoControlMobile* echo_control_mobile) + EchoControlMobileImpl* 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; @@ -32,7 +31,6 @@ 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; } @@ -41,29 +39,31 @@ bool EchoControlMobileProxy::is_enabled() const { } int EchoControlMobileProxy::set_routing_mode(RoutingMode mode) { - return echo_control_mobile_->set_routing_mode(mode); + RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AECM routing mode"; + return AudioProcessing::kUnsupportedFunctionError; } EchoControlMobile::RoutingMode EchoControlMobileProxy::routing_mode() const { - return echo_control_mobile_->routing_mode(); + return EchoControlMobile::kSpeakerphone; } int EchoControlMobileProxy::enable_comfort_noise(bool enable) { - return echo_control_mobile_->enable_comfort_noise(enable); + RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AECM comfort noise"; + return AudioProcessing::kUnsupportedFunctionError; } bool EchoControlMobileProxy::is_comfort_noise_enabled() const { - return echo_control_mobile_->is_comfort_noise_enabled(); + return false; } int EchoControlMobileProxy::SetEchoPath(const void* echo_path, size_t size_bytes) { - return echo_control_mobile_->SetEchoPath(echo_path, size_bytes); + return AudioProcessing::kUnsupportedFunctionError; } int EchoControlMobileProxy::GetEchoPath(void* echo_path, size_t size_bytes) const { - return echo_control_mobile_->GetEchoPath(echo_path, size_bytes); + return AudioProcessing::kUnsupportedFunctionError; } } // namespace webrtc diff --git a/modules/audio_processing/echo_control_mobile_proxy.h b/modules/audio_processing/echo_control_mobile_proxy.h index eb5908a4e0..13be65988d 100644 --- a/modules/audio_processing/echo_control_mobile_proxy.h +++ b/modules/audio_processing/echo_control_mobile_proxy.h @@ -11,6 +11,7 @@ #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" @@ -21,7 +22,7 @@ namespace webrtc { class EchoControlMobileProxy : public EchoControlMobile { public: EchoControlMobileProxy(AudioProcessing* audio_processing, - EchoControlMobile* echo_control_mobile); + EchoControlMobileImpl* echo_control_mobile); ~EchoControlMobileProxy() override; bool is_enabled() const override; @@ -35,7 +36,7 @@ class EchoControlMobileProxy : public EchoControlMobile { private: AudioProcessing* audio_processing_; - EchoControlMobile* echo_control_mobile_; + EchoControlMobileImpl* 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 fb58a5b870..d7e470ca12 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) 2016 The WebRTC project authors. All Rights Reserved. + * 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 @@ -7,218 +7,70 @@ * 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/test/audio_buffer_tools.h" -#include "modules/audio_processing/test/bitexactness_tools.h" +#include "modules/audio_processing/include/audio_processing.h" +#include "rtc_base/criticalsection.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, - 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) { +TEST(EchoControlMobileTest, InterfaceConfiguration) { 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); + EchoControlMobileImpl aecm(&crit_render, &crit_capture); + aecm.Initialize(AudioProcessing::kSampleRate16kHz, 2, 2); - 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); + // Turn AECM on + EXPECT_EQ(0, aecm.Enable(true)); + EXPECT_TRUE(aecm.is_enabled()); - 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); + // 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()); } - // Extract and verify the test results. - std::vector capture_output; - test::ExtractVectorFromAudioBuffer(capture_config, &capture_buffer, - &capture_output); + // 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()); - // 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)); -} + // 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]); + } -} // 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); + // Turn AECM off + EXPECT_EQ(0, aecm.Enable(false)); + EXPECT_FALSE(aecm.is_enabled()); } } // 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 2d4f12f11d..94ebc6a43b 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/runtime_setting_util.h" - #include "modules/audio_processing/test/protobuf_utils.h" +#include "modules/audio_processing/test/runtime_setting_util.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" @@ -347,30 +347,16 @@ void AecDumpBasedSimulator::HandleMessage( } } - 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_comfort_noise_enabled() && + msg.aecm_comfort_noise_enabled()) { + RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AECM comfort noise"; } - 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_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_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 4ac92ee796..608e35c10f 100644 --- a/modules/audio_processing/test/audio_processing_simulator.cc +++ b/modules/audio_processing/test/audio_processing_simulator.cc @@ -21,6 +21,7 @@ #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" @@ -1034,19 +1035,6 @@ 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 68b35b2539..81349e69b2 100644 --- a/modules/audio_processing/test/audio_processing_simulator.h +++ b/modules/audio_processing/test/audio_processing_simulator.h @@ -69,8 +69,6 @@ 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 bd77b96ea9..8bb078e9e8 100644 --- a/modules/audio_processing/test/audioproc_float_impl.cc +++ b/modules/audio_processing/test/audioproc_float_impl.cc @@ -129,12 +129,6 @@ 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, @@ -270,9 +264,6 @@ 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); @@ -367,11 +358,6 @@ 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 94d03d3dbf..e3ca5915d8 100644 --- a/modules/audio_processing/test/debug_dump_replayer.cc +++ b/modules/audio_processing/test/debug_dump_replayer.cc @@ -218,17 +218,6 @@ 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,