1 /*
2  *  Copyright (c) 2021 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/agc2/input_volume_stats_reporter.h"
12 
13 #include "absl/strings/string_view.h"
14 #include "rtc_base/strings/string_builder.h"
15 #include "system_wrappers/include/metrics.h"
16 #include "test/gmock.h"
17 
18 namespace webrtc {
19 namespace {
20 
21 using InputVolumeType = InputVolumeStatsReporter::InputVolumeType;
22 
23 constexpr int kFramesIn60Seconds = 6000;
24 
25 constexpr absl::string_view kLabelPrefix = "WebRTC.Audio.Apm.";
26 
27 class InputVolumeStatsReporterTest
28     : public ::testing::TestWithParam<InputVolumeType> {
29  public:
InputVolumeStatsReporterTest()30   InputVolumeStatsReporterTest() { metrics::Reset(); }
31 
32  protected:
InputVolumeType() const33   InputVolumeType InputVolumeType() const { return GetParam(); }
DecreaseRateLabel() const34   std::string DecreaseRateLabel() const {
35     return (rtc::StringBuilder(kLabelPrefix)
36             << VolumeTypeLabel() << "DecreaseRate")
37         .str();
38   }
DecreaseAverageLabel() const39   std::string DecreaseAverageLabel() const {
40     return (rtc::StringBuilder(kLabelPrefix)
41             << VolumeTypeLabel() << "DecreaseAverage")
42         .str();
43   }
IncreaseRateLabel() const44   std::string IncreaseRateLabel() const {
45     return (rtc::StringBuilder(kLabelPrefix)
46             << VolumeTypeLabel() << "IncreaseRate")
47         .str();
48   }
IncreaseAverageLabel() const49   std::string IncreaseAverageLabel() const {
50     return (rtc::StringBuilder(kLabelPrefix)
51             << VolumeTypeLabel() << "IncreaseAverage")
52         .str();
53   }
UpdateRateLabel() const54   std::string UpdateRateLabel() const {
55     return (rtc::StringBuilder(kLabelPrefix)
56             << VolumeTypeLabel() << "UpdateRate")
57         .str();
58   }
UpdateAverageLabel() const59   std::string UpdateAverageLabel() const {
60     return (rtc::StringBuilder(kLabelPrefix)
61             << VolumeTypeLabel() << "UpdateAverage")
62         .str();
63   }
64 
65  private:
VolumeTypeLabel() const66   absl::string_view VolumeTypeLabel() const {
67     switch (InputVolumeType()) {
68       case InputVolumeType::kApplied:
69         return "AppliedInputVolume.";
70       case InputVolumeType::kRecommended:
71         return "RecommendedInputVolume.";
72     }
73   }
74 };
75 
TEST_P(InputVolumeStatsReporterTest,CheckLogVolumeUpdateStatsEmpty)76 TEST_P(InputVolumeStatsReporterTest, CheckLogVolumeUpdateStatsEmpty) {
77   InputVolumeStatsReporter stats_reporter(InputVolumeType());
78   constexpr int kInputVolume = 10;
79   stats_reporter.UpdateStatistics(kInputVolume);
80   // Update almost until the periodic logging and reset.
81   for (int i = 0; i < kFramesIn60Seconds - 2; i += 2) {
82     stats_reporter.UpdateStatistics(kInputVolume + 2);
83     stats_reporter.UpdateStatistics(kInputVolume);
84   }
85   EXPECT_METRIC_THAT(metrics::Samples(UpdateRateLabel()),
86                      ::testing::ElementsAre());
87   EXPECT_METRIC_THAT(metrics::Samples(DecreaseRateLabel()),
88                      ::testing::ElementsAre());
89   EXPECT_METRIC_THAT(metrics::Samples(IncreaseRateLabel()),
90                      ::testing::ElementsAre());
91   EXPECT_METRIC_THAT(metrics::Samples(UpdateAverageLabel()),
92                      ::testing::ElementsAre());
93   EXPECT_METRIC_THAT(metrics::Samples(DecreaseAverageLabel()),
94                      ::testing::ElementsAre());
95   EXPECT_METRIC_THAT(metrics::Samples(IncreaseAverageLabel()),
96                      ::testing::ElementsAre());
97 }
98 
TEST_P(InputVolumeStatsReporterTest,CheckLogVolumeUpdateStatsNotEmpty)99 TEST_P(InputVolumeStatsReporterTest, CheckLogVolumeUpdateStatsNotEmpty) {
100   InputVolumeStatsReporter stats_reporter(InputVolumeType());
101   constexpr int kInputVolume = 10;
102   stats_reporter.UpdateStatistics(kInputVolume);
103   // Update until periodic logging.
104   for (int i = 0; i < kFramesIn60Seconds; i += 2) {
105     stats_reporter.UpdateStatistics(kInputVolume + 2);
106     stats_reporter.UpdateStatistics(kInputVolume);
107   }
108   // Update until periodic logging.
109   for (int i = 0; i < kFramesIn60Seconds; i += 2) {
110     stats_reporter.UpdateStatistics(kInputVolume + 3);
111     stats_reporter.UpdateStatistics(kInputVolume);
112   }
113   EXPECT_METRIC_THAT(
114       metrics::Samples(UpdateRateLabel()),
115       ::testing::ElementsAre(::testing::Pair(kFramesIn60Seconds - 1, 1),
116                              ::testing::Pair(kFramesIn60Seconds, 1)));
117   EXPECT_METRIC_THAT(
118       metrics::Samples(DecreaseRateLabel()),
119       ::testing::ElementsAre(::testing::Pair(kFramesIn60Seconds / 2 - 1, 1),
120                              ::testing::Pair(kFramesIn60Seconds / 2, 1)));
121   EXPECT_METRIC_THAT(
122       metrics::Samples(IncreaseRateLabel()),
123       ::testing::ElementsAre(::testing::Pair(kFramesIn60Seconds / 2, 2)));
124   EXPECT_METRIC_THAT(
125       metrics::Samples(UpdateAverageLabel()),
126       ::testing::ElementsAre(::testing::Pair(2, 1), ::testing::Pair(3, 1)));
127   EXPECT_METRIC_THAT(
128       metrics::Samples(DecreaseAverageLabel()),
129       ::testing::ElementsAre(::testing::Pair(2, 1), ::testing::Pair(3, 1)));
130   EXPECT_METRIC_THAT(
131       metrics::Samples(IncreaseAverageLabel()),
132       ::testing::ElementsAre(::testing::Pair(2, 1), ::testing::Pair(3, 1)));
133 }
134 }  // namespace
135 
TEST_P(InputVolumeStatsReporterTest,CheckVolumeUpdateStatsForEmptyStats)136 TEST_P(InputVolumeStatsReporterTest, CheckVolumeUpdateStatsForEmptyStats) {
137   InputVolumeStatsReporter stats_reporter(InputVolumeType());
138   const auto& update_stats = stats_reporter.volume_update_stats();
139   EXPECT_EQ(update_stats.num_decreases, 0);
140   EXPECT_EQ(update_stats.sum_decreases, 0);
141   EXPECT_EQ(update_stats.num_increases, 0);
142   EXPECT_EQ(update_stats.sum_increases, 0);
143 }
144 
TEST_P(InputVolumeStatsReporterTest,CheckVolumeUpdateStatsAfterNoVolumeChange)145 TEST_P(InputVolumeStatsReporterTest,
146        CheckVolumeUpdateStatsAfterNoVolumeChange) {
147   constexpr int kInputVolume = 10;
148   InputVolumeStatsReporter stats_reporter(InputVolumeType());
149   stats_reporter.UpdateStatistics(kInputVolume);
150   stats_reporter.UpdateStatistics(kInputVolume);
151   stats_reporter.UpdateStatistics(kInputVolume);
152   const auto& update_stats = stats_reporter.volume_update_stats();
153   EXPECT_EQ(update_stats.num_decreases, 0);
154   EXPECT_EQ(update_stats.sum_decreases, 0);
155   EXPECT_EQ(update_stats.num_increases, 0);
156   EXPECT_EQ(update_stats.sum_increases, 0);
157 }
158 
TEST_P(InputVolumeStatsReporterTest,CheckVolumeUpdateStatsAfterVolumeIncrease)159 TEST_P(InputVolumeStatsReporterTest,
160        CheckVolumeUpdateStatsAfterVolumeIncrease) {
161   constexpr int kInputVolume = 10;
162   InputVolumeStatsReporter stats_reporter(InputVolumeType());
163   stats_reporter.UpdateStatistics(kInputVolume);
164   stats_reporter.UpdateStatistics(kInputVolume + 4);
165   stats_reporter.UpdateStatistics(kInputVolume + 5);
166   const auto& update_stats = stats_reporter.volume_update_stats();
167   EXPECT_EQ(update_stats.num_decreases, 0);
168   EXPECT_EQ(update_stats.sum_decreases, 0);
169   EXPECT_EQ(update_stats.num_increases, 2);
170   EXPECT_EQ(update_stats.sum_increases, 5);
171 }
172 
TEST_P(InputVolumeStatsReporterTest,CheckVolumeUpdateStatsAfterVolumeDecrease)173 TEST_P(InputVolumeStatsReporterTest,
174        CheckVolumeUpdateStatsAfterVolumeDecrease) {
175   constexpr int kInputVolume = 10;
176   InputVolumeStatsReporter stats_reporter(InputVolumeType());
177   stats_reporter.UpdateStatistics(kInputVolume);
178   stats_reporter.UpdateStatistics(kInputVolume - 4);
179   stats_reporter.UpdateStatistics(kInputVolume - 5);
180   const auto& stats_update = stats_reporter.volume_update_stats();
181   EXPECT_EQ(stats_update.num_decreases, 2);
182   EXPECT_EQ(stats_update.sum_decreases, 5);
183   EXPECT_EQ(stats_update.num_increases, 0);
184   EXPECT_EQ(stats_update.sum_increases, 0);
185 }
186 
TEST_P(InputVolumeStatsReporterTest,CheckVolumeUpdateStatsAfterReset)187 TEST_P(InputVolumeStatsReporterTest, CheckVolumeUpdateStatsAfterReset) {
188   InputVolumeStatsReporter stats_reporter(InputVolumeType());
189   constexpr int kInputVolume = 10;
190   stats_reporter.UpdateStatistics(kInputVolume);
191   // Update until the periodic reset.
192   for (int i = 0; i < kFramesIn60Seconds - 2; i += 2) {
193     stats_reporter.UpdateStatistics(kInputVolume + 2);
194     stats_reporter.UpdateStatistics(kInputVolume);
195   }
196   const auto& stats_before_reset = stats_reporter.volume_update_stats();
197   EXPECT_EQ(stats_before_reset.num_decreases, kFramesIn60Seconds / 2 - 1);
198   EXPECT_EQ(stats_before_reset.sum_decreases, kFramesIn60Seconds - 2);
199   EXPECT_EQ(stats_before_reset.num_increases, kFramesIn60Seconds / 2 - 1);
200   EXPECT_EQ(stats_before_reset.sum_increases, kFramesIn60Seconds - 2);
201   stats_reporter.UpdateStatistics(kInputVolume + 2);
202   const auto& stats_during_reset = stats_reporter.volume_update_stats();
203   EXPECT_EQ(stats_during_reset.num_decreases, 0);
204   EXPECT_EQ(stats_during_reset.sum_decreases, 0);
205   EXPECT_EQ(stats_during_reset.num_increases, 0);
206   EXPECT_EQ(stats_during_reset.sum_increases, 0);
207   stats_reporter.UpdateStatistics(kInputVolume);
208   stats_reporter.UpdateStatistics(kInputVolume + 3);
209   const auto& stats_after_reset = stats_reporter.volume_update_stats();
210   EXPECT_EQ(stats_after_reset.num_decreases, 1);
211   EXPECT_EQ(stats_after_reset.sum_decreases, 2);
212   EXPECT_EQ(stats_after_reset.num_increases, 1);
213   EXPECT_EQ(stats_after_reset.sum_increases, 3);
214 }
215 
216 INSTANTIATE_TEST_SUITE_P(,
217                          InputVolumeStatsReporterTest,
218                          ::testing::Values(InputVolumeType::kApplied,
219                                            InputVolumeType::kRecommended));
220 
221 }  // namespace webrtc
222