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