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