blob: af92b9c149d8705cf470c1f68131f5af6407b774 [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
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,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +000093 audio->split_bands(i),
94 audio->num_bands(),
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,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000109 audio->split_bands(i),
110 audio->num_bands(),
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,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000147 audio->split_bands_const(i),
148 audio->num_bands(),
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000149 static_cast<int16_t>(audio->samples_per_split_channel()),
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) {
182 was_analog_level_set_ = true;
183 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
184 return apm_->kBadParameterError;
185 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000186 analog_capture_level_ = level;
187
188 return apm_->kNoError;
189}
190
191int GainControlImpl::stream_analog_level() {
192 // TODO(ajm): enable this assertion?
193 //assert(mode_ == kAdaptiveAnalog);
194
195 return analog_capture_level_;
196}
197
198int GainControlImpl::Enable(bool enable) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000199 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000200 return EnableComponent(enable);
201}
202
203bool GainControlImpl::is_enabled() const {
204 return is_component_enabled();
205}
206
207int GainControlImpl::set_mode(Mode mode) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000208 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 if (MapSetting(mode) == -1) {
210 return apm_->kBadParameterError;
211 }
212
213 mode_ = mode;
214 return Initialize();
215}
216
217GainControl::Mode GainControlImpl::mode() const {
218 return mode_;
219}
220
221int GainControlImpl::set_analog_level_limits(int minimum,
222 int maximum) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000223 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 if (minimum < 0) {
225 return apm_->kBadParameterError;
226 }
227
228 if (maximum > 65535) {
229 return apm_->kBadParameterError;
230 }
231
232 if (maximum < minimum) {
233 return apm_->kBadParameterError;
234 }
235
236 minimum_capture_level_ = minimum;
237 maximum_capture_level_ = maximum;
238
239 return Initialize();
240}
241
242int GainControlImpl::analog_level_minimum() const {
243 return minimum_capture_level_;
244}
245
246int GainControlImpl::analog_level_maximum() const {
247 return maximum_capture_level_;
248}
249
250bool GainControlImpl::stream_is_saturated() const {
251 return stream_is_saturated_;
252}
253
254int GainControlImpl::set_target_level_dbfs(int level) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000255 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 if (level > 31 || level < 0) {
257 return apm_->kBadParameterError;
258 }
259
260 target_level_dbfs_ = level;
261 return Configure();
262}
263
264int GainControlImpl::target_level_dbfs() const {
265 return target_level_dbfs_;
266}
267
268int GainControlImpl::set_compression_gain_db(int gain) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000269 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000270 if (gain < 0 || gain > 90) {
271 return apm_->kBadParameterError;
272 }
273
274 compression_gain_db_ = gain;
275 return Configure();
276}
277
278int GainControlImpl::compression_gain_db() const {
279 return compression_gain_db_;
280}
281
282int GainControlImpl::enable_limiter(bool enable) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000283 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000284 limiter_enabled_ = enable;
285 return Configure();
286}
287
288bool GainControlImpl::is_limiter_enabled() const {
289 return limiter_enabled_;
290}
291
292int GainControlImpl::Initialize() {
293 int err = ProcessingComponent::Initialize();
294 if (err != apm_->kNoError || !is_component_enabled()) {
295 return err;
296 }
297
andrew@webrtc.orgb6541ca2014-01-07 18:36:10 +0000298 capture_levels_.assign(num_handles(), analog_capture_level_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000299 return apm_->kNoError;
300}
301
niklase@google.com470e71d2011-07-07 08:21:25 +0000302void* GainControlImpl::CreateHandle() const {
303 Handle* handle = NULL;
304 if (WebRtcAgc_Create(&handle) != apm_->kNoError) {
305 handle = NULL;
306 } else {
307 assert(handle != NULL);
308 }
309
310 return handle;
311}
312
bjornv@webrtc.org5964fe02014-04-22 06:52:28 +0000313void GainControlImpl::DestroyHandle(void* handle) const {
314 WebRtcAgc_Free(static_cast<Handle*>(handle));
niklase@google.com470e71d2011-07-07 08:21:25 +0000315}
316
317int GainControlImpl::InitializeHandle(void* handle) const {
318 return WebRtcAgc_Init(static_cast<Handle*>(handle),
319 minimum_capture_level_,
320 maximum_capture_level_,
321 MapSetting(mode_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000322 apm_->proc_sample_rate_hz());
niklase@google.com470e71d2011-07-07 08:21:25 +0000323}
324
325int GainControlImpl::ConfigureHandle(void* handle) const {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000326 WebRtcAgcConfig config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000327 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
328 // change the interface.
329 //assert(target_level_dbfs_ <= 0);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000330 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
331 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000332 config.compressionGaindB =
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000333 static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000334 config.limiterEnable = limiter_enabled_;
335
336 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
337}
338
339int GainControlImpl::num_handles_required() const {
340 return apm_->num_output_channels();
341}
342
343int GainControlImpl::GetHandleError(void* handle) const {
344 // The AGC has no get_error() function.
345 // (Despite listing errors in its interface...)
346 assert(handle != NULL);
347 return apm_->kUnspecifiedError;
348}
349} // namespace webrtc