tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

audio_processing_impl_unittest.cc (41180B)


      1 /*
      2 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "modules/audio_processing/audio_processing_impl.h"
     12 
     13 #include <algorithm>
     14 #include <array>
     15 #include <cstddef>
     16 #include <cstdint>
     17 #include <memory>
     18 #include <string>
     19 #include <tuple>
     20 #include <utility>
     21 #include <vector>
     22 
     23 #include "api/array_view.h"
     24 #include "api/audio/audio_processing.h"
     25 #include "api/audio/builtin_audio_processing_builder.h"
     26 #include "api/audio/echo_control.h"
     27 #include "api/environment/environment.h"
     28 #include "api/environment/environment_factory.h"
     29 #include "api/make_ref_counted.h"
     30 #include "api/ref_count.h"
     31 #include "api/scoped_refptr.h"
     32 #include "modules/audio_processing/test/echo_canceller_test_tools.h"
     33 #include "modules/audio_processing/test/echo_control_mock.h"
     34 #include "modules/audio_processing/test/test_utils.h"
     35 #include "rtc_base/random.h"
     36 #include "test/gmock.h"
     37 #include "test/gtest.h"
     38 
     39 namespace webrtc {
     40 namespace {
     41 
     42 using ::testing::Invoke;
     43 using ::testing::NotNull;
     44 
     45 class MockInitialize : public AudioProcessingImpl {
     46 public:
     47  MockInitialize() : AudioProcessingImpl(CreateEnvironment()) {}
     48 
     49  MOCK_METHOD(void, InitializeLocked, (), (override));
     50  void RealInitializeLocked() {
     51    AssertLockedForTest();
     52    AudioProcessingImpl::InitializeLocked();
     53  }
     54 
     55  MOCK_METHOD(void, AddRef, (), (const, override));
     56  MOCK_METHOD(RefCountReleaseStatus, Release, (), (const, override));
     57 };
     58 
     59 // Creates MockEchoControl instances and provides a raw pointer access to
     60 // the next created one. The raw pointer is meant to be used with gmock.
     61 // Returning a pointer of the next created MockEchoControl instance is necessary
     62 // for the following reasons: (i) gmock expectations must be set before any call
     63 // occurs, (ii) APM is initialized the first time that
     64 // AudioProcessingImpl::ProcessStream() is called and the initialization leads
     65 // to the creation of a new EchoControl object.
     66 class MockEchoControlFactory : public EchoControlFactory {
     67 public:
     68  MockEchoControlFactory() : next_mock_(std::make_unique<MockEchoControl>()) {}
     69  // Returns a pointer to the next MockEchoControl that this factory creates.
     70  MockEchoControl* GetNext() const { return next_mock_.get(); }
     71  std::unique_ptr<EchoControl> Create(const Environment& /* env */,
     72                                      int /* sample_rate_hz */,
     73                                      int /* num_render_channels */,
     74                                      int /* num_capture_channels */) override {
     75    std::unique_ptr<EchoControl> mock = std::move(next_mock_);
     76    next_mock_ = std::make_unique<MockEchoControl>();
     77    return mock;
     78  }
     79 
     80 private:
     81  std::unique_ptr<MockEchoControl> next_mock_;
     82 };
     83 
     84 // Mocks EchoDetector and records the first samples of the last analyzed render
     85 // stream frame. Used to check what data is read by an EchoDetector
     86 // implementation injected into an APM.
     87 class TestEchoDetector : public EchoDetector {
     88 public:
     89  TestEchoDetector()
     90      : analyze_render_audio_called_(false),
     91        last_render_audio_first_sample_(0.f) {}
     92  ~TestEchoDetector() override = default;
     93  void AnalyzeRenderAudio(ArrayView<const float> render_audio) override {
     94    last_render_audio_first_sample_ = render_audio[0];
     95    analyze_render_audio_called_ = true;
     96  }
     97  void AnalyzeCaptureAudio(
     98      ArrayView<const float> /* capture_audio */) override {}
     99  void Initialize(int /* capture_sample_rate_hz */,
    100                  int /* num_capture_channels */,
    101                  int /* render_sample_rate_hz */,
    102                  int /* num_render_channels */) override {}
    103  EchoDetector::Metrics GetMetrics() const override { return {}; }
    104  // Returns true if AnalyzeRenderAudio() has been called at least once.
    105  bool analyze_render_audio_called() const {
    106    return analyze_render_audio_called_;
    107  }
    108  // Returns the first sample of the last analyzed render frame.
    109  float last_render_audio_first_sample() const {
    110    return last_render_audio_first_sample_;
    111  }
    112 
    113 private:
    114  bool analyze_render_audio_called_;
    115  float last_render_audio_first_sample_;
    116 };
    117 
    118 // Mocks CustomProcessing and applies ProcessSample() to all the samples.
    119 // Meant to be injected into an APM to modify samples in a known and detectable
    120 // way.
    121 class TestRenderPreProcessor : public CustomProcessing {
    122 public:
    123  TestRenderPreProcessor() = default;
    124  ~TestRenderPreProcessor() override = default;
    125  void Initialize(int /* sample_rate_hz */, int /* num_channels */) override {}
    126  void Process(AudioBuffer* audio) override {
    127    for (size_t k = 0; k < audio->num_channels(); ++k) {
    128      ArrayView<float> channel_view(audio->channels()[k], audio->num_frames());
    129      std::transform(channel_view.begin(), channel_view.end(),
    130                     channel_view.begin(), ProcessSample);
    131    }
    132  }
    133  std::string ToString() const override { return "TestRenderPreProcessor"; }
    134  void SetRuntimeSetting(
    135      AudioProcessing::RuntimeSetting /* setting */) override {}
    136  // Modifies a sample. This member is used in Process() to modify a frame and
    137  // it is publicly visible to enable tests.
    138  static constexpr float ProcessSample(float x) { return 2.f * x; }
    139 };
    140 
    141 // Runs `apm` input processing for volume adjustments for `num_frames` random
    142 // frames starting from the volume `initial_volume`. This includes three steps:
    143 // 1) Set the input volume 2) Process the stream 3) Set the new recommended
    144 // input volume. Returns the new recommended input volume.
    145 int ProcessInputVolume(AudioProcessing& apm,
    146                       int num_frames,
    147                       int initial_volume) {
    148  constexpr int kSampleRateHz = 48000;
    149  constexpr int kNumChannels = 1;
    150  std::array<float, kSampleRateHz / 100> buffer;
    151  float* channel_pointers[] = {buffer.data()};
    152  StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
    153                             /*num_channels=*/kNumChannels);
    154  int recommended_input_volume = initial_volume;
    155  for (int i = 0; i < num_frames; ++i) {
    156    Random random_generator(2341U);
    157    RandomizeSampleVector(&random_generator, buffer);
    158 
    159    apm.set_stream_analog_level(recommended_input_volume);
    160    apm.ProcessStream(channel_pointers, stream_config, stream_config,
    161                      channel_pointers);
    162    recommended_input_volume = apm.recommended_stream_analog_level();
    163  }
    164  return recommended_input_volume;
    165 }
    166 
    167 }  // namespace
    168 
    169 TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
    170  MockInitialize mock;
    171  ON_CALL(mock, InitializeLocked)
    172      .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
    173 
    174  EXPECT_CALL(mock, InitializeLocked).Times(1);
    175  mock.Initialize();
    176 
    177  constexpr size_t kMaxTestedSampleRateHz = 32000;
    178  constexpr size_t kMaxTestedNumChannels = 2;
    179  std::array<int16_t, kMaxTestedNumChannels * kMaxTestedSampleRateHz / 100>
    180      frame;
    181  frame.fill(0);
    182  StreamConfig config(16000, 1);
    183  // Call with the default parameters; there should be an init.
    184  EXPECT_CALL(mock, InitializeLocked).Times(0);
    185  EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
    186  EXPECT_NOERR(
    187      mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
    188 
    189  // New sample rate. (Only impacts ProcessStream).
    190  config = StreamConfig(32000, 1);
    191  EXPECT_CALL(mock, InitializeLocked).Times(1);
    192  EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
    193 
    194  // New number of channels.
    195  config = StreamConfig(32000, 2);
    196  EXPECT_CALL(mock, InitializeLocked).Times(2);
    197  EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
    198  EXPECT_NOERR(
    199      mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
    200 
    201  // A new sample rate passed to ProcessReverseStream should cause an init.
    202  config = StreamConfig(16000, 2);
    203  EXPECT_CALL(mock, InitializeLocked).Times(1);
    204  EXPECT_NOERR(
    205      mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
    206 }
    207 
    208 TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
    209  scoped_refptr<AudioProcessing> apm =
    210      BuiltinAudioProcessingBuilder().Build(CreateEnvironment());
    211  AudioProcessing::Config apm_config;
    212  apm_config.pre_amplifier.enabled = true;
    213  apm_config.pre_amplifier.fixed_gain_factor = 1.f;
    214  apm->ApplyConfig(apm_config);
    215 
    216  constexpr int kSampleRateHz = 48000;
    217  constexpr int16_t kAudioLevel = 10000;
    218  constexpr size_t kNumChannels = 2;
    219 
    220  std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
    221  StreamConfig config(kSampleRateHz, kNumChannels);
    222  frame.fill(kAudioLevel);
    223  apm->ProcessStream(frame.data(), config, config, frame.data());
    224  EXPECT_EQ(frame[100], kAudioLevel)
    225      << "With factor 1, frame shouldn't be modified.";
    226 
    227  constexpr float kGainFactor = 2.f;
    228  apm->SetRuntimeSetting(
    229      AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
    230 
    231  // Process for two frames to have time to ramp up gain.
    232  for (int i = 0; i < 2; ++i) {
    233    frame.fill(kAudioLevel);
    234    apm->ProcessStream(frame.data(), config, config, frame.data());
    235  }
    236  EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
    237      << "Frame should be amplified.";
    238 }
    239 
    240 TEST(AudioProcessingImplTest,
    241     LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
    242  scoped_refptr<AudioProcessing> apm =
    243      BuiltinAudioProcessingBuilder().Build(CreateEnvironment());
    244  AudioProcessing::Config apm_config;
    245  apm_config.capture_level_adjustment.enabled = true;
    246  apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
    247  apm->ApplyConfig(apm_config);
    248 
    249  constexpr int kSampleRateHz = 48000;
    250  constexpr int16_t kAudioLevel = 10000;
    251  constexpr size_t kNumChannels = 2;
    252 
    253  std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
    254  StreamConfig config(kSampleRateHz, kNumChannels);
    255  frame.fill(kAudioLevel);
    256  apm->ProcessStream(frame.data(), config, config, frame.data());
    257  EXPECT_EQ(frame[100], kAudioLevel)
    258      << "With factor 1, frame shouldn't be modified.";
    259 
    260  constexpr float kGainFactor = 2.f;
    261  apm->SetRuntimeSetting(
    262      AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
    263 
    264  // Process for two frames to have time to ramp up gain.
    265  for (int i = 0; i < 2; ++i) {
    266    frame.fill(kAudioLevel);
    267    apm->ProcessStream(frame.data(), config, config, frame.data());
    268  }
    269  EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
    270      << "Frame should be amplified.";
    271 }
    272 
    273 TEST(AudioProcessingImplTest,
    274     LevelAdjustmentUpdateCapturePostGainRuntimeSetting) {
    275  scoped_refptr<AudioProcessing> apm =
    276      BuiltinAudioProcessingBuilder().Build(CreateEnvironment());
    277  AudioProcessing::Config apm_config;
    278  apm_config.capture_level_adjustment.enabled = true;
    279  apm_config.capture_level_adjustment.post_gain_factor = 1.f;
    280  apm->ApplyConfig(apm_config);
    281 
    282  constexpr int kSampleRateHz = 48000;
    283  constexpr int16_t kAudioLevel = 10000;
    284  constexpr size_t kNumChannels = 2;
    285 
    286  std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
    287  StreamConfig config(kSampleRateHz, kNumChannels);
    288  frame.fill(kAudioLevel);
    289  apm->ProcessStream(frame.data(), config, config, frame.data());
    290  EXPECT_EQ(frame[100], kAudioLevel)
    291      << "With factor 1, frame shouldn't be modified.";
    292 
    293  constexpr float kGainFactor = 2.f;
    294  apm->SetRuntimeSetting(
    295      AudioProcessing::RuntimeSetting::CreateCapturePostGain(kGainFactor));
    296 
    297  // Process for two frames to have time to ramp up gain.
    298  for (int i = 0; i < 2; ++i) {
    299    frame.fill(kAudioLevel);
    300    apm->ProcessStream(frame.data(), config, config, frame.data());
    301  }
    302  EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
    303      << "Frame should be amplified.";
    304 }
    305 
    306 TEST(AudioProcessingImplTest, EchoControllerObservesSetCaptureUsageChange) {
    307  // Tests that the echo controller observes that the capture usage has been
    308  // updated.
    309  auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
    310  const MockEchoControlFactory* echo_control_factory_ptr =
    311      echo_control_factory.get();
    312 
    313  scoped_refptr<AudioProcessing> apm =
    314      BuiltinAudioProcessingBuilder()
    315          .SetEchoControlFactory(std::move(echo_control_factory))
    316          .Build(CreateEnvironment());
    317 
    318  constexpr int16_t kAudioLevel = 10000;
    319  constexpr int kSampleRateHz = 48000;
    320  constexpr int kNumChannels = 2;
    321  std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
    322  StreamConfig config(kSampleRateHz, kNumChannels);
    323  frame.fill(kAudioLevel);
    324 
    325  MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
    326 
    327  // Ensure that SetCaptureOutputUsage is not called when no runtime settings
    328  // are passed.
    329  EXPECT_CALL(*echo_control_mock, SetCaptureOutputUsage(testing::_)).Times(0);
    330  apm->ProcessStream(frame.data(), config, config, frame.data());
    331 
    332  // Ensure that SetCaptureOutputUsage is called with the right information when
    333  // a runtime setting is passed.
    334  EXPECT_CALL(*echo_control_mock,
    335              SetCaptureOutputUsage(/*capture_output_used=*/false))
    336      .Times(1);
    337  EXPECT_TRUE(apm->PostRuntimeSetting(
    338      AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
    339          /*capture_output_used=*/false)));
    340  apm->ProcessStream(frame.data(), config, config, frame.data());
    341 
    342  EXPECT_CALL(*echo_control_mock,
    343              SetCaptureOutputUsage(/*capture_output_used=*/true))
    344      .Times(1);
    345  EXPECT_TRUE(apm->PostRuntimeSetting(
    346      AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
    347          /*capture_output_used=*/true)));
    348  apm->ProcessStream(frame.data(), config, config, frame.data());
    349 
    350  // The number of positions to place items in the queue is equal to the queue
    351  // size minus 1.
    352  constexpr int kNumSlotsInQueue = RuntimeSettingQueueSize();
    353 
    354  // Ensure that SetCaptureOutputUsage is called with the right information when
    355  // many runtime settings are passed.
    356  for (int k = 0; k < kNumSlotsInQueue - 1; ++k) {
    357    EXPECT_TRUE(apm->PostRuntimeSetting(
    358        AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
    359            /*capture_output_used=*/false)));
    360  }
    361  EXPECT_CALL(*echo_control_mock,
    362              SetCaptureOutputUsage(/*capture_output_used=*/false))
    363      .Times(kNumSlotsInQueue - 1);
    364  apm->ProcessStream(frame.data(), config, config, frame.data());
    365 
    366  // Ensure that SetCaptureOutputUsage is properly called with the fallback
    367  // value when the runtime settings queue becomes full.
    368  for (int k = 0; k < kNumSlotsInQueue; ++k) {
    369    EXPECT_TRUE(apm->PostRuntimeSetting(
    370        AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
    371            /*capture_output_used=*/false)));
    372  }
    373  EXPECT_FALSE(apm->PostRuntimeSetting(
    374      AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
    375          /*capture_output_used=*/false)));
    376  EXPECT_FALSE(apm->PostRuntimeSetting(
    377      AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
    378          /*capture_output_used=*/false)));
    379  EXPECT_CALL(*echo_control_mock,
    380              SetCaptureOutputUsage(/*capture_output_used=*/false))
    381      .Times(kNumSlotsInQueue);
    382  EXPECT_CALL(*echo_control_mock,
    383              SetCaptureOutputUsage(/*capture_output_used=*/true))
    384      .Times(1);
    385  apm->ProcessStream(frame.data(), config, config, frame.data());
    386 }
    387 
    388 TEST(AudioProcessingImplTest,
    389     EchoControllerObservesPreAmplifierEchoPathGainChange) {
    390  // Tests that the echo controller observes an echo path gain change when the
    391  // pre-amplifier submodule changes the gain.
    392  auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
    393  const auto* echo_control_factory_ptr = echo_control_factory.get();
    394 
    395  scoped_refptr<AudioProcessing> apm =
    396      BuiltinAudioProcessingBuilder()
    397          .SetEchoControlFactory(std::move(echo_control_factory))
    398          .Build(CreateEnvironment());
    399  // Disable AGC.
    400  AudioProcessing::Config apm_config;
    401  apm_config.gain_controller1.enabled = false;
    402  apm_config.gain_controller2.enabled = false;
    403  apm_config.pre_amplifier.enabled = true;
    404  apm_config.pre_amplifier.fixed_gain_factor = 1.f;
    405  apm->ApplyConfig(apm_config);
    406 
    407  constexpr int16_t kAudioLevel = 10000;
    408  constexpr size_t kSampleRateHz = 48000;
    409  constexpr size_t kNumChannels = 2;
    410  std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
    411  StreamConfig config(kSampleRateHz, kNumChannels);
    412  frame.fill(kAudioLevel);
    413 
    414  MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
    415 
    416  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    417  EXPECT_CALL(*echo_control_mock,
    418              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
    419      .Times(1);
    420  apm->ProcessStream(frame.data(), config, config, frame.data());
    421 
    422  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    423  EXPECT_CALL(*echo_control_mock,
    424              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
    425      .Times(1);
    426  apm->SetRuntimeSetting(
    427      AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
    428  apm->ProcessStream(frame.data(), config, config, frame.data());
    429 }
    430 
    431 TEST(AudioProcessingImplTest,
    432     EchoControllerObservesLevelAdjustmentPreGainEchoPathGainChange) {
    433  // Tests that the echo controller observes an echo path gain change when the
    434  // pre-amplifier submodule changes the gain.
    435  auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
    436  const auto* echo_control_factory_ptr = echo_control_factory.get();
    437 
    438  scoped_refptr<AudioProcessing> apm =
    439      BuiltinAudioProcessingBuilder()
    440          .SetEchoControlFactory(std::move(echo_control_factory))
    441          .Build(CreateEnvironment());
    442  // Disable AGC.
    443  AudioProcessing::Config apm_config;
    444  apm_config.gain_controller1.enabled = false;
    445  apm_config.gain_controller2.enabled = false;
    446  apm_config.capture_level_adjustment.enabled = true;
    447  apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
    448  apm->ApplyConfig(apm_config);
    449 
    450  constexpr int16_t kAudioLevel = 10000;
    451  constexpr size_t kSampleRateHz = 48000;
    452  constexpr size_t kNumChannels = 2;
    453  std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
    454  StreamConfig config(kSampleRateHz, kNumChannels);
    455  frame.fill(kAudioLevel);
    456 
    457  MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
    458 
    459  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    460  EXPECT_CALL(*echo_control_mock,
    461              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
    462      .Times(1);
    463  apm->ProcessStream(frame.data(), config, config, frame.data());
    464 
    465  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    466  EXPECT_CALL(*echo_control_mock,
    467              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
    468      .Times(1);
    469  apm->SetRuntimeSetting(
    470      AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
    471  apm->ProcessStream(frame.data(), config, config, frame.data());
    472 }
    473 
    474 TEST(AudioProcessingImplTest,
    475     EchoControllerObservesAnalogAgc1EchoPathGainChange) {
    476  // Tests that the echo controller observes an echo path gain change when the
    477  // AGC1 analog adaptive submodule changes the analog gain.
    478  auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
    479  const auto* echo_control_factory_ptr = echo_control_factory.get();
    480 
    481  scoped_refptr<AudioProcessing> apm =
    482      BuiltinAudioProcessingBuilder()
    483          .SetEchoControlFactory(std::move(echo_control_factory))
    484          .Build(CreateEnvironment());
    485  AudioProcessing::Config apm_config;
    486  // Enable AGC1.
    487  apm_config.gain_controller1.enabled = true;
    488  apm_config.gain_controller1.analog_gain_controller.enabled = true;
    489  apm_config.gain_controller2.enabled = false;
    490  apm_config.pre_amplifier.enabled = false;
    491  apm->ApplyConfig(apm_config);
    492 
    493  constexpr int16_t kAudioLevel = 1000;
    494  constexpr size_t kSampleRateHz = 48000;
    495  constexpr size_t kNumChannels = 2;
    496  std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
    497  StreamConfig stream_config(kSampleRateHz, kNumChannels);
    498  frame.fill(kAudioLevel);
    499 
    500  MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
    501 
    502  constexpr int kInitialStreamAnalogLevel = 123;
    503  apm->set_stream_analog_level(kInitialStreamAnalogLevel);
    504 
    505  // When the first fame is processed, no echo path gain change must be
    506  // detected.
    507  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    508  EXPECT_CALL(*echo_control_mock,
    509              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
    510      .Times(1);
    511  apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
    512 
    513  // Simulate the application of the recommended analog level.
    514  int recommended_analog_level = apm->recommended_stream_analog_level();
    515  if (recommended_analog_level == kInitialStreamAnalogLevel) {
    516    // Force an analog gain change if it did not happen.
    517    recommended_analog_level++;
    518  }
    519  apm->set_stream_analog_level(recommended_analog_level);
    520 
    521  // After the first fame and with a stream analog level change, the echo path
    522  // gain change must be detected.
    523  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    524  EXPECT_CALL(*echo_control_mock,
    525              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
    526      .Times(1);
    527  apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
    528 }
    529 
    530 TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
    531  // Tests that the echo controller observes an echo path gain change when a
    532  // playout volume change is reported.
    533  auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
    534  const auto* echo_control_factory_ptr = echo_control_factory.get();
    535 
    536  scoped_refptr<AudioProcessing> apm =
    537      BuiltinAudioProcessingBuilder()
    538          .SetEchoControlFactory(std::move(echo_control_factory))
    539          .Build(CreateEnvironment());
    540  // Disable AGC.
    541  AudioProcessing::Config apm_config;
    542  apm_config.gain_controller1.enabled = false;
    543  apm_config.gain_controller2.enabled = false;
    544  apm->ApplyConfig(apm_config);
    545 
    546  constexpr int16_t kAudioLevel = 10000;
    547  constexpr size_t kSampleRateHz = 48000;
    548  constexpr size_t kNumChannels = 2;
    549  std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
    550  StreamConfig stream_config(kSampleRateHz, kNumChannels);
    551  frame.fill(kAudioLevel);
    552 
    553  MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
    554 
    555  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    556  EXPECT_CALL(*echo_control_mock,
    557              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
    558      .Times(1);
    559  apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
    560 
    561  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    562  EXPECT_CALL(*echo_control_mock,
    563              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
    564      .Times(1);
    565  apm->SetRuntimeSetting(
    566      AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
    567  apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
    568 
    569  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    570  EXPECT_CALL(*echo_control_mock,
    571              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
    572      .Times(1);
    573  apm->SetRuntimeSetting(
    574      AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
    575  apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
    576 
    577  EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
    578  EXPECT_CALL(*echo_control_mock,
    579              ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
    580      .Times(1);
    581  apm->SetRuntimeSetting(
    582      AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
    583  apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
    584 }
    585 
    586 TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
    587  // Make sure that signal changes caused by a render pre-processing sub-module
    588  // take place before any echo detector analysis.
    589  auto test_echo_detector = make_ref_counted<TestEchoDetector>();
    590  std::unique_ptr<CustomProcessing> test_render_pre_processor(
    591      new TestRenderPreProcessor());
    592  // Create APM injecting the test echo detector and render pre-processor.
    593  scoped_refptr<AudioProcessing> apm =
    594      BuiltinAudioProcessingBuilder()
    595          .SetEchoDetector(test_echo_detector)
    596          .SetRenderPreProcessing(std::move(test_render_pre_processor))
    597          .Build(CreateEnvironment());
    598  AudioProcessing::Config apm_config;
    599  apm_config.pre_amplifier.enabled = true;
    600  apm->ApplyConfig(apm_config);
    601 
    602  constexpr int16_t kAudioLevel = 1000;
    603  constexpr int kSampleRateHz = 16000;
    604  constexpr size_t kNumChannels = 1;
    605  // Explicitly initialize APM to ensure no render frames are discarded.
    606  const ProcessingConfig processing_config = {{
    607      {kSampleRateHz, kNumChannels},
    608      {kSampleRateHz, kNumChannels},
    609      {kSampleRateHz, kNumChannels},
    610      {kSampleRateHz, kNumChannels},
    611  }};
    612  apm->Initialize(processing_config);
    613 
    614  std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
    615  StreamConfig stream_config(kSampleRateHz, kNumChannels);
    616 
    617  constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
    618  constexpr float kExpectedPreprocessedAudioLevel =
    619      TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
    620  ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
    621 
    622  // Analyze a render stream frame.
    623  frame.fill(kAudioLevel);
    624  ASSERT_EQ(AudioProcessing::Error::kNoError,
    625            apm->ProcessReverseStream(frame.data(), stream_config,
    626                                      stream_config, frame.data()));
    627  // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
    628  // ProcessStream().
    629  frame.fill(kAudioLevel);
    630  ASSERT_EQ(AudioProcessing::Error::kNoError,
    631            apm->ProcessStream(frame.data(), stream_config, stream_config,
    632                               frame.data()));
    633  // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
    634  // triggered, the line below checks that the call has occurred. If not, the
    635  // APM implementation may have changed and this test might need to be adapted.
    636  ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
    637  // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
    638  // produced by the render pre-processor.
    639  EXPECT_EQ(kExpectedPreprocessedAudioLevel,
    640            test_echo_detector->last_render_audio_first_sample());
    641 }
    642 
    643 class StartupInputVolumeParameterizedTest
    644    : public ::testing::TestWithParam<int> {};
    645 
    646 // Tests that, when no input volume controller is used, the startup input volume
    647 // is never modified.
    648 TEST_P(StartupInputVolumeParameterizedTest,
    649       WithNoInputVolumeControllerStartupVolumeNotModified) {
    650  AudioProcessing::Config config;
    651  config.gain_controller1.enabled = false;
    652  config.gain_controller2.enabled = false;
    653  auto apm = BuiltinAudioProcessingBuilder(config).Build(CreateEnvironment());
    654 
    655  int startup_volume = GetParam();
    656  int recommended_volume = ProcessInputVolume(
    657      *apm, /*num_frames=*/1, /*initial_volume=*/startup_volume);
    658  EXPECT_EQ(recommended_volume, startup_volume);
    659 }
    660 
    661 INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
    662                         StartupInputVolumeParameterizedTest,
    663                         ::testing::Values(0, 5, 15, 50, 100));
    664 
    665 // Tests that, when no input volume controller is used, the recommended input
    666 // volume always matches the applied one.
    667 TEST(AudioProcessingImplTest,
    668     WithNoInputVolumeControllerAppliedAndRecommendedVolumesMatch) {
    669  AudioProcessing::Config config;
    670  config.gain_controller1.enabled = false;
    671  config.gain_controller2.enabled = false;
    672  auto apm = BuiltinAudioProcessingBuilder(config).Build(CreateEnvironment());
    673 
    674  Random rand_gen(42);
    675  for (int i = 0; i < 32; ++i) {
    676    SCOPED_TRACE(i);
    677    int32_t applied_volume = rand_gen.Rand(/*low=*/0, /*high=*/255);
    678    int recommended_volume =
    679        ProcessInputVolume(*apm, /*num_frames=*/1, applied_volume);
    680    EXPECT_EQ(recommended_volume, applied_volume);
    681  }
    682 }
    683 
    684 class ApmInputVolumeControllerParametrizedTest
    685    : public ::testing::TestWithParam<
    686          std::tuple<int, int, AudioProcessing::Config>> {
    687 protected:
    688  ApmInputVolumeControllerParametrizedTest()
    689      : sample_rate_hz_(std::get<0>(GetParam())),
    690        num_channels_(std::get<1>(GetParam())),
    691        channels_(num_channels_),
    692        channel_pointers_(num_channels_) {
    693    const int frame_size = sample_rate_hz_ / 100;
    694    for (int c = 0; c < num_channels_; ++c) {
    695      channels_[c].resize(frame_size);
    696      channel_pointers_[c] = channels_[c].data();
    697      std::fill(channels_[c].begin(), channels_[c].end(), 0.0f);
    698    }
    699  }
    700 
    701  int sample_rate_hz() const { return sample_rate_hz_; }
    702  int num_channels() const { return num_channels_; }
    703  AudioProcessing::Config GetConfig() const { return std::get<2>(GetParam()); }
    704 
    705  float* const* channel_pointers() { return channel_pointers_.data(); }
    706 
    707 private:
    708  const int sample_rate_hz_;
    709  const int num_channels_;
    710  std::vector<std::vector<float>> channels_;
    711  std::vector<float*> channel_pointers_;
    712 };
    713 
    714 TEST_P(ApmInputVolumeControllerParametrizedTest,
    715       EnforceMinInputVolumeAtStartupWithZeroVolume) {
    716  const StreamConfig stream_config(sample_rate_hz(), num_channels());
    717  auto apm =
    718      BuiltinAudioProcessingBuilder(GetConfig()).Build(CreateEnvironment());
    719 
    720  apm->set_stream_analog_level(0);
    721  apm->ProcessStream(channel_pointers(), stream_config, stream_config,
    722                     channel_pointers());
    723  EXPECT_GT(apm->recommended_stream_analog_level(), 0);
    724 }
    725 
    726 TEST_P(ApmInputVolumeControllerParametrizedTest,
    727       EnforceMinInputVolumeAtStartupWithNonZeroVolume) {
    728  const StreamConfig stream_config(sample_rate_hz(), num_channels());
    729  auto apm =
    730      BuiltinAudioProcessingBuilder(GetConfig()).Build(CreateEnvironment());
    731 
    732  constexpr int kStartupVolume = 3;
    733  apm->set_stream_analog_level(kStartupVolume);
    734  apm->ProcessStream(channel_pointers(), stream_config, stream_config,
    735                     channel_pointers());
    736  EXPECT_GT(apm->recommended_stream_analog_level(), kStartupVolume);
    737 }
    738 
    739 TEST_P(ApmInputVolumeControllerParametrizedTest,
    740       EnforceMinInputVolumeAfterManualVolumeAdjustment) {
    741  const auto config = GetConfig();
    742  if (config.gain_controller1.enabled) {
    743    // After a downward manual adjustment, AGC1 slowly converges to the minimum
    744    // input volume.
    745    GTEST_SKIP() << "Does not apply to AGC1";
    746  }
    747  const StreamConfig stream_config(sample_rate_hz(), num_channels());
    748  auto apm =
    749      BuiltinAudioProcessingBuilder(GetConfig()).Build(CreateEnvironment());
    750 
    751  apm->set_stream_analog_level(20);
    752  apm->ProcessStream(channel_pointers(), stream_config, stream_config,
    753                     channel_pointers());
    754  constexpr int kManuallyAdjustedVolume = 3;
    755  apm->set_stream_analog_level(kManuallyAdjustedVolume);
    756  apm->ProcessStream(channel_pointers(), stream_config, stream_config,
    757                     channel_pointers());
    758  EXPECT_GT(apm->recommended_stream_analog_level(), kManuallyAdjustedVolume);
    759 }
    760 
    761 TEST_P(ApmInputVolumeControllerParametrizedTest,
    762       DoNotEnforceMinInputVolumeAtStartupWithHighVolume) {
    763  const StreamConfig stream_config(sample_rate_hz(), num_channels());
    764  auto apm =
    765      BuiltinAudioProcessingBuilder(GetConfig()).Build(CreateEnvironment());
    766 
    767  constexpr int kStartupVolume = 200;
    768  apm->set_stream_analog_level(kStartupVolume);
    769  apm->ProcessStream(channel_pointers(), stream_config, stream_config,
    770                     channel_pointers());
    771  EXPECT_EQ(apm->recommended_stream_analog_level(), kStartupVolume);
    772 }
    773 
    774 TEST_P(ApmInputVolumeControllerParametrizedTest,
    775       DoNotEnforceMinInputVolumeAfterManualVolumeAdjustmentToZero) {
    776  const StreamConfig stream_config(sample_rate_hz(), num_channels());
    777  auto apm =
    778      BuiltinAudioProcessingBuilder(GetConfig()).Build(CreateEnvironment());
    779 
    780  apm->set_stream_analog_level(100);
    781  apm->ProcessStream(channel_pointers(), stream_config, stream_config,
    782                     channel_pointers());
    783  apm->set_stream_analog_level(0);
    784  apm->ProcessStream(channel_pointers(), stream_config, stream_config,
    785                     channel_pointers());
    786  EXPECT_EQ(apm->recommended_stream_analog_level(), 0);
    787 }
    788 
    789 INSTANTIATE_TEST_SUITE_P(
    790    AudioProcessingImplTest,
    791    ApmInputVolumeControllerParametrizedTest,
    792    ::testing::Combine(
    793        ::testing::Values(8000, 16000, 32000, 48000),  // Sample rates.
    794        ::testing::Values(1, 2),                       // Number of channels.
    795        ::testing::Values(
    796            // Full AGC1.
    797            AudioProcessing::Config{
    798                .gain_controller1 = {.enabled = true,
    799                                     .analog_gain_controller =
    800                                         {.enabled = true,
    801                                          .enable_digital_adaptive = true}},
    802                .gain_controller2 = {.enabled = false}},
    803            // Hybrid AGC.
    804            AudioProcessing::Config{
    805                .gain_controller1 = {.enabled = true,
    806                                     .analog_gain_controller =
    807                                         {.enabled = true,
    808                                          .enable_digital_adaptive = false}},
    809                .gain_controller2 = {.enabled = true,
    810                                     .adaptive_digital = {.enabled = true}}})));
    811 
    812 // When the input volume is not emulated and no input volume controller is
    813 // active, the recommended volume must always be the applied volume.
    814 TEST(AudioProcessingImplTest,
    815     RecommendAppliedInputVolumeWithNoAgcWithNoEmulation) {
    816  auto apm = BuiltinAudioProcessingBuilder(
    817                 {.capture_level_adjustment = {.enabled = false},
    818                  .gain_controller1 = {.enabled = false}})
    819                 .Build(CreateEnvironment());
    820 
    821  constexpr int kOneFrame = 1;
    822  EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
    823  EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
    824  EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
    825 }
    826 
    827 // When the input volume is emulated, the recommended volume must always be the
    828 // applied volume and at any time it must not be that set in the input volume
    829 // emulator.
    830 // TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
    831 TEST(AudioProcessingImplTest,
    832     DISABLED_RecommendAppliedInputVolumeWithNoAgcWithEmulation) {
    833  auto apm = BuiltinAudioProcessingBuilder(
    834                 {.capture_level_adjustment = {.enabled = true,
    835                                               .analog_mic_gain_emulation{
    836                                                   .enabled = true,
    837                                                   .initial_level = 255}},
    838                  .gain_controller1 = {.enabled = false}})
    839                 .Build(CreateEnvironment());
    840 
    841  constexpr int kOneFrame = 1;
    842  EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
    843  EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
    844  EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
    845 }
    846 
    847 // Even if there is an enabled input volume controller, when the input volume is
    848 // emulated, the recommended volume is always the applied volume because the
    849 // active controller must only adjust the internally emulated volume and leave
    850 // the externally applied volume unchanged.
    851 // TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
    852 TEST(AudioProcessingImplTest,
    853     DISABLED_RecommendAppliedInputVolumeWithAgcWithEmulation) {
    854  auto apm = BuiltinAudioProcessingBuilder(
    855                 {.capture_level_adjustment = {.enabled = true,
    856                                               .analog_mic_gain_emulation{
    857                                                   .enabled = true}},
    858                  .gain_controller1 = {.enabled = true,
    859                                       .analog_gain_controller{
    860                                           .enabled = true,
    861                                       }}})
    862                 .Build(CreateEnvironment());
    863 
    864  constexpr int kOneFrame = 1;
    865  EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
    866  EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
    867  EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
    868 }
    869 
    870 class Agc2ParametrizedTest
    871    : public ::testing::TestWithParam<AudioProcessing::Config> {};
    872 
    873 TEST_P(Agc2ParametrizedTest, ProcessSucceedsWhenOneAgcEnabled) {
    874  auto apm =
    875      BuiltinAudioProcessingBuilder(GetParam()).Build(CreateEnvironment());
    876  constexpr int kSampleRateHz = 48000;
    877  constexpr int kNumChannels = 1;
    878  std::array<float, kSampleRateHz / 100> buffer;
    879  float* channel_pointers[] = {buffer.data()};
    880  StreamConfig stream_config(kSampleRateHz, kNumChannels);
    881  Random random_generator(2341U);
    882  constexpr int kFramesToProcess = 10;
    883  int volume = 100;
    884  for (int i = 0; i < kFramesToProcess; ++i) {
    885    SCOPED_TRACE(i);
    886    RandomizeSampleVector(&random_generator, buffer);
    887    apm->set_stream_analog_level(volume);
    888    ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
    889                                 channel_pointers),
    890              kNoErr);
    891    volume = apm->recommended_stream_analog_level();
    892  }
    893 }
    894 
    895 TEST_P(Agc2ParametrizedTest,
    896       BitExactWithAndWithoutTransientSuppressionEnabledInConfig) {
    897  const Environment env = CreateEnvironment();
    898  // Enable transient suppression in the config (expect no effect).
    899  auto config = GetParam();
    900  config.transient_suppression.enabled = true;
    901  auto apm = BuiltinAudioProcessingBuilder(config).Build(env);
    902  ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
    903  // Disable transient suppression in the config.
    904  auto config_reference = GetParam();
    905  config_reference.transient_suppression.enabled = false;
    906  auto apm_reference =
    907      BuiltinAudioProcessingBuilder(config_reference).Build(env);
    908  ASSERT_EQ(apm_reference->Initialize(), AudioProcessing::kNoError);
    909 
    910  constexpr int kSampleRateHz = 16000;
    911  constexpr int kNumChannels = 1;
    912  std::array<float, kSampleRateHz / 100> buffer;
    913  std::array<float, kSampleRateHz / 100> buffer_reference;
    914  float* channel_pointers[] = {buffer.data()};
    915  float* channel_pointers_reference[] = {buffer_reference.data()};
    916  StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
    917                             /*num_channels=*/kNumChannels);
    918  Random random_generator(2341U);
    919  constexpr int kFramesToProcessPerConfiguration = 100;
    920  int volume = 100;
    921  int volume_reference = 100;
    922  for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
    923    RandomizeSampleVector(&random_generator, buffer);
    924    std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
    925    apm->set_stream_analog_level(volume);
    926    apm_reference->set_stream_analog_level(volume_reference);
    927    ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
    928                                 channel_pointers),
    929              kNoErr);
    930    ASSERT_EQ(
    931        apm_reference->ProcessStream(channel_pointers_reference, stream_config,
    932                                     stream_config, channel_pointers_reference),
    933        kNoErr);
    934    volume = apm->recommended_stream_analog_level();
    935    volume_reference = apm_reference->recommended_stream_analog_level();
    936    for (int j = 0; j < kSampleRateHz / 100; ++j) {
    937      // Expect no effect from transient suppression.
    938      EXPECT_EQ(buffer[j], buffer_reference[j]);
    939    }
    940  }
    941 }
    942 
    943 INSTANTIATE_TEST_SUITE_P(
    944    AudioProcessingImplTest,
    945    Agc2ParametrizedTest,
    946    ::testing::Values(
    947        // Full AGC1, TS disabled.
    948        AudioProcessing::Config{
    949            .transient_suppression = {.enabled = false},
    950            .gain_controller1 =
    951                {.enabled = true,
    952                 .analog_gain_controller = {.enabled = true,
    953                                            .enable_digital_adaptive = true}},
    954            .gain_controller2 = {.enabled = false}},
    955        // Hybrid AGC, TS disabled.
    956        AudioProcessing::Config{
    957            .transient_suppression = {.enabled = false},
    958            .gain_controller1 =
    959                {.enabled = true,
    960                 .analog_gain_controller = {.enabled = true,
    961                                            .enable_digital_adaptive = false}},
    962            .gain_controller2 = {.enabled = true,
    963                                 .adaptive_digital = {.enabled = true}}},
    964        // Full AGC2, TS disabled.
    965        AudioProcessing::Config{
    966            .transient_suppression = {.enabled = false},
    967            .gain_controller1 =
    968                {.enabled = false,
    969                 .analog_gain_controller = {.enabled = false,
    970                                            .enable_digital_adaptive = false}},
    971            .gain_controller2 = {.enabled = true,
    972                                 .input_volume_controller = {.enabled = true},
    973                                 .adaptive_digital = {.enabled = true}}}));
    974 
    975 }  // namespace webrtc