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 {