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}
diff --git a/webrtc/modules/audio_processing/BUILD.gn b/webrtc/modules/audio_processing/BUILD.gn
index b4d8759..25c47ec 100644
--- a/webrtc/modules/audio_processing/BUILD.gn
+++ b/webrtc/modules/audio_processing/BUILD.gn
@@ -46,7 +46,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",
@@ -68,6 +67,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",
@@ -79,9 +79,9 @@
     "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 9338789..d7d84d1 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 5e08b85..85f1597 100644
--- a/webrtc/modules/audio_processing/audio_processing_impl.cc
+++ b/webrtc/modules/audio_processing/audio_processing_impl.cc
@@ -298,6 +298,8 @@
         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 @@
 }
 
 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 c8162c1..be0e951 100644
--- a/webrtc/modules/audio_processing/audio_processing_impl.h
+++ b/webrtc/modules/audio_processing/audio_processing_impl.h
@@ -17,6 +17,7 @@
 #include <vector>
 
 #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 @@
       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 @@
   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 6e0b175..d4faa81 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 @@
 #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<AudioProcessingImpl> 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<float>::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<float>::epsilon());
+}
+
+TEST(ApmConfiguration, ValidConfigBehavior) {
+  // Verify that the initial level can be specified and is retained after the
+  // config has been applied.
+  std::unique_ptr<AudioProcessingImpl> 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<float>::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<AudioProcessingImpl> 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<float>::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<float>::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 2b447c4..b5d2aa2 100644
--- a/webrtc/modules/audio_processing/include/audio_processing.h
+++ b/webrtc/modules/audio_processing/include/audio_processing.h
@@ -252,6 +252,11 @@
   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 2accd71..cf90d8d 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 @@
 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 3d00499..78b9101 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 @@
   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 247b7d0..b8388e6 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 @@
 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 @@
   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 @@
   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 @@
                         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<float>::epsilon() &&
+          config.initial_peak_level_dbfs >
+              -(100.f + std::numeric_limits<float>::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 1d8e043..1030f79 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 @@
   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 @@
   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 3390cc9..7b962d3 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 ed842b6..3c07cb6 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 <vector>
 
 #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 @@
 // any errors.
 void RunBitexactnessTest(int sample_rate_hz,
                          size_t num_channels,
+                         rtc::Optional<float> initial_peak_level_dbfs,
                          rtc::ArrayView<const float> 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 @@
 
 }  // 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<float>(), kOutputReference);
 }
 
 TEST(LevelControlBitExactnessTest, DISABLED_Mono16kHz) {
   const float kOutputReference[] = {-0.013706f, -0.013215f, -0.013018f};
   RunBitexactnessTest(AudioProcessing::kSampleRate16kHz, 1,
-                      kOutputReference);
+                      rtc::Optional<float>(), kOutputReference);
 }
 
 TEST(LevelControlBitExactnessTest, DISABLED_Mono32kHz) {
   const float kOutputReference[] = {-0.014495f, -0.016425f, -0.016085f};
   RunBitexactnessTest(AudioProcessing::kSampleRate32kHz, 1,
-                      kOutputReference);
+                      rtc::Optional<float>(), kOutputReference);
 }
 
 // TODO(peah): Investigate why this particular testcase differ between Android
@@ -115,37 +116,41 @@
   const float kOutputReference[] = {-0.015949f, -0.016957f, -0.019478f};
 #endif
   RunBitexactnessTest(AudioProcessing::kSampleRate48kHz, 1,
-                      kOutputReference);
+                      rtc::Optional<float>(), 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<float>(), 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<float>(), 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<float>(), 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<float>(), kOutputReference);
 }
 
-
+TEST(LevelControlBitExactnessTest, DISABLED_MonoInitial48kHz) {
+  const float kOutputReference[] = {-0.013753f, -0.014623f, -0.016797f};
+  RunBitexactnessTest(AudioProcessing::kSampleRate48kHz, 1,
+                      rtc::Optional<float>(-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 2ba806c..37046fd 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 <algorithm>
 
 #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 @@
 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 @@
     }
   }
 
-  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 270bbc3..f908717 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 8ba57a9..b9db974 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 <math.h>
 #include <algorithm>
 
-#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 {