From c19f312f54b9674621c0482d7c067043643308c1 Mon Sep 17 00:00:00 2001 From: peah Date: Fri, 7 Oct 2016 14:54:10 -0700 Subject: [PATCH] This CL adds functionality in the level controller to receive a signal level to use initially, instead of the default initial signal level. The initial form of the CL (https://codereview.webrtc.org/2254973003/) was reverted due to down-stream dependencies. These have been resolved, but the CL needed to be revised according to the new scheme for passing parameters to the audio processing module. Therefore, please review this CL as if it is new. TBR=aleloi@webrtc.org BUG=webrtc:6386 Review-Url: https://codereview.webrtc.org/2337083002 Cr-Commit-Position: refs/heads/master@{#14579} --- webrtc/modules/audio_processing/BUILD.gn | 4 +- .../audio_processing/audio_processing.gypi | 4 +- .../audio_processing/audio_processing_impl.cc | 28 ++++-- .../audio_processing/audio_processing_impl.h | 9 ++ .../audio_processing_unittest.cc | 96 +++++++++++++++++++ .../{ => include}/audio_processing.cc | 0 .../include/audio_processing.h | 5 + .../level_controller/gain_selector.cc | 6 +- .../level_controller/gain_selector.h | 1 + .../level_controller/level_controller.cc | 29 ++++-- .../level_controller/level_controller.h | 6 ++ ...nstants.h => level_controller_constants.h} | 9 +- .../level_controller_unittest.cc | 45 +++++---- .../level_controller/peak_level_estimator.cc | 23 +++-- .../level_controller/peak_level_estimator.h | 8 +- .../saturating_gain_estimator.cc | 2 +- 16 files changed, 217 insertions(+), 58 deletions(-) rename webrtc/modules/audio_processing/{ => include}/audio_processing.cc (100%) rename webrtc/modules/audio_processing/level_controller/{lc_constants.h => level_controller_constants.h} (60%) diff --git a/webrtc/modules/audio_processing/BUILD.gn b/webrtc/modules/audio_processing/BUILD.gn index b4d875934b..25c47ec964 100644 --- a/webrtc/modules/audio_processing/BUILD.gn +++ b/webrtc/modules/audio_processing/BUILD.gn @@ -46,7 +46,6 @@ rtc_static_library("audio_processing") { "agc/utility.h", "audio_buffer.cc", "audio_buffer.h", - "audio_processing.cc", "audio_processing_impl.cc", "audio_processing_impl.h", "beamformer/array_util.cc", @@ -68,6 +67,7 @@ rtc_static_library("audio_processing") { "gain_control_impl.h", "high_pass_filter_impl.cc", "high_pass_filter_impl.h", + "include/audio_processing.cc", "include/audio_processing.h", "include/config.cc", "include/config.h", @@ -79,9 +79,9 @@ rtc_static_library("audio_processing") { "level_controller/gain_applier.h", "level_controller/gain_selector.cc", "level_controller/gain_selector.h", - "level_controller/lc_constants.h", "level_controller/level_controller.cc", "level_controller/level_controller.h", + "level_controller/level_controller_constants.h", "level_controller/noise_level_estimator.cc", "level_controller/noise_level_estimator.h", "level_controller/noise_spectrum_estimator.cc", diff --git a/webrtc/modules/audio_processing/audio_processing.gypi b/webrtc/modules/audio_processing/audio_processing.gypi index 93387891eb..d7d84d1695 100644 --- a/webrtc/modules/audio_processing/audio_processing.gypi +++ b/webrtc/modules/audio_processing/audio_processing.gypi @@ -58,7 +58,6 @@ 'agc/utility.h', 'audio_buffer.cc', 'audio_buffer.h', - 'audio_processing.cc', 'audio_processing_impl.cc', 'audio_processing_impl.h', 'beamformer/array_util.cc', @@ -80,6 +79,7 @@ 'gain_control_impl.h', 'high_pass_filter_impl.cc', 'high_pass_filter_impl.h', + 'include/audio_processing.cc', 'include/audio_processing.h', 'include/config.cc', 'include/config.h', @@ -91,7 +91,7 @@ 'level_controller/gain_applier.h', 'level_controller/gain_selector.cc', 'level_controller/gain_selector.h', - 'level_controller/lc_constants.h', + 'level_controller/level_controller_constants.h', 'level_controller/level_controller.cc', 'level_controller/level_controller.h', 'level_controller/noise_spectrum_estimator.cc', diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc index 5e08b85fbf..85f159716c 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.cc +++ b/webrtc/modules/audio_processing/audio_processing_impl.cc @@ -298,6 +298,8 @@ AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config, new GainControlForExperimentalAgc( public_submodules_->gain_control.get(), &crit_capture_)); + // TODO(peah): Move this creation to happen only when the level controller + // is enabled. private_submodules_->level_controller.reset(new LevelController()); } @@ -543,30 +545,36 @@ int AudioProcessingImpl::InitializeLocked(const ProcessingConfig& config) { } void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) { - AudioProcessing::Config config_to_use = config; + config_ = config; - bool config_ok = LevelController::Validate(config_to_use.level_controller); + bool config_ok = LevelController::Validate(config_.level_controller); if (!config_ok) { LOG(LS_ERROR) << "AudioProcessing module config error" << std::endl << "level_controller: " - << LevelController::ToString(config_to_use.level_controller) + << LevelController::ToString(config_.level_controller) << std::endl << "Reverting to default parameter set"; - config_to_use.level_controller = AudioProcessing::Config::LevelController(); + config_.level_controller = AudioProcessing::Config::LevelController(); } // Run in a single-threaded manner when applying the settings. rtc::CritScope cs_render(&crit_render_); rtc::CritScope cs_capture(&crit_capture_); - if (config.level_controller.enabled != - capture_nonlocked_.level_controller_enabled) { - InitializeLevelController(); - LOG(LS_INFO) << "Level controller activated: " - << capture_nonlocked_.level_controller_enabled; + // TODO(peah): Replace the use of capture_nonlocked_.level_controller_enabled + // with the value in config_ everywhere in the code. + if (capture_nonlocked_.level_controller_enabled != + config_.level_controller.enabled) { capture_nonlocked_.level_controller_enabled = - config.level_controller.enabled; + config_.level_controller.enabled; + // TODO(peah): Remove the conditional initialization to always initialize + // the level controller regardless of whether it is enabled or not. + InitializeLevelController(); } + LOG(LS_INFO) << "Level controller activated: " + << capture_nonlocked_.level_controller_enabled; + + private_submodules_->level_controller->ApplyConfig(config_.level_controller); } void AudioProcessingImpl::SetExtraOptions(const webrtc::Config& config) { diff --git a/webrtc/modules/audio_processing/audio_processing_impl.h b/webrtc/modules/audio_processing/audio_processing_impl.h index c8162c1b66..be0e9518c3 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.h +++ b/webrtc/modules/audio_processing/audio_processing_impl.h @@ -17,6 +17,7 @@ #include #include "webrtc/base/criticalsection.h" +#include "webrtc/base/gtest_prod_util.h" #include "webrtc/base/ignore_wundef.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/modules/audio_processing/audio_buffer.h" @@ -132,6 +133,11 @@ class AudioProcessingImpl : public AudioProcessing { EXCLUSIVE_LOCKS_REQUIRED(crit_render_, crit_capture_); private: + // TODO(peah): These friend classes should be removed as soon as the new + // parameter setting scheme allows. + FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, DefaultBehavior); + FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, ValidConfigBehavior); + FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, InValidConfigBehavior); struct ApmPublicSubmodules; struct ApmPrivateSubmodules; @@ -269,6 +275,9 @@ class AudioProcessingImpl : public AudioProcessing { rtc::CriticalSection crit_render_ ACQUIRED_BEFORE(crit_capture_); rtc::CriticalSection crit_capture_; + // Struct containing the Config specifying the behavior of APM. + AudioProcessing::Config config_; + // Class containing information about what submodules are active. ApmSubmoduleStates submodule_states_; diff --git a/webrtc/modules/audio_processing/audio_processing_unittest.cc b/webrtc/modules/audio_processing/audio_processing_unittest.cc index 6e0b175003..d4faa81205 100644 --- a/webrtc/modules/audio_processing/audio_processing_unittest.cc +++ b/webrtc/modules/audio_processing/audio_processing_unittest.cc @@ -18,14 +18,17 @@ #include "webrtc/base/arraysize.h" #include "webrtc/base/checks.h" +#include "webrtc/base/gtest_prod_util.h" #include "webrtc/base/ignore_wundef.h" #include "webrtc/common_audio/include/audio_util.h" #include "webrtc/common_audio/resampler/include/push_resampler.h" #include "webrtc/common_audio/resampler/push_sinc_resampler.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" +#include "webrtc/modules/audio_processing/audio_processing_impl.h" #include "webrtc/modules/audio_processing/beamformer/mock_nonlinear_beamformer.h" #include "webrtc/modules/audio_processing/common.h" #include "webrtc/modules/audio_processing/include/audio_processing.h" +#include "webrtc/modules/audio_processing/level_controller/level_controller_constants.h" #include "webrtc/modules/audio_processing/test/protobuf_utils.h" #include "webrtc/modules/audio_processing/test/test_utils.h" #include "webrtc/modules/include/module_common_types.h" @@ -2782,4 +2785,97 @@ INSTANTIATE_TEST_CASE_P( #endif } // namespace + +TEST(ApmConfiguration, DefaultBehavior) { + // Verify that the level controller is default off, it can be activated using + // the config, and that the default initial level is maintained after the + // config has been applied. + std::unique_ptr apm( + new AudioProcessingImpl(webrtc::Config())); + AudioProcessing::Config config; + EXPECT_FALSE(apm->config_.level_controller.enabled); + // TODO(peah): Add test for the existence of the level controller object once + // that is created only when that is specified in the config. + // TODO(peah): Remove the testing for + // apm->capture_nonlocked_.level_controller_enabled once the value in config_ + // is instead used to activate the level controller. + EXPECT_FALSE(apm->capture_nonlocked_.level_controller_enabled); + EXPECT_NEAR(kTargetLcPeakLeveldBFS, + apm->config_.level_controller.initial_peak_level_dbfs, + std::numeric_limits::epsilon()); + config.level_controller.enabled = true; + apm->ApplyConfig(config); + EXPECT_TRUE(apm->config_.level_controller.enabled); + // TODO(peah): Add test for the existence of the level controller object once + // that is created only when the that is specified in the config. + // TODO(peah): Remove the testing for + // apm->capture_nonlocked_.level_controller_enabled once the value in config_ + // is instead used to activate the level controller. + EXPECT_TRUE(apm->capture_nonlocked_.level_controller_enabled); + EXPECT_NEAR(kTargetLcPeakLeveldBFS, + apm->config_.level_controller.initial_peak_level_dbfs, + std::numeric_limits::epsilon()); +} + +TEST(ApmConfiguration, ValidConfigBehavior) { + // Verify that the initial level can be specified and is retained after the + // config has been applied. + std::unique_ptr apm( + new AudioProcessingImpl(webrtc::Config())); + AudioProcessing::Config config; + config.level_controller.initial_peak_level_dbfs = -50.f; + apm->ApplyConfig(config); + EXPECT_FALSE(apm->config_.level_controller.enabled); + // TODO(peah): Add test for the existence of the level controller object once + // that is created only when the that is specified in the config. + // TODO(peah): Remove the testing for + // apm->capture_nonlocked_.level_controller_enabled once the value in config_ + // is instead used to activate the level controller. + EXPECT_FALSE(apm->capture_nonlocked_.level_controller_enabled); + EXPECT_NEAR(-50.f, apm->config_.level_controller.initial_peak_level_dbfs, + std::numeric_limits::epsilon()); +} + +TEST(ApmConfiguration, InValidConfigBehavior) { + // Verify that the config is properly reset when nonproper values are applied + // for the initial level. + + // Verify that the config is properly reset when the specified initial peak + // level is too low. + std::unique_ptr apm( + new AudioProcessingImpl(webrtc::Config())); + AudioProcessing::Config config; + config.level_controller.enabled = true; + config.level_controller.initial_peak_level_dbfs = -101.f; + apm->ApplyConfig(config); + EXPECT_FALSE(apm->config_.level_controller.enabled); + // TODO(peah): Add test for the existence of the level controller object once + // that is created only when the that is specified in the config. + // TODO(peah): Remove the testing for + // apm->capture_nonlocked_.level_controller_enabled once the value in config_ + // is instead used to activate the level controller. + EXPECT_FALSE(apm->capture_nonlocked_.level_controller_enabled); + EXPECT_NEAR(kTargetLcPeakLeveldBFS, + apm->config_.level_controller.initial_peak_level_dbfs, + std::numeric_limits::epsilon()); + + // Verify that the config is properly reset when the specified initial peak + // level is too high. + apm.reset(new AudioProcessingImpl(webrtc::Config())); + config = AudioProcessing::Config(); + config.level_controller.enabled = true; + config.level_controller.initial_peak_level_dbfs = 1.f; + apm->ApplyConfig(config); + EXPECT_FALSE(apm->config_.level_controller.enabled); + // TODO(peah): Add test for the existence of the level controller object once + // that is created only when that is specified in the config. + // TODO(peah): Remove the testing for + // apm->capture_nonlocked_.level_controller_enabled once the value in config_ + // is instead used to activate the level controller. + EXPECT_FALSE(apm->capture_nonlocked_.level_controller_enabled); + EXPECT_NEAR(kTargetLcPeakLeveldBFS, + apm->config_.level_controller.initial_peak_level_dbfs, + std::numeric_limits::epsilon()); +} + } // namespace webrtc diff --git a/webrtc/modules/audio_processing/audio_processing.cc b/webrtc/modules/audio_processing/include/audio_processing.cc similarity index 100% rename from webrtc/modules/audio_processing/audio_processing.cc rename to webrtc/modules/audio_processing/include/audio_processing.cc diff --git a/webrtc/modules/audio_processing/include/audio_processing.h b/webrtc/modules/audio_processing/include/audio_processing.h index 2b447c4ade..b5d2aa22c0 100644 --- a/webrtc/modules/audio_processing/include/audio_processing.h +++ b/webrtc/modules/audio_processing/include/audio_processing.h @@ -252,6 +252,11 @@ class AudioProcessing { struct Config { struct LevelController { bool enabled = false; + + // Sets the initial peak level to use inside the level controller in order + // to compute the signal gain. The unit for the peak level is dBFS and + // the allowed range is [-100, 0]. + float initial_peak_level_dbfs = -6.0206f; } level_controller; }; diff --git a/webrtc/modules/audio_processing/level_controller/gain_selector.cc b/webrtc/modules/audio_processing/level_controller/gain_selector.cc index 2accd7180c..cf90d8d26b 100644 --- a/webrtc/modules/audio_processing/level_controller/gain_selector.cc +++ b/webrtc/modules/audio_processing/level_controller/gain_selector.cc @@ -15,7 +15,7 @@ #include "webrtc/base/checks.h" #include "webrtc/modules/audio_processing/include/audio_processing.h" -#include "webrtc/modules/audio_processing/level_controller/lc_constants.h" +#include "webrtc/modules/audio_processing/level_controller/level_controller_constants.h" namespace webrtc { @@ -42,10 +42,12 @@ void GainSelector::Initialize(int sample_rate_hz) { float GainSelector::GetNewGain(float peak_level, float noise_energy, float saturating_gain, + bool gain_jumpstart, SignalClassifier::SignalType signal_type) { RTC_DCHECK_LT(0.f, peak_level); - if (signal_type == SignalClassifier::SignalType::kHighlyNonStationary) { + if (signal_type == SignalClassifier::SignalType::kHighlyNonStationary || + gain_jumpstart) { highly_nonstationary_signal_hold_counter_ = 100; } else { highly_nonstationary_signal_hold_counter_ = diff --git a/webrtc/modules/audio_processing/level_controller/gain_selector.h b/webrtc/modules/audio_processing/level_controller/gain_selector.h index 3d00499652..78b9101500 100644 --- a/webrtc/modules/audio_processing/level_controller/gain_selector.h +++ b/webrtc/modules/audio_processing/level_controller/gain_selector.h @@ -24,6 +24,7 @@ class GainSelector { float GetNewGain(float peak_level, float noise_energy, float saturating_gain, + bool gain_jumpstart, SignalClassifier::SignalType signal_type); private: diff --git a/webrtc/modules/audio_processing/level_controller/level_controller.cc b/webrtc/modules/audio_processing/level_controller/level_controller.cc index 247b7d0c61..b8388e6141 100644 --- a/webrtc/modules/audio_processing/level_controller/level_controller.cc +++ b/webrtc/modules/audio_processing/level_controller/level_controller.cc @@ -179,7 +179,8 @@ void LevelController::Metrics::Update(float long_term_peak_level, LevelController::LevelController() : data_dumper_(new ApmDataDumper(instance_count_)), gain_applier_(data_dumper_.get()), - signal_classifier_(data_dumper_.get()) { + signal_classifier_(data_dumper_.get()), + peak_level_estimator_(kTargetLcPeakLeveldBFS) { Initialize(AudioProcessing::kSampleRate48kHz); ++instance_count_; } @@ -196,7 +197,7 @@ void LevelController::Initialize(int sample_rate_hz) { gain_applier_.Initialize(sample_rate_hz); signal_classifier_.Initialize(sample_rate_hz); noise_level_estimator_.Initialize(sample_rate_hz); - peak_level_estimator_.Initialize(); + peak_level_estimator_.Initialize(config_.initial_peak_level_dbfs); saturating_gain_estimator_.Initialize(); metrics_.Initialize(sample_rate_hz); @@ -238,8 +239,12 @@ void LevelController::Process(AudioBuffer* audio) { float saturating_gain = saturating_gain_estimator_.GetGain(); // Compute the new gain to apply. - last_gain_ = gain_selector_.GetNewGain(long_term_peak_level, noise_energy, - saturating_gain, signal_type); + last_gain_ = + gain_selector_.GetNewGain(long_term_peak_level, noise_energy, + saturating_gain, gain_jumpstart_, signal_type); + + // Unflag the jumpstart of the gain as it should only happen once. + gain_jumpstart_ = false; // Apply the gain to the signal. int num_saturations = gain_applier_.Process(last_gain_, audio); @@ -260,17 +265,29 @@ void LevelController::Process(AudioBuffer* audio) { audio->channels_f()[0], *sample_rate_hz_, 1); } +void LevelController::ApplyConfig( + const AudioProcessing::Config::LevelController& config) { + RTC_DCHECK(Validate(config)); + config_ = config; + peak_level_estimator_.Initialize(config_.initial_peak_level_dbfs); + gain_jumpstart_ = true; +} + std::string LevelController::ToString( const AudioProcessing::Config::LevelController& config) { std::stringstream ss; ss << "{" - << "enabled: " << (config.enabled ? "true" : "false") << "}"; + << "enabled: " << (config.enabled ? "true" : "false") << ", " + << "initial_peak_level_dbfs: " << config.initial_peak_level_dbfs << "}"; return ss.str(); } bool LevelController::Validate( const AudioProcessing::Config::LevelController& config) { - return true; + return (config.initial_peak_level_dbfs < + std::numeric_limits::epsilon() && + config.initial_peak_level_dbfs > + -(100.f + std::numeric_limits::epsilon())); } } // namespace webrtc diff --git a/webrtc/modules/audio_processing/level_controller/level_controller.h b/webrtc/modules/audio_processing/level_controller/level_controller.h index 1d8e043cce..1030f7952e 100644 --- a/webrtc/modules/audio_processing/level_controller/level_controller.h +++ b/webrtc/modules/audio_processing/level_controller/level_controller.h @@ -38,6 +38,10 @@ class LevelController { void Process(AudioBuffer* audio); float GetLastGain() { return last_gain_; } + // TODO(peah): This method is a temporary solution as the the aim is to + // instead apply the config inside the constructor. Therefore this is likely + // to change. + void ApplyConfig(const AudioProcessing::Config::LevelController& config); // Validates a config. static bool Validate(const AudioProcessing::Config::LevelController& config); // Dumps a config to a string. @@ -80,6 +84,8 @@ class LevelController { float dc_level_[2]; float dc_forgetting_factor_; float last_gain_; + bool gain_jumpstart_ = false; + AudioProcessing::Config::LevelController config_; RTC_DISALLOW_COPY_AND_ASSIGN(LevelController); }; diff --git a/webrtc/modules/audio_processing/level_controller/lc_constants.h b/webrtc/modules/audio_processing/level_controller/level_controller_constants.h similarity index 60% rename from webrtc/modules/audio_processing/level_controller/lc_constants.h rename to webrtc/modules/audio_processing/level_controller/level_controller_constants.h index 3390cc96e5..7b962d37d9 100644 --- a/webrtc/modules/audio_processing/level_controller/lc_constants.h +++ b/webrtc/modules/audio_processing/level_controller/level_controller_constants.h @@ -8,15 +8,16 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_CONTROLLER_LC_CONSTANTS_H_ -#define WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_CONTROLLER_LC_CONSTANTS_H_ +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_CONTROLLER_LEVEL_CONTROLLER_CONSTANTS_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_CONTROLLER_LEVEL_CONTROLLER_CONSTANTS_H_ namespace webrtc { const float kMaxLcGain = 10; const float kMaxLcNoisePower = 100.f * 100.f; -const float kTargetLcPeakLevel = 0.5f * 32767.f; +const float kTargetLcPeakLevel = 16384.f; +const float kTargetLcPeakLeveldBFS = -6.0206f; } // namespace webrtc -#endif // WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_CONTROLLER_LC_CONSTANTS_H_ +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_CONTROLLER_LEVEL_CONTROLLER_CONSTANTS_H_ diff --git a/webrtc/modules/audio_processing/level_controller/level_controller_unittest.cc b/webrtc/modules/audio_processing/level_controller/level_controller_unittest.cc index ed842b6e27..3c07cb6dcb 100644 --- a/webrtc/modules/audio_processing/level_controller/level_controller_unittest.cc +++ b/webrtc/modules/audio_processing/level_controller/level_controller_unittest.cc @@ -11,6 +11,7 @@ #include #include "webrtc/base/array_view.h" +#include "webrtc/base/optional.h" #include "webrtc/modules/audio_processing/audio_buffer.h" #include "webrtc/modules/audio_processing/include/audio_processing.h" #include "webrtc/modules/audio_processing/level_controller/level_controller.h" @@ -27,9 +28,15 @@ const int kNumFramesToProcess = 1000; // any errors. void RunBitexactnessTest(int sample_rate_hz, size_t num_channels, + rtc::Optional initial_peak_level_dbfs, rtc::ArrayView output_reference) { LevelController level_controller; level_controller.Initialize(sample_rate_hz); + if (initial_peak_level_dbfs) { + AudioProcessing::Config::LevelController config; + config.initial_peak_level_dbfs = *initial_peak_level_dbfs; + level_controller.ApplyConfig(config); + } int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100); const StreamConfig capture_config(sample_rate_hz, num_channels, false); @@ -68,41 +75,35 @@ void RunBitexactnessTest(int sample_rate_hz, } // namespace -TEST(LevelControlConfigTest, ToStringEnabled) { +TEST(LevelControllerConfig, ToString) { AudioProcessing::Config config; config.level_controller.enabled = true; - EXPECT_EQ("{enabled: true}", + config.level_controller.initial_peak_level_dbfs = -6.0206f; + EXPECT_EQ("{enabled: true, initial_peak_level_dbfs: -6.0206}", LevelController::ToString(config.level_controller)); -} -TEST(LevelControlConfigTest, ToStringNotEnabled) { - AudioProcessing::Config config; config.level_controller.enabled = false; - EXPECT_EQ("{enabled: false}", + config.level_controller.initial_peak_level_dbfs = -50.f; + EXPECT_EQ("{enabled: false, initial_peak_level_dbfs: -50}", LevelController::ToString(config.level_controller)); } -TEST(LevelControlConfigTest, DefaultValue) { - AudioProcessing::Config config; - EXPECT_FALSE(config.level_controller.enabled); -} - TEST(LevelControlBitExactnessTest, DISABLED_Mono8kHz) { const float kOutputReference[] = {-0.013939f, -0.012154f, -0.009054f}; RunBitexactnessTest(AudioProcessing::kSampleRate8kHz, 1, - kOutputReference); + rtc::Optional(), kOutputReference); } TEST(LevelControlBitExactnessTest, DISABLED_Mono16kHz) { const float kOutputReference[] = {-0.013706f, -0.013215f, -0.013018f}; RunBitexactnessTest(AudioProcessing::kSampleRate16kHz, 1, - kOutputReference); + rtc::Optional(), kOutputReference); } TEST(LevelControlBitExactnessTest, DISABLED_Mono32kHz) { const float kOutputReference[] = {-0.014495f, -0.016425f, -0.016085f}; RunBitexactnessTest(AudioProcessing::kSampleRate32kHz, 1, - kOutputReference); + rtc::Optional(), kOutputReference); } // TODO(peah): Investigate why this particular testcase differ between Android @@ -115,37 +116,41 @@ TEST(LevelControlBitExactnessTest, DISABLED_Mono48kHz) { const float kOutputReference[] = {-0.015949f, -0.016957f, -0.019478f}; #endif RunBitexactnessTest(AudioProcessing::kSampleRate48kHz, 1, - kOutputReference); + rtc::Optional(), kOutputReference); } TEST(LevelControlBitExactnessTest, DISABLED_Stereo8kHz) { const float kOutputReference[] = {-0.014063f, -0.008450f, -0.012159f, -0.051967f, -0.023202f, -0.047858f}; RunBitexactnessTest(AudioProcessing::kSampleRate8kHz, 2, - kOutputReference); + rtc::Optional(), kOutputReference); } TEST(LevelControlBitExactnessTest, DISABLED_Stereo16kHz) { const float kOutputReference[] = {-0.012714f, -0.005896f, -0.012220f, -0.053306f, -0.024549f, -0.051527f}; RunBitexactnessTest(AudioProcessing::kSampleRate16kHz, 2, - kOutputReference); + rtc::Optional(), kOutputReference); } TEST(LevelControlBitExactnessTest, DISABLED_Stereo32kHz) { const float kOutputReference[] = {-0.011737f, -0.007018f, -0.013446f, -0.053505f, -0.026292f, -0.056221f}; RunBitexactnessTest(AudioProcessing::kSampleRate32kHz, 2, - kOutputReference); + rtc::Optional(), kOutputReference); } TEST(LevelControlBitExactnessTest, DISABLED_Stereo48kHz) { const float kOutputReference[] = {-0.010643f, -0.006334f, -0.011377f, -0.049088f, -0.023600f, -0.050465f}; RunBitexactnessTest(AudioProcessing::kSampleRate48kHz, 2, - kOutputReference); + rtc::Optional(), kOutputReference); } - +TEST(LevelControlBitExactnessTest, DISABLED_MonoInitial48kHz) { + const float kOutputReference[] = {-0.013753f, -0.014623f, -0.016797f}; + RunBitexactnessTest(AudioProcessing::kSampleRate48kHz, 1, + rtc::Optional(-50), kOutputReference); +} } // namespace webrtc diff --git a/webrtc/modules/audio_processing/level_controller/peak_level_estimator.cc b/webrtc/modules/audio_processing/level_controller/peak_level_estimator.cc index 2ba806c8ee..37046fdceb 100644 --- a/webrtc/modules/audio_processing/level_controller/peak_level_estimator.cc +++ b/webrtc/modules/audio_processing/level_controller/peak_level_estimator.cc @@ -13,19 +13,28 @@ #include #include "webrtc/modules/audio_processing/audio_buffer.h" -#include "webrtc/modules/audio_processing/level_controller/lc_constants.h" #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h" namespace webrtc { +namespace { -PeakLevelEstimator::PeakLevelEstimator() { - Initialize(); +constexpr float kMinLevel = 30.f; + +} // namespace + +PeakLevelEstimator::PeakLevelEstimator(float initial_peak_level_dbfs) { + Initialize(initial_peak_level_dbfs); } PeakLevelEstimator::~PeakLevelEstimator() {} -void PeakLevelEstimator::Initialize() { - peak_level_ = kTargetLcPeakLevel; +void PeakLevelEstimator::Initialize(float initial_peak_level_dbfs) { + RTC_DCHECK_LE(-100.f, initial_peak_level_dbfs); + RTC_DCHECK_GE(0.f, initial_peak_level_dbfs); + + peak_level_ = std::pow(10.f, initial_peak_level_dbfs / 20.f) * 32768.f; + peak_level_ = std::max(peak_level_, kMinLevel); + hold_counter_ = 0; initialization_phase_ = true; } @@ -33,7 +42,7 @@ void PeakLevelEstimator::Initialize() { float PeakLevelEstimator::Analyze(SignalClassifier::SignalType signal_type, float frame_peak_level) { if (frame_peak_level == 0) { - RTC_DCHECK_LE(30.f, peak_level_); + RTC_DCHECK_LE(kMinLevel, peak_level_); return peak_level_; } @@ -57,7 +66,7 @@ float PeakLevelEstimator::Analyze(SignalClassifier::SignalType signal_type, } } - peak_level_ = std::max(peak_level_, 30.f); + peak_level_ = std::max(peak_level_, kMinLevel); return peak_level_; } diff --git a/webrtc/modules/audio_processing/level_controller/peak_level_estimator.h b/webrtc/modules/audio_processing/level_controller/peak_level_estimator.h index 270bbc3ad0..f908717445 100644 --- a/webrtc/modules/audio_processing/level_controller/peak_level_estimator.h +++ b/webrtc/modules/audio_processing/level_controller/peak_level_estimator.h @@ -12,24 +12,24 @@ #define WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_CONTROLLER_PEAK_LEVEL_ESTIMATOR_H_ #include "webrtc/base/constructormagic.h" +#include "webrtc/modules/audio_processing/level_controller/level_controller_constants.h" #include "webrtc/modules/audio_processing/level_controller/signal_classifier.h" namespace webrtc { class PeakLevelEstimator { public: - PeakLevelEstimator(); + explicit PeakLevelEstimator(float initial_peak_level_dbfs); ~PeakLevelEstimator(); - void Initialize(); + void Initialize(float initial_peak_level_dbfs); float Analyze(SignalClassifier::SignalType signal_type, float frame_peak_level); - private: float peak_level_; int hold_counter_; bool initialization_phase_; - RTC_DISALLOW_COPY_AND_ASSIGN(PeakLevelEstimator); + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(PeakLevelEstimator); }; } // namespace webrtc diff --git a/webrtc/modules/audio_processing/level_controller/saturating_gain_estimator.cc b/webrtc/modules/audio_processing/level_controller/saturating_gain_estimator.cc index 8ba57a9d58..b9db974631 100644 --- a/webrtc/modules/audio_processing/level_controller/saturating_gain_estimator.cc +++ b/webrtc/modules/audio_processing/level_controller/saturating_gain_estimator.cc @@ -13,7 +13,7 @@ #include #include -#include "webrtc/modules/audio_processing/level_controller/lc_constants.h" +#include "webrtc/modules/audio_processing/level_controller/level_controller_constants.h" #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h" namespace webrtc {