• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cmath>
14 
15 #include "absl/strings/string_view.h"
16 #include "rtc_base/logging.h"
17 #include "rtc_base/numerics/safe_minmax.h"
18 #include "rtc_base/strings/string_builder.h"
19 #include "system_wrappers/include/metrics.h"
20 
21 namespace webrtc {
22 namespace {
23 
24 using InputVolumeType = InputVolumeStatsReporter::InputVolumeType;
25 
26 constexpr int kFramesIn60Seconds = 6000;
27 constexpr int kMinInputVolume = 0;
28 constexpr int kMaxInputVolume = 255;
29 constexpr int kMaxUpdate = kMaxInputVolume - kMinInputVolume;
30 
ComputeAverageUpdate(int sum_updates,int num_updates)31 int ComputeAverageUpdate(int sum_updates, int num_updates) {
32   RTC_DCHECK_GE(sum_updates, 0);
33   RTC_DCHECK_LE(sum_updates, kMaxUpdate * kFramesIn60Seconds);
34   RTC_DCHECK_GE(num_updates, 0);
35   RTC_DCHECK_LE(num_updates, kFramesIn60Seconds);
36   if (num_updates == 0) {
37     return 0;
38   }
39   return std::round(static_cast<float>(sum_updates) /
40                     static_cast<float>(num_updates));
41 }
42 
MetricNamePrefix(InputVolumeType input_volume_type)43 constexpr absl::string_view MetricNamePrefix(
44     InputVolumeType input_volume_type) {
45   switch (input_volume_type) {
46     case InputVolumeType::kApplied:
47       return "WebRTC.Audio.Apm.AppliedInputVolume.";
48     case InputVolumeType::kRecommended:
49       return "WebRTC.Audio.Apm.RecommendedInputVolume.";
50   }
51 }
52 
CreateRateHistogram(InputVolumeType input_volume_type,absl::string_view name)53 metrics::Histogram* CreateRateHistogram(InputVolumeType input_volume_type,
54                                         absl::string_view name) {
55   char buffer[64];
56   rtc::SimpleStringBuilder builder(buffer);
57   builder << MetricNamePrefix(input_volume_type) << name;
58   return metrics::HistogramFactoryGetCountsLinear(/*name=*/builder.str(),
59                                                   /*min=*/1,
60                                                   /*max=*/kFramesIn60Seconds,
61                                                   /*bucket_count=*/50);
62 }
63 
CreateAverageHistogram(InputVolumeType input_volume_type,absl::string_view name)64 metrics::Histogram* CreateAverageHistogram(InputVolumeType input_volume_type,
65                                            absl::string_view name) {
66   char buffer[64];
67   rtc::SimpleStringBuilder builder(buffer);
68   builder << MetricNamePrefix(input_volume_type) << name;
69   return metrics::HistogramFactoryGetCountsLinear(/*name=*/builder.str(),
70                                                   /*min=*/1,
71                                                   /*max=*/kMaxUpdate,
72                                                   /*bucket_count=*/50);
73 }
74 
75 }  // namespace
76 
InputVolumeStatsReporter(InputVolumeType type)77 InputVolumeStatsReporter::InputVolumeStatsReporter(InputVolumeType type)
78     : histograms_(
79           {.decrease_rate = CreateRateHistogram(type, "DecreaseRate"),
80            .decrease_average = CreateAverageHistogram(type, "DecreaseAverage"),
81            .increase_rate = CreateRateHistogram(type, "IncreaseRate"),
82            .increase_average = CreateAverageHistogram(type, "IncreaseAverage"),
83            .update_rate = CreateRateHistogram(type, "UpdateRate"),
84            .update_average = CreateAverageHistogram(type, "UpdateAverage")}),
85       cannot_log_stats_(!histograms_.AllPointersSet()) {
86   if (cannot_log_stats_) {
87     RTC_LOG(LS_WARNING) << "Will not log any `" << MetricNamePrefix(type)
88                         << "*` histogram stats.";
89   }
90 }
91 
92 InputVolumeStatsReporter::~InputVolumeStatsReporter() = default;
93 
UpdateStatistics(int input_volume)94 void InputVolumeStatsReporter::UpdateStatistics(int input_volume) {
95   if (cannot_log_stats_) {
96     // Since the stats cannot be logged, do not bother updating them.
97     return;
98   }
99 
100   RTC_DCHECK_GE(input_volume, kMinInputVolume);
101   RTC_DCHECK_LE(input_volume, kMaxInputVolume);
102   if (previous_input_volume_.has_value() &&
103       input_volume != previous_input_volume_.value()) {
104     const int volume_change = input_volume - previous_input_volume_.value();
105     if (volume_change < 0) {
106       ++volume_update_stats_.num_decreases;
107       volume_update_stats_.sum_decreases -= volume_change;
108     } else {
109       ++volume_update_stats_.num_increases;
110       volume_update_stats_.sum_increases += volume_change;
111     }
112   }
113   // Periodically log input volume change metrics.
114   if (++log_volume_update_stats_counter_ >= kFramesIn60Seconds) {
115     LogVolumeUpdateStats();
116     volume_update_stats_ = {};
117     log_volume_update_stats_counter_ = 0;
118   }
119   previous_input_volume_ = input_volume;
120 }
121 
LogVolumeUpdateStats() const122 void InputVolumeStatsReporter::LogVolumeUpdateStats() const {
123   // Decrease rate and average.
124   metrics::HistogramAdd(histograms_.decrease_rate,
125                         volume_update_stats_.num_decreases);
126   if (volume_update_stats_.num_decreases > 0) {
127     int average_decrease = ComputeAverageUpdate(
128         volume_update_stats_.sum_decreases, volume_update_stats_.num_decreases);
129     metrics::HistogramAdd(histograms_.decrease_average, average_decrease);
130   }
131   // Increase rate and average.
132   metrics::HistogramAdd(histograms_.increase_rate,
133                         volume_update_stats_.num_increases);
134   if (volume_update_stats_.num_increases > 0) {
135     int average_increase = ComputeAverageUpdate(
136         volume_update_stats_.sum_increases, volume_update_stats_.num_increases);
137     metrics::HistogramAdd(histograms_.increase_average, average_increase);
138   }
139   // Update rate and average.
140   int num_updates =
141       volume_update_stats_.num_decreases + volume_update_stats_.num_increases;
142   metrics::HistogramAdd(histograms_.update_rate, num_updates);
143   if (num_updates > 0) {
144     int average_update = ComputeAverageUpdate(
145         volume_update_stats_.sum_decreases + volume_update_stats_.sum_increases,
146         num_updates);
147     metrics::HistogramAdd(histograms_.update_average, average_update);
148   }
149 }
150 
151 }  // namespace webrtc
152