/* * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_processing/agc2/input_volume_stats_reporter.h" #include "absl/strings/string_view.h" #include "rtc_base/strings/string_builder.h" #include "system_wrappers/include/metrics.h" #include "test/gmock.h" namespace webrtc { namespace { using InputVolumeType = InputVolumeStatsReporter::InputVolumeType; constexpr int kFramesIn60Seconds = 6000; constexpr absl::string_view kLabelPrefix = "WebRTC.Audio.Apm."; class InputVolumeStatsReporterTest : public ::testing::TestWithParam { public: InputVolumeStatsReporterTest() { metrics::Reset(); } protected: InputVolumeType InputVolumeType() const { return GetParam(); } std::string VolumeLabel() const { return (rtc::StringBuilder(kLabelPrefix) << VolumeTypeLabel() << "OnChange") .str(); } std::string DecreaseRateLabel() const { return (rtc::StringBuilder(kLabelPrefix) << VolumeTypeLabel() << "DecreaseRate") .str(); } std::string DecreaseAverageLabel() const { return (rtc::StringBuilder(kLabelPrefix) << VolumeTypeLabel() << "DecreaseAverage") .str(); } std::string IncreaseRateLabel() const { return (rtc::StringBuilder(kLabelPrefix) << VolumeTypeLabel() << "IncreaseRate") .str(); } std::string IncreaseAverageLabel() const { return (rtc::StringBuilder(kLabelPrefix) << VolumeTypeLabel() << "IncreaseAverage") .str(); } std::string UpdateRateLabel() const { return (rtc::StringBuilder(kLabelPrefix) << VolumeTypeLabel() << "UpdateRate") .str(); } std::string UpdateAverageLabel() const { return (rtc::StringBuilder(kLabelPrefix) << VolumeTypeLabel() << "UpdateAverage") .str(); } private: absl::string_view VolumeTypeLabel() const { switch (InputVolumeType()) { case InputVolumeType::kApplied: return "AppliedInputVolume."; case InputVolumeType::kRecommended: return "RecommendedInputVolume."; } } }; TEST_P(InputVolumeStatsReporterTest, CheckVolumeOnChangeIsEmpty) { InputVolumeStatsReporter stats_reporter(InputVolumeType()); stats_reporter.UpdateStatistics(10); EXPECT_METRIC_THAT(metrics::Samples(VolumeLabel()), ::testing::ElementsAre()); } TEST_P(InputVolumeStatsReporterTest, CheckRateAverageStatsEmpty) { InputVolumeStatsReporter stats_reporter(InputVolumeType()); constexpr int kInputVolume = 10; stats_reporter.UpdateStatistics(kInputVolume); // Update almost until the periodic logging and reset. for (int i = 0; i < kFramesIn60Seconds - 2; i += 2) { stats_reporter.UpdateStatistics(kInputVolume + 2); stats_reporter.UpdateStatistics(kInputVolume); } EXPECT_METRIC_THAT(metrics::Samples(UpdateRateLabel()), ::testing::ElementsAre()); EXPECT_METRIC_THAT(metrics::Samples(DecreaseRateLabel()), ::testing::ElementsAre()); EXPECT_METRIC_THAT(metrics::Samples(IncreaseRateLabel()), ::testing::ElementsAre()); EXPECT_METRIC_THAT(metrics::Samples(UpdateAverageLabel()), ::testing::ElementsAre()); EXPECT_METRIC_THAT(metrics::Samples(DecreaseAverageLabel()), ::testing::ElementsAre()); EXPECT_METRIC_THAT(metrics::Samples(IncreaseAverageLabel()), ::testing::ElementsAre()); } TEST_P(InputVolumeStatsReporterTest, CheckSamples) { InputVolumeStatsReporter stats_reporter(InputVolumeType()); constexpr int kInputVolume1 = 10; stats_reporter.UpdateStatistics(kInputVolume1); // Update until periodic logging. constexpr int kInputVolume2 = 12; for (int i = 0; i < kFramesIn60Seconds; i += 2) { stats_reporter.UpdateStatistics(kInputVolume2); stats_reporter.UpdateStatistics(kInputVolume1); } // Update until periodic logging. constexpr int kInputVolume3 = 13; for (int i = 0; i < kFramesIn60Seconds; i += 2) { stats_reporter.UpdateStatistics(kInputVolume3); stats_reporter.UpdateStatistics(kInputVolume1); } // Check volume changes stats. EXPECT_METRIC_THAT( metrics::Samples(VolumeLabel()), ::testing::ElementsAre( ::testing::Pair(kInputVolume1, kFramesIn60Seconds), ::testing::Pair(kInputVolume2, kFramesIn60Seconds / 2), ::testing::Pair(kInputVolume3, kFramesIn60Seconds / 2))); // Check volume change rate stats. EXPECT_METRIC_THAT( metrics::Samples(UpdateRateLabel()), ::testing::ElementsAre(::testing::Pair(kFramesIn60Seconds - 1, 1), ::testing::Pair(kFramesIn60Seconds, 1))); EXPECT_METRIC_THAT( metrics::Samples(DecreaseRateLabel()), ::testing::ElementsAre(::testing::Pair(kFramesIn60Seconds / 2 - 1, 1), ::testing::Pair(kFramesIn60Seconds / 2, 1))); EXPECT_METRIC_THAT( metrics::Samples(IncreaseRateLabel()), ::testing::ElementsAre(::testing::Pair(kFramesIn60Seconds / 2, 2))); // Check volume change average stats. EXPECT_METRIC_THAT( metrics::Samples(UpdateAverageLabel()), ::testing::ElementsAre(::testing::Pair(2, 1), ::testing::Pair(3, 1))); EXPECT_METRIC_THAT( metrics::Samples(DecreaseAverageLabel()), ::testing::ElementsAre(::testing::Pair(2, 1), ::testing::Pair(3, 1))); EXPECT_METRIC_THAT( metrics::Samples(IncreaseAverageLabel()), ::testing::ElementsAre(::testing::Pair(2, 1), ::testing::Pair(3, 1))); } } // namespace TEST_P(InputVolumeStatsReporterTest, CheckVolumeUpdateStatsForEmptyStats) { InputVolumeStatsReporter stats_reporter(InputVolumeType()); const auto& update_stats = stats_reporter.volume_update_stats(); EXPECT_EQ(update_stats.num_decreases, 0); EXPECT_EQ(update_stats.sum_decreases, 0); EXPECT_EQ(update_stats.num_increases, 0); EXPECT_EQ(update_stats.sum_increases, 0); } TEST_P(InputVolumeStatsReporterTest, CheckVolumeUpdateStatsAfterNoVolumeChange) { constexpr int kInputVolume = 10; InputVolumeStatsReporter stats_reporter(InputVolumeType()); stats_reporter.UpdateStatistics(kInputVolume); stats_reporter.UpdateStatistics(kInputVolume); stats_reporter.UpdateStatistics(kInputVolume); const auto& update_stats = stats_reporter.volume_update_stats(); EXPECT_EQ(update_stats.num_decreases, 0); EXPECT_EQ(update_stats.sum_decreases, 0); EXPECT_EQ(update_stats.num_increases, 0); EXPECT_EQ(update_stats.sum_increases, 0); } TEST_P(InputVolumeStatsReporterTest, CheckVolumeUpdateStatsAfterVolumeIncrease) { constexpr int kInputVolume = 10; InputVolumeStatsReporter stats_reporter(InputVolumeType()); stats_reporter.UpdateStatistics(kInputVolume); stats_reporter.UpdateStatistics(kInputVolume + 4); stats_reporter.UpdateStatistics(kInputVolume + 5); const auto& update_stats = stats_reporter.volume_update_stats(); EXPECT_EQ(update_stats.num_decreases, 0); EXPECT_EQ(update_stats.sum_decreases, 0); EXPECT_EQ(update_stats.num_increases, 2); EXPECT_EQ(update_stats.sum_increases, 5); } TEST_P(InputVolumeStatsReporterTest, CheckVolumeUpdateStatsAfterVolumeDecrease) { constexpr int kInputVolume = 10; InputVolumeStatsReporter stats_reporter(InputVolumeType()); stats_reporter.UpdateStatistics(kInputVolume); stats_reporter.UpdateStatistics(kInputVolume - 4); stats_reporter.UpdateStatistics(kInputVolume - 5); const auto& stats_update = stats_reporter.volume_update_stats(); EXPECT_EQ(stats_update.num_decreases, 2); EXPECT_EQ(stats_update.sum_decreases, 5); EXPECT_EQ(stats_update.num_increases, 0); EXPECT_EQ(stats_update.sum_increases, 0); } TEST_P(InputVolumeStatsReporterTest, CheckVolumeUpdateStatsAfterReset) { InputVolumeStatsReporter stats_reporter(InputVolumeType()); constexpr int kInputVolume = 10; stats_reporter.UpdateStatistics(kInputVolume); // Update until the periodic reset. for (int i = 0; i < kFramesIn60Seconds - 2; i += 2) { stats_reporter.UpdateStatistics(kInputVolume + 2); stats_reporter.UpdateStatistics(kInputVolume); } const auto& stats_before_reset = stats_reporter.volume_update_stats(); EXPECT_EQ(stats_before_reset.num_decreases, kFramesIn60Seconds / 2 - 1); EXPECT_EQ(stats_before_reset.sum_decreases, kFramesIn60Seconds - 2); EXPECT_EQ(stats_before_reset.num_increases, kFramesIn60Seconds / 2 - 1); EXPECT_EQ(stats_before_reset.sum_increases, kFramesIn60Seconds - 2); stats_reporter.UpdateStatistics(kInputVolume + 2); const auto& stats_during_reset = stats_reporter.volume_update_stats(); EXPECT_EQ(stats_during_reset.num_decreases, 0); EXPECT_EQ(stats_during_reset.sum_decreases, 0); EXPECT_EQ(stats_during_reset.num_increases, 0); EXPECT_EQ(stats_during_reset.sum_increases, 0); stats_reporter.UpdateStatistics(kInputVolume); stats_reporter.UpdateStatistics(kInputVolume + 3); const auto& stats_after_reset = stats_reporter.volume_update_stats(); EXPECT_EQ(stats_after_reset.num_decreases, 1); EXPECT_EQ(stats_after_reset.sum_decreases, 2); EXPECT_EQ(stats_after_reset.num_increases, 1); EXPECT_EQ(stats_after_reset.sum_increases, 3); } INSTANTIATE_TEST_SUITE_P(, InputVolumeStatsReporterTest, ::testing::Values(InputVolumeType::kApplied, InputVolumeType::kRecommended)); } // namespace webrtc