Analog AGC: Add clipping rate metrics

Add a histogram WebRTC.Audio.Agc.InputClippingRate and logging of
max clipping rate in AgcManagerDirect.

Bug: webrtc:12774
Change-Id: I4a72119b65ad032fc50672e2a8fb4a4d55e1ff24
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/225264
Commit-Queue: Hanna Silen <silen@webrtc.org>
Reviewed-by: Minyue Li <minyue@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34450}
diff --git a/modules/audio_processing/agc/agc_manager_direct.cc b/modules/audio_processing/agc/agc_manager_direct.cc
index 8176788..e2a5b99 100644
--- a/modules/audio_processing/agc/agc_manager_direct.cc
+++ b/modules/audio_processing/agc/agc_manager_direct.cc
@@ -160,6 +160,13 @@
   }
 }
 
+void LogClippingMetrics(int clipping_rate) {
+  RTC_LOG(LS_INFO) << "Input clipping rate: " << clipping_rate << "%";
+  RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.Agc.InputClippingRate",
+                              clipping_rate, /*min=*/0, /*max=*/100,
+                              /*bucket_count=*/50);
+}
+
 }  // namespace
 
 MonoAgc::MonoAgc(ApmDataDumper* data_dumper,
@@ -480,7 +487,9 @@
       use_clipping_predictor_step_(!!clipping_predictor_ &&
                                    clipping_config.use_predicted_step),
       clipping_predictor_evaluator_(kClippingPredictorEvaluatorHistorySize),
-      clipping_predictor_log_counter_(0) {
+      clipping_predictor_log_counter_(0),
+      clipping_rate_log_(0.0f),
+      clipping_rate_log_counter_(0) {
   const int min_mic_level = GetMinMicLevel();
   for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) {
     ApmDataDumper* data_dumper_ch = ch == 0 ? data_dumper_.get() : nullptr;
@@ -511,6 +520,8 @@
   AggregateChannelLevels();
   clipping_predictor_evaluator_.Reset();
   clipping_predictor_log_counter_ = 0;
+  clipping_rate_log_ = 0.0f;
+  clipping_rate_log_counter_ = 0;
 }
 
 void AgcManagerDirect::SetupDigitalGainControl(
@@ -553,11 +564,6 @@
     clipping_predictor_->Analyze(frame);
   }
 
-  if (frames_since_clipped_ < clipped_wait_frames_) {
-    ++frames_since_clipped_;
-    return;
-  }
-
   // Check for clipped samples, as the AGC has difficulty detecting pitch
   // under clipping distortion. We do this in the preprocessing phase in order
   // to catch clipped echo as well.
@@ -569,6 +575,20 @@
   // gain is increased, through SetMaxLevel().
   float clipped_ratio =
       ComputeClippedRatio(audio, num_capture_channels_, samples_per_channel);
+  clipping_rate_log_ = std::max(clipped_ratio, clipping_rate_log_);
+  clipping_rate_log_counter_++;
+  constexpr int kNumFramesIn30Seconds = 3000;
+  if (clipping_rate_log_counter_ == kNumFramesIn30Seconds) {
+    LogClippingMetrics(std::round(100.0f * clipping_rate_log_));
+    clipping_rate_log_ = 0.0f;
+    clipping_rate_log_counter_ = 0;
+  }
+
+  if (frames_since_clipped_ < clipped_wait_frames_) {
+    ++frames_since_clipped_;
+    return;
+  }
+
   const bool clipping_detected = clipped_ratio > clipped_ratio_threshold_;
   bool clipping_predicted = false;
   int predicted_step = 0;
@@ -592,7 +612,6 @@
           prediction_interval.value(), /*min=*/0,
           /*max=*/49, /*bucket_count=*/50);
     }
-    constexpr int kNumFramesIn30Seconds = 3000;
     clipping_predictor_log_counter_++;
     if (clipping_predictor_log_counter_ == kNumFramesIn30Seconds) {
       LogClippingPredictorMetrics(clipping_predictor_evaluator_);
diff --git a/modules/audio_processing/agc/agc_manager_direct.h b/modules/audio_processing/agc/agc_manager_direct.h
index 7ac96a6..d80a255c 100644
--- a/modules/audio_processing/agc/agc_manager_direct.h
+++ b/modules/audio_processing/agc/agc_manager_direct.h
@@ -152,6 +152,8 @@
   const bool use_clipping_predictor_step_;
   ClippingPredictorEvaluator clipping_predictor_evaluator_;
   int clipping_predictor_log_counter_;
+  float clipping_rate_log_;
+  int clipping_rate_log_counter_;
 };
 
 class MonoAgc {