blob: 8a3612dce5a7b7ea9c2b5a6c128329a3168b2da9 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
bjornv@webrtc.org0c6f9312012-01-30 09:39:08 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000011#include "webrtc/modules/audio_processing/gain_control_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000015#include "webrtc/modules/audio_processing/audio_buffer.h"
bjornv@webrtc.orgb395a5e2014-12-16 10:38:10 +000016#include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000017#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018
niklase@google.com470e71d2011-07-07 08:21:25 +000019namespace webrtc {
20
21typedef void Handle;
22
niklase@google.com470e71d2011-07-07 08:21:25 +000023namespace {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000024int16_t MapSetting(GainControl::Mode mode) {
niklase@google.com470e71d2011-07-07 08:21:25 +000025 switch (mode) {
26 case GainControl::kAdaptiveAnalog:
27 return kAgcModeAdaptiveAnalog;
niklase@google.com470e71d2011-07-07 08:21:25 +000028 case GainControl::kAdaptiveDigital:
29 return kAgcModeAdaptiveDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000030 case GainControl::kFixedDigital:
31 return kAgcModeFixedDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000032 }
andrew@webrtc.org648af742012-02-08 01:57:29 +000033 assert(false);
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000034 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
36} // namespace
37
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000038GainControlImpl::GainControlImpl(const AudioProcessing* apm,
39 CriticalSectionWrapper* crit)
40 : ProcessingComponent(),
niklase@google.com470e71d2011-07-07 08:21:25 +000041 apm_(apm),
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000042 crit_(crit),
niklase@google.com470e71d2011-07-07 08:21:25 +000043 mode_(kAdaptiveAnalog),
44 minimum_capture_level_(0),
45 maximum_capture_level_(255),
46 limiter_enabled_(true),
47 target_level_dbfs_(3),
48 compression_gain_db_(9),
49 analog_capture_level_(0),
50 was_analog_level_set_(false),
51 stream_is_saturated_(false) {}
52
53GainControlImpl::~GainControlImpl() {}
54
55int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
56 if (!is_component_enabled()) {
57 return apm_->kNoError;
58 }
59
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +000060 assert(audio->num_frames_per_band() <= 160);
niklase@google.com470e71d2011-07-07 08:21:25 +000061
niklase@google.com470e71d2011-07-07 08:21:25 +000062 for (int i = 0; i < num_handles(); i++) {
63 Handle* my_handle = static_cast<Handle*>(handle(i));
64 int err = WebRtcAgc_AddFarend(
65 my_handle,
aluebs@webrtc.org2561d522014-07-17 08:27:39 +000066 audio->mixed_low_pass_data(),
Peter Kastingdce40cf2015-08-24 14:52:23 -070067 audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +000068
69 if (err != apm_->kNoError) {
70 return GetHandleError(my_handle);
71 }
72 }
73
74 return apm_->kNoError;
75}
76
77int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
78 if (!is_component_enabled()) {
79 return apm_->kNoError;
80 }
81
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +000082 assert(audio->num_frames_per_band() <= 160);
niklase@google.com470e71d2011-07-07 08:21:25 +000083 assert(audio->num_channels() == num_handles());
84
85 int err = apm_->kNoError;
86
87 if (mode_ == kAdaptiveAnalog) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000088 capture_levels_.assign(num_handles(), analog_capture_level_);
niklase@google.com470e71d2011-07-07 08:21:25 +000089 for (int i = 0; i < num_handles(); i++) {
90 Handle* my_handle = static_cast<Handle*>(handle(i));
91 err = WebRtcAgc_AddMic(
92 my_handle,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +000093 audio->split_bands(i),
94 audio->num_bands(),
Peter Kastingdce40cf2015-08-24 14:52:23 -070095 audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +000096
97 if (err != apm_->kNoError) {
98 return GetHandleError(my_handle);
99 }
100 }
101 } else if (mode_ == kAdaptiveDigital) {
102
103 for (int i = 0; i < num_handles(); i++) {
104 Handle* my_handle = static_cast<Handle*>(handle(i));
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000105 int32_t capture_level_out = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000106
107 err = WebRtcAgc_VirtualMic(
108 my_handle,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000109 audio->split_bands(i),
110 audio->num_bands(),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700111 audio->num_frames_per_band(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000112 analog_capture_level_,
113 &capture_level_out);
114
115 capture_levels_[i] = capture_level_out;
116
117 if (err != apm_->kNoError) {
118 return GetHandleError(my_handle);
119 }
120
121 }
122 }
123
124 return apm_->kNoError;
125}
126
127int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) {
128 if (!is_component_enabled()) {
129 return apm_->kNoError;
130 }
131
132 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
133 return apm_->kStreamParameterNotSetError;
134 }
135
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000136 assert(audio->num_frames_per_band() <= 160);
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 assert(audio->num_channels() == num_handles());
138
139 stream_is_saturated_ = false;
140 for (int i = 0; i < num_handles(); i++) {
141 Handle* my_handle = static_cast<Handle*>(handle(i));
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000142 int32_t capture_level_out = 0;
143 uint8_t saturation_warning = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000144
145 int err = WebRtcAgc_Process(
146 my_handle,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000147 audio->split_bands_const(i),
148 audio->num_bands(),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700149 audio->num_frames_per_band(),
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000150 audio->split_bands(i),
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 capture_levels_[i],
152 &capture_level_out,
153 apm_->echo_cancellation()->stream_has_echo(),
154 &saturation_warning);
155
156 if (err != apm_->kNoError) {
157 return GetHandleError(my_handle);
158 }
159
160 capture_levels_[i] = capture_level_out;
161 if (saturation_warning == 1) {
162 stream_is_saturated_ = true;
163 }
164 }
165
166 if (mode_ == kAdaptiveAnalog) {
167 // Take the analog level to be the average across the handles.
168 analog_capture_level_ = 0;
169 for (int i = 0; i < num_handles(); i++) {
170 analog_capture_level_ += capture_levels_[i];
171 }
172
173 analog_capture_level_ /= num_handles();
174 }
175
176 was_analog_level_set_ = false;
177 return apm_->kNoError;
178}
179
180// TODO(ajm): ensure this is called under kAdaptiveAnalog.
181int GainControlImpl::set_stream_analog_level(int level) {
Brave Yao1a07a1e2015-05-21 12:42:40 +0800182 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 was_analog_level_set_ = true;
184 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
185 return apm_->kBadParameterError;
186 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000187 analog_capture_level_ = level;
188
189 return apm_->kNoError;
190}
191
192int GainControlImpl::stream_analog_level() {
193 // TODO(ajm): enable this assertion?
194 //assert(mode_ == kAdaptiveAnalog);
195
196 return analog_capture_level_;
197}
198
199int GainControlImpl::Enable(bool enable) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000200 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 return EnableComponent(enable);
202}
203
204bool GainControlImpl::is_enabled() const {
205 return is_component_enabled();
206}
207
208int GainControlImpl::set_mode(Mode mode) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000209 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000210 if (MapSetting(mode) == -1) {
211 return apm_->kBadParameterError;
212 }
213
214 mode_ = mode;
215 return Initialize();
216}
217
218GainControl::Mode GainControlImpl::mode() const {
219 return mode_;
220}
221
222int GainControlImpl::set_analog_level_limits(int minimum,
223 int maximum) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000224 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000225 if (minimum < 0) {
226 return apm_->kBadParameterError;
227 }
228
229 if (maximum > 65535) {
230 return apm_->kBadParameterError;
231 }
232
233 if (maximum < minimum) {
234 return apm_->kBadParameterError;
235 }
236
237 minimum_capture_level_ = minimum;
238 maximum_capture_level_ = maximum;
239
240 return Initialize();
241}
242
243int GainControlImpl::analog_level_minimum() const {
244 return minimum_capture_level_;
245}
246
247int GainControlImpl::analog_level_maximum() const {
248 return maximum_capture_level_;
249}
250
251bool GainControlImpl::stream_is_saturated() const {
252 return stream_is_saturated_;
253}
254
255int GainControlImpl::set_target_level_dbfs(int level) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000256 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000257 if (level > 31 || level < 0) {
258 return apm_->kBadParameterError;
259 }
260
261 target_level_dbfs_ = level;
262 return Configure();
263}
264
265int GainControlImpl::target_level_dbfs() const {
266 return target_level_dbfs_;
267}
268
269int GainControlImpl::set_compression_gain_db(int gain) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000270 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000271 if (gain < 0 || gain > 90) {
272 return apm_->kBadParameterError;
273 }
274
275 compression_gain_db_ = gain;
276 return Configure();
277}
278
279int GainControlImpl::compression_gain_db() const {
280 return compression_gain_db_;
281}
282
283int GainControlImpl::enable_limiter(bool enable) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000284 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 limiter_enabled_ = enable;
286 return Configure();
287}
288
289bool GainControlImpl::is_limiter_enabled() const {
290 return limiter_enabled_;
291}
292
293int GainControlImpl::Initialize() {
294 int err = ProcessingComponent::Initialize();
295 if (err != apm_->kNoError || !is_component_enabled()) {
296 return err;
297 }
298
andrew@webrtc.orgb6541ca2014-01-07 18:36:10 +0000299 capture_levels_.assign(num_handles(), analog_capture_level_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000300 return apm_->kNoError;
301}
302
niklase@google.com470e71d2011-07-07 08:21:25 +0000303void* GainControlImpl::CreateHandle() const {
Bjorn Volcker9345e862015-06-10 21:43:36 +0200304 return WebRtcAgc_Create();
niklase@google.com470e71d2011-07-07 08:21:25 +0000305}
306
bjornv@webrtc.org5964fe02014-04-22 06:52:28 +0000307void GainControlImpl::DestroyHandle(void* handle) const {
308 WebRtcAgc_Free(static_cast<Handle*>(handle));
niklase@google.com470e71d2011-07-07 08:21:25 +0000309}
310
311int GainControlImpl::InitializeHandle(void* handle) const {
312 return WebRtcAgc_Init(static_cast<Handle*>(handle),
313 minimum_capture_level_,
314 maximum_capture_level_,
315 MapSetting(mode_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000316 apm_->proc_sample_rate_hz());
niklase@google.com470e71d2011-07-07 08:21:25 +0000317}
318
319int GainControlImpl::ConfigureHandle(void* handle) const {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000320 WebRtcAgcConfig config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
322 // change the interface.
323 //assert(target_level_dbfs_ <= 0);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000324 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
325 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 config.compressionGaindB =
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000327 static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 config.limiterEnable = limiter_enabled_;
329
330 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
331}
332
333int GainControlImpl::num_handles_required() const {
334 return apm_->num_output_channels();
335}
336
337int GainControlImpl::GetHandleError(void* handle) const {
338 // The AGC has no get_error() function.
339 // (Despite listing errors in its interface...)
340 assert(handle != NULL);
341 return apm_->kUnspecifiedError;
342}
343} // namespace webrtc