xref: /aosp_15_r20/external/webrtc/modules/audio_processing/agc/agc.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2012 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/agc/agc.h"
12 
13 #include <cmath>
14 #include <cstdlib>
15 #include <vector>
16 
17 #include "modules/audio_processing/agc/loudness_histogram.h"
18 #include "modules/audio_processing/agc/utility.h"
19 #include "rtc_base/checks.h"
20 
21 namespace webrtc {
22 namespace {
23 
24 constexpr int kDefaultLevelDbfs = -18;
25 constexpr int kNumAnalysisFrames = 100;
26 constexpr double kActivityThreshold = 0.3;
27 constexpr int kNum10msFramesInOneSecond = 100;
28 constexpr int kMaxSampleRateHz = 384000;
29 
30 }  // namespace
31 
Agc()32 Agc::Agc()
33     : target_level_loudness_(Dbfs2Loudness(kDefaultLevelDbfs)),
34       target_level_dbfs_(kDefaultLevelDbfs),
35       histogram_(LoudnessHistogram::Create(kNumAnalysisFrames)),
36       inactive_histogram_(LoudnessHistogram::Create()) {}
37 
38 Agc::~Agc() = default;
39 
Process(rtc::ArrayView<const int16_t> audio)40 void Agc::Process(rtc::ArrayView<const int16_t> audio) {
41   const int sample_rate_hz = audio.size() * kNum10msFramesInOneSecond;
42   RTC_DCHECK_LE(sample_rate_hz, kMaxSampleRateHz);
43   vad_.ProcessChunk(audio.data(), audio.size(), sample_rate_hz);
44   const std::vector<double>& rms = vad_.chunkwise_rms();
45   const std::vector<double>& probabilities =
46       vad_.chunkwise_voice_probabilities();
47   RTC_DCHECK_EQ(rms.size(), probabilities.size());
48   for (size_t i = 0; i < rms.size(); ++i) {
49     histogram_->Update(rms[i], probabilities[i]);
50   }
51 }
52 
GetRmsErrorDb(int * error)53 bool Agc::GetRmsErrorDb(int* error) {
54   if (!error) {
55     RTC_DCHECK_NOTREACHED();
56     return false;
57   }
58 
59   if (histogram_->num_updates() < kNumAnalysisFrames) {
60     // We haven't yet received enough frames.
61     return false;
62   }
63 
64   if (histogram_->AudioContent() < kNumAnalysisFrames * kActivityThreshold) {
65     // We are likely in an inactive segment.
66     return false;
67   }
68 
69   double loudness = Linear2Loudness(histogram_->CurrentRms());
70   *error = std::floor(Loudness2Db(target_level_loudness_ - loudness) + 0.5);
71   histogram_->Reset();
72   return true;
73 }
74 
Reset()75 void Agc::Reset() {
76   histogram_->Reset();
77 }
78 
set_target_level_dbfs(int level)79 int Agc::set_target_level_dbfs(int level) {
80   // TODO(turajs): just some arbitrary sanity check. We can come up with better
81   // limits. The upper limit should be chosen such that the risk of clipping is
82   // low. The lower limit should not result in a too quiet signal.
83   if (level >= 0 || level <= -100)
84     return -1;
85   target_level_dbfs_ = level;
86   target_level_loudness_ = Dbfs2Loudness(level);
87   return 0;
88 }
89 
target_level_dbfs() const90 int Agc::target_level_dbfs() const {
91   return target_level_dbfs_;
92 }
93 
voice_probability() const94 float Agc::voice_probability() const {
95   return vad_.last_voice_probability();
96 }
97 
98 }  // namespace webrtc
99