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