diff options
author | Erwin Jansen <jansene@google.com> | 2021-06-30 07:29:26 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-06-30 07:29:26 +0000 |
commit | 059cdc5996938f5f6b5343b6c969c12098275587 (patch) | |
tree | 6eacaffe4bebf8e00c290c1e1839e084b0c52e88 /modules/audio_processing/agc/agc_manager_direct_unittest.cc | |
parent | 97e54a7e73c7b24e464ef06ef3c3b3716f21bb15 (diff) | |
parent | 16be34ae72cdb525c88c2b31b21b976f35fe36d8 (diff) | |
download | webrtc-059cdc5996938f5f6b5343b6c969c12098275587.tar.gz |
Merge "Merge upstream-master and enable ARM64" into emu-master-devemu-31-stable-releaseemu-31-release
Diffstat (limited to 'modules/audio_processing/agc/agc_manager_direct_unittest.cc')
-rw-r--r-- | modules/audio_processing/agc/agc_manager_direct_unittest.cc | 256 |
1 files changed, 239 insertions, 17 deletions
diff --git a/modules/audio_processing/agc/agc_manager_direct_unittest.cc b/modules/audio_processing/agc/agc_manager_direct_unittest.cc index 1954ed4b21..bb284f9abc 100644 --- a/modules/audio_processing/agc/agc_manager_direct_unittest.cc +++ b/modules/audio_processing/agc/agc_manager_direct_unittest.cc @@ -26,13 +26,19 @@ using ::testing::SetArgPointee; namespace webrtc { namespace { -const int kSampleRateHz = 32000; -const int kNumChannels = 1; -const int kSamplesPerChannel = kSampleRateHz / 100; -const int kInitialVolume = 128; +constexpr int kSampleRateHz = 32000; +constexpr int kNumChannels = 1; +constexpr int kSamplesPerChannel = kSampleRateHz / 100; +constexpr int kInitialVolume = 128; constexpr int kClippedMin = 165; // Arbitrary, but different from the default. -const float kAboveClippedThreshold = 0.2f; -const int kMinMicLevel = 12; +constexpr float kAboveClippedThreshold = 0.2f; +constexpr int kMinMicLevel = 12; +constexpr int kClippedLevelStep = 15; +constexpr float kClippedRatioThreshold = 0.1f; +constexpr int kClippedWaitFrames = 300; + +using ClippingPredictorConfig = AudioProcessing::Config::GainController1:: + AnalogGainController::ClippingPredictor; class MockGainControl : public GainControl { public: @@ -57,10 +63,53 @@ class MockGainControl : public GainControl { }; std::unique_ptr<AgcManagerDirect> CreateAgcManagerDirect( - int startup_min_level) { + int startup_min_level, + int clipped_level_step, + float clipped_ratio_threshold, + int clipped_wait_frames) { return std::make_unique<AgcManagerDirect>( /*num_capture_channels=*/1, startup_min_level, kClippedMin, - /*disable_digital_adaptive=*/true, kSampleRateHz); + /*disable_digital_adaptive=*/true, kSampleRateHz, clipped_level_step, + clipped_ratio_threshold, clipped_wait_frames, ClippingPredictorConfig()); +} + +std::unique_ptr<AgcManagerDirect> CreateAgcManagerDirect( + int startup_min_level, + int clipped_level_step, + float clipped_ratio_threshold, + int clipped_wait_frames, + const ClippingPredictorConfig& clipping_cfg) { + return std::make_unique<AgcManagerDirect>( + /*num_capture_channels=*/1, startup_min_level, kClippedMin, + /*disable_digital_adaptive=*/true, kSampleRateHz, clipped_level_step, + clipped_ratio_threshold, clipped_wait_frames, clipping_cfg); +} + +void CallPreProcessAudioBuffer(int num_calls, + float peak_ratio, + AgcManagerDirect& manager) { + RTC_DCHECK_GE(1.f, peak_ratio); + AudioBuffer audio_buffer(kSampleRateHz, 1, kSampleRateHz, 1, kSampleRateHz, + 1); + const int num_channels = audio_buffer.num_channels(); + const int num_frames = audio_buffer.num_frames(); + for (int ch = 0; ch < num_channels; ++ch) { + for (int i = 0; i < num_frames; i += 2) { + audio_buffer.channels()[ch][i] = peak_ratio * 32767.f; + audio_buffer.channels()[ch][i + 1] = 0.0f; + } + } + for (int n = 0; n < num_calls / 2; ++n) { + manager.AnalyzePreProcess(&audio_buffer); + } + for (int ch = 0; ch < num_channels; ++ch) { + for (int i = 0; i < num_frames; ++i) { + audio_buffer.channels()[ch][i] = peak_ratio * 32767.f; + } + } + for (int n = 0; n < num_calls - num_calls / 2; ++n) { + manager.AnalyzePreProcess(&audio_buffer); + } } } // namespace @@ -69,7 +118,14 @@ class AgcManagerDirectTest : public ::testing::Test { protected: AgcManagerDirectTest() : agc_(new MockAgc), - manager_(agc_, kInitialVolume, kClippedMin, kSampleRateHz), + manager_(agc_, + kInitialVolume, + kClippedMin, + kSampleRateHz, + kClippedLevelStep, + kClippedRatioThreshold, + kClippedWaitFrames, + ClippingPredictorConfig()), audio(kNumChannels), audio_data(kNumChannels * kSamplesPerChannel, 0.f) { ExpectInitialize(); @@ -124,12 +180,32 @@ class AgcManagerDirectTest : public ::testing::Test { audio[ch][k] = 32767.f; } } - for (int i = 0; i < num_calls; ++i) { manager_.AnalyzePreProcess(audio.data(), kSamplesPerChannel); } } + void CallPreProcForChangingAudio(int num_calls, float peak_ratio) { + RTC_DCHECK_GE(1.f, peak_ratio); + std::fill(audio_data.begin(), audio_data.end(), 0.f); + for (size_t ch = 0; ch < kNumChannels; ++ch) { + for (size_t k = 0; k < kSamplesPerChannel; k += 2) { + audio[ch][k] = peak_ratio * 32767.f; + } + } + for (int i = 0; i < num_calls / 2; ++i) { + manager_.AnalyzePreProcess(audio.data(), kSamplesPerChannel); + } + for (size_t ch = 0; ch < kNumChannels; ++ch) { + for (size_t k = 0; k < kSamplesPerChannel; ++k) { + audio[ch][k] = peak_ratio * 32767.f; + } + } + for (int i = 0; i < num_calls - num_calls / 2; ++i) { + manager_.AnalyzePreProcess(audio.data(), kSamplesPerChannel); + } + } + MockAgc* agc_; MockGainControl gctrl_; AgcManagerDirect manager_; @@ -696,6 +772,25 @@ TEST_F(AgcManagerDirectTest, TakesNoActionOnZeroMicVolume) { EXPECT_EQ(0, manager_.stream_analog_level()); } +TEST_F(AgcManagerDirectTest, ClippingDetectionLowersVolume) { + SetVolumeAndProcess(255); + EXPECT_EQ(255, manager_.stream_analog_level()); + CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/0.99f); + EXPECT_EQ(255, manager_.stream_analog_level()); + CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/1.0f); + EXPECT_EQ(240, manager_.stream_analog_level()); +} + +TEST_F(AgcManagerDirectTest, DisabledClippingPredictorDoesNotLowerVolume) { + SetVolumeAndProcess(255); + EXPECT_FALSE(manager_.clipping_predictor_enabled()); + EXPECT_EQ(255, manager_.stream_analog_level()); + CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/0.99f); + EXPECT_EQ(255, manager_.stream_analog_level()); + CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/0.99f); + EXPECT_EQ(255, manager_.stream_analog_level()); +} + TEST(AgcManagerDirectStandaloneTest, DisableDigitalDisablesDigital) { auto agc = std::unique_ptr<Agc>(new ::testing::NiceMock<MockAgc>()); MockGainControl gctrl; @@ -705,14 +800,16 @@ TEST(AgcManagerDirectStandaloneTest, DisableDigitalDisablesDigital) { EXPECT_CALL(gctrl, enable_limiter(false)); std::unique_ptr<AgcManagerDirect> manager = - CreateAgcManagerDirect(kInitialVolume); + CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames); manager->Initialize(); manager->SetupDigitalGainControl(&gctrl); } TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperiment) { std::unique_ptr<AgcManagerDirect> manager = - CreateAgcManagerDirect(kInitialVolume); + CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); } @@ -721,7 +818,8 @@ TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperimentDisabled) { test::ScopedFieldTrials field_trial( "WebRTC-Audio-AgcMinMicLevelExperiment/Disabled/"); std::unique_ptr<AgcManagerDirect> manager = - CreateAgcManagerDirect(kInitialVolume); + CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); } @@ -732,7 +830,8 @@ TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperimentOutOfRangeAbove) { test::ScopedFieldTrials field_trial( "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-256/"); std::unique_ptr<AgcManagerDirect> manager = - CreateAgcManagerDirect(kInitialVolume); + CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); } @@ -743,7 +842,8 @@ TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperimentOutOfRangeBelow) { test::ScopedFieldTrials field_trial( "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled--1/"); std::unique_ptr<AgcManagerDirect> manager = - CreateAgcManagerDirect(kInitialVolume); + CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); } @@ -755,7 +855,8 @@ TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperimentEnabled50) { test::ScopedFieldTrials field_trial( "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-50/"); std::unique_ptr<AgcManagerDirect> manager = - CreateAgcManagerDirect(kInitialVolume); + CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), 50); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), kInitialVolume); } @@ -768,9 +869,130 @@ TEST(AgcManagerDirectStandaloneTest, test::ScopedFieldTrials field_trial( "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-50/"); std::unique_ptr<AgcManagerDirect> manager = - CreateAgcManagerDirect(/*startup_min_level=*/30); + CreateAgcManagerDirect(/*startup_min_level=*/30, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames); EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), 50); EXPECT_EQ(manager->channel_agcs_[0]->startup_min_level(), 50); } +// TODO(bugs.webrtc.org/12774): Test the bahavior of `clipped_level_step`. +// TODO(bugs.webrtc.org/12774): Test the bahavior of `clipped_ratio_threshold`. +// TODO(bugs.webrtc.org/12774): Test the bahavior of `clipped_wait_frames`. +// Verifies that configurable clipping parameters are initialized as intended. +TEST(AgcManagerDirectStandaloneTest, ClippingParametersVerified) { + std::unique_ptr<AgcManagerDirect> manager = + CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames); + manager->Initialize(); + EXPECT_EQ(manager->clipped_level_step_, kClippedLevelStep); + EXPECT_EQ(manager->clipped_ratio_threshold_, kClippedRatioThreshold); + EXPECT_EQ(manager->clipped_wait_frames_, kClippedWaitFrames); + std::unique_ptr<AgcManagerDirect> manager_custom = + CreateAgcManagerDirect(kInitialVolume, + /*clipped_level_step=*/10, + /*clipped_ratio_threshold=*/0.2f, + /*clipped_wait_frames=*/50); + manager_custom->Initialize(); + EXPECT_EQ(manager_custom->clipped_level_step_, 10); + EXPECT_EQ(manager_custom->clipped_ratio_threshold_, 0.2f); + EXPECT_EQ(manager_custom->clipped_wait_frames_, 50); +} + +TEST(AgcManagerDirectStandaloneTest, + DisableClippingPredictorDisablesClippingPredictor) { + ClippingPredictorConfig default_config; + EXPECT_FALSE(default_config.enabled); + std::unique_ptr<AgcManagerDirect> manager = CreateAgcManagerDirect( + kInitialVolume, kClippedLevelStep, kClippedRatioThreshold, + kClippedWaitFrames, default_config); + manager->Initialize(); + EXPECT_FALSE(manager->clipping_predictor_enabled()); + EXPECT_FALSE(manager->use_clipping_predictor_step()); +} + +TEST(AgcManagerDirectStandaloneTest, ClippingPredictorDisabledByDefault) { + constexpr ClippingPredictorConfig kDefaultConfig; + EXPECT_FALSE(kDefaultConfig.enabled); +} + +TEST(AgcManagerDirectStandaloneTest, + EnableClippingPredictorEnablesClippingPredictor) { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + ClippingPredictorConfig config; + config.enabled = true; + config.use_predicted_step = true; + std::unique_ptr<AgcManagerDirect> manager = CreateAgcManagerDirect( + kInitialVolume, kClippedLevelStep, kClippedRatioThreshold, + kClippedWaitFrames, config); + manager->Initialize(); + EXPECT_TRUE(manager->clipping_predictor_enabled()); + EXPECT_TRUE(manager->use_clipping_predictor_step()); +} + +TEST(AgcManagerDirectStandaloneTest, + DisableClippingPredictorDoesNotLowerVolume) { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + constexpr ClippingPredictorConfig kConfig{/*enabled=*/false}; + AgcManagerDirect manager(new ::testing::NiceMock<MockAgc>(), kInitialVolume, + kClippedMin, kSampleRateHz, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames, kConfig); + manager.Initialize(); + manager.set_stream_analog_level(/*level=*/255); + EXPECT_FALSE(manager.clipping_predictor_enabled()); + EXPECT_FALSE(manager.use_clipping_predictor_step()); + EXPECT_EQ(manager.stream_analog_level(), 255); + manager.Process(nullptr); + CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, manager); + EXPECT_EQ(manager.stream_analog_level(), 255); + CallPreProcessAudioBuffer(/*num_calls=*/300, /*peak_ratio=*/0.99f, manager); + EXPECT_EQ(manager.stream_analog_level(), 255); + CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, manager); + EXPECT_EQ(manager.stream_analog_level(), 255); +} + +TEST(AgcManagerDirectStandaloneTest, + EnableClippingPredictorWithUnusedPredictedStepDoesNotLowerVolume) { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + ClippingPredictorConfig config; + config.enabled = true; + config.use_predicted_step = false; + AgcManagerDirect manager(new ::testing::NiceMock<MockAgc>(), kInitialVolume, + kClippedMin, kSampleRateHz, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames, config); + manager.Initialize(); + manager.set_stream_analog_level(/*level=*/255); + EXPECT_TRUE(manager.clipping_predictor_enabled()); + EXPECT_FALSE(manager.use_clipping_predictor_step()); + EXPECT_EQ(manager.stream_analog_level(), 255); + manager.Process(nullptr); + CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, manager); + EXPECT_EQ(manager.stream_analog_level(), 255); + CallPreProcessAudioBuffer(/*num_calls=*/300, /*peak_ratio=*/0.99f, manager); + EXPECT_EQ(manager.stream_analog_level(), 255); + CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, manager); + EXPECT_EQ(manager.stream_analog_level(), 255); +} + +TEST(AgcManagerDirectStandaloneTest, EnableClippingPredictorLowersVolume) { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + ClippingPredictorConfig config; + config.enabled = true; + config.use_predicted_step = true; + AgcManagerDirect manager(new ::testing::NiceMock<MockAgc>(), kInitialVolume, + kClippedMin, kSampleRateHz, kClippedLevelStep, + kClippedRatioThreshold, kClippedWaitFrames, config); + manager.Initialize(); + manager.set_stream_analog_level(/*level=*/255); + EXPECT_TRUE(manager.clipping_predictor_enabled()); + EXPECT_TRUE(manager.use_clipping_predictor_step()); + EXPECT_EQ(manager.stream_analog_level(), 255); + manager.Process(nullptr); + CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, manager); + EXPECT_EQ(manager.stream_analog_level(), 240); + CallPreProcessAudioBuffer(/*num_calls=*/300, /*peak_ratio=*/0.99f, manager); + EXPECT_EQ(manager.stream_analog_level(), 240); + CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, manager); + EXPECT_EQ(manager.stream_analog_level(), 225); +} + } // namespace webrtc |