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()32Agc::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)40void 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)53bool 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()75void Agc::Reset() { 76 histogram_->Reset(); 77 } 78 set_target_level_dbfs(int level)79int 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() const90int Agc::target_level_dbfs() const { 91 return target_level_dbfs_; 92 } 93 voice_probability() const94float Agc::voice_probability() const { 95 return vad_.last_voice_probability(); 96 } 97 98 } // namespace webrtc 99