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