blob: cf7df169cb55c860f4f1a807a3915eb9f502d243 [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"
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000016#include "webrtc/modules/audio_processing/agc/include/gain_control.h"
17#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
60 assert(audio->samples_per_split_channel() <= 160);
61
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(),
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000067 static_cast<int16_t>(audio->samples_per_split_channel()));
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
82 assert(audio->samples_per_split_channel() <= 160);
83 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,
93 audio->low_pass_split_data(i),
94 audio->high_pass_split_data(i),
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000095 static_cast<int16_t>(audio->samples_per_split_channel()));
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,
109 audio->low_pass_split_data(i),
110 audio->high_pass_split_data(i),
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000111 static_cast<int16_t>(audio->samples_per_split_channel()),
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
136 assert(audio->samples_per_split_channel() <= 160);
137 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,
147 audio->low_pass_split_data(i),
148 audio->high_pass_split_data(i),
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000149 static_cast<int16_t>(audio->samples_per_split_channel()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000150 audio->low_pass_split_data(i),
151 audio->high_pass_split_data(i),
152 capture_levels_[i],
153 &capture_level_out,
154 apm_->echo_cancellation()->stream_has_echo(),
155 &saturation_warning);
156
157 if (err != apm_->kNoError) {
158 return GetHandleError(my_handle);
159 }
160
161 capture_levels_[i] = capture_level_out;
162 if (saturation_warning == 1) {
163 stream_is_saturated_ = true;
164 }
165 }
166
167 if (mode_ == kAdaptiveAnalog) {
168 // Take the analog level to be the average across the handles.
169 analog_capture_level_ = 0;
170 for (int i = 0; i < num_handles(); i++) {
171 analog_capture_level_ += capture_levels_[i];
172 }
173
174 analog_capture_level_ /= num_handles();
175 }
176
177 was_analog_level_set_ = false;
178 return apm_->kNoError;
179}
180
181// TODO(ajm): ensure this is called under kAdaptiveAnalog.
182int GainControlImpl::set_stream_analog_level(int level) {
183 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 {
304 Handle* handle = NULL;
305 if (WebRtcAgc_Create(&handle) != apm_->kNoError) {
306 handle = NULL;
307 } else {
308 assert(handle != NULL);
309 }
310
311 return handle;
312}
313
bjornv@webrtc.org5964fe02014-04-22 06:52:28 +0000314void GainControlImpl::DestroyHandle(void* handle) const {
315 WebRtcAgc_Free(static_cast<Handle*>(handle));
niklase@google.com470e71d2011-07-07 08:21:25 +0000316}
317
318int GainControlImpl::InitializeHandle(void* handle) const {
319 return WebRtcAgc_Init(static_cast<Handle*>(handle),
320 minimum_capture_level_,
321 maximum_capture_level_,
322 MapSetting(mode_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000323 apm_->proc_sample_rate_hz());
niklase@google.com470e71d2011-07-07 08:21:25 +0000324}
325
326int GainControlImpl::ConfigureHandle(void* handle) const {
327 WebRtcAgc_config_t config;
328 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
329 // change the interface.
330 //assert(target_level_dbfs_ <= 0);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000331 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
332 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000333 config.compressionGaindB =
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000334 static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000335 config.limiterEnable = limiter_enabled_;
336
337 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
338}
339
340int GainControlImpl::num_handles_required() const {
341 return apm_->num_output_channels();
342}
343
344int GainControlImpl::GetHandleError(void* handle) const {
345 // The AGC has no get_error() function.
346 // (Despite listing errors in its interface...)
347 assert(handle != NULL);
348 return apm_->kUnspecifiedError;
349}
350} // namespace webrtc