blob: a6cd6842560b7179cf54ce01e99405d942a2b12b [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
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
pbos@webrtc.org9fb16132013-05-28 08:11:59 +000011#include "webrtc/modules/audio_processing/gain_control_impl.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
pbos@webrtc.org3f45c2e2013-08-05 16:22:53 +000013#include <assert.h>
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000014
pbos@webrtc.org9fb16132013-05-28 08:11:59 +000015#include "webrtc/modules/audio_processing/agc/include/gain_control.h"
16#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000017
pbos@webrtc.org9fb16132013-05-28 08:11:59 +000018#include "webrtc/modules/audio_processing/audio_buffer.h"
19#include "webrtc/modules/audio_processing/audio_processing_impl.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000020
21namespace webrtc {
22
23typedef void Handle;
24
25namespace {
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +000026int16_t MapSetting(GainControl::Mode mode) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000027 switch (mode) {
28 case GainControl::kAdaptiveAnalog:
29 return kAgcModeAdaptiveAnalog;
30 case GainControl::kAdaptiveDigital:
31 return kAgcModeAdaptiveDigital;
32 case GainControl::kFixedDigital:
33 return kAgcModeFixedDigital;
34 }
35 assert(false);
36 return -1;
37}
38} // namespace
39
40GainControlImpl::GainControlImpl(const AudioProcessingImpl* apm)
41 : ProcessingComponent(apm),
42 apm_(apm),
43 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
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +000062 int16_t* mixed_data = audio->low_pass_split_data(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000063 if (audio->num_channels() > 1) {
64 audio->CopyAndMixLowPass(1);
65 mixed_data = audio->mixed_low_pass_data(0);
66 }
67
68 for (int i = 0; i < num_handles(); i++) {
69 Handle* my_handle = static_cast<Handle*>(handle(i));
70 int err = WebRtcAgc_AddFarend(
71 my_handle,
72 mixed_data,
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +000073 static_cast<int16_t>(audio->samples_per_split_channel()));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000074
75 if (err != apm_->kNoError) {
76 return GetHandleError(my_handle);
77 }
78 }
79
80 return apm_->kNoError;
81}
82
83int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
84 if (!is_component_enabled()) {
85 return apm_->kNoError;
86 }
87
88 assert(audio->samples_per_split_channel() <= 160);
89 assert(audio->num_channels() == num_handles());
90
91 int err = apm_->kNoError;
92
93 if (mode_ == kAdaptiveAnalog) {
andrew@webrtc.orge95dc252014-01-07 17:45:09 +000094 capture_levels_.assign(num_handles(), analog_capture_level_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000095 for (int i = 0; i < num_handles(); i++) {
96 Handle* my_handle = static_cast<Handle*>(handle(i));
97 err = WebRtcAgc_AddMic(
98 my_handle,
99 audio->low_pass_split_data(i),
100 audio->high_pass_split_data(i),
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000101 static_cast<int16_t>(audio->samples_per_split_channel()));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000102
103 if (err != apm_->kNoError) {
104 return GetHandleError(my_handle);
105 }
106 }
107 } else if (mode_ == kAdaptiveDigital) {
108
109 for (int i = 0; i < num_handles(); i++) {
110 Handle* my_handle = static_cast<Handle*>(handle(i));
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000111 int32_t capture_level_out = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000112
113 err = WebRtcAgc_VirtualMic(
114 my_handle,
115 audio->low_pass_split_data(i),
116 audio->high_pass_split_data(i),
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000117 static_cast<int16_t>(audio->samples_per_split_channel()),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000118 analog_capture_level_,
119 &capture_level_out);
120
121 capture_levels_[i] = capture_level_out;
122
123 if (err != apm_->kNoError) {
124 return GetHandleError(my_handle);
125 }
126
127 }
128 }
129
130 return apm_->kNoError;
131}
132
133int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) {
134 if (!is_component_enabled()) {
135 return apm_->kNoError;
136 }
137
138 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
139 return apm_->kStreamParameterNotSetError;
140 }
141
142 assert(audio->samples_per_split_channel() <= 160);
143 assert(audio->num_channels() == num_handles());
144
145 stream_is_saturated_ = false;
146 for (int i = 0; i < num_handles(); i++) {
147 Handle* my_handle = static_cast<Handle*>(handle(i));
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000148 int32_t capture_level_out = 0;
149 uint8_t saturation_warning = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000150
151 int err = WebRtcAgc_Process(
152 my_handle,
153 audio->low_pass_split_data(i),
154 audio->high_pass_split_data(i),
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000155 static_cast<int16_t>(audio->samples_per_split_channel()),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000156 audio->low_pass_split_data(i),
157 audio->high_pass_split_data(i),
158 capture_levels_[i],
159 &capture_level_out,
160 apm_->echo_cancellation()->stream_has_echo(),
161 &saturation_warning);
162
163 if (err != apm_->kNoError) {
164 return GetHandleError(my_handle);
165 }
166
167 capture_levels_[i] = capture_level_out;
168 if (saturation_warning == 1) {
169 stream_is_saturated_ = true;
170 }
171 }
172
173 if (mode_ == kAdaptiveAnalog) {
174 // Take the analog level to be the average across the handles.
175 analog_capture_level_ = 0;
176 for (int i = 0; i < num_handles(); i++) {
177 analog_capture_level_ += capture_levels_[i];
178 }
179
180 analog_capture_level_ /= num_handles();
181 }
182
183 was_analog_level_set_ = false;
184 return apm_->kNoError;
185}
186
187// TODO(ajm): ensure this is called under kAdaptiveAnalog.
188int GainControlImpl::set_stream_analog_level(int level) {
189 was_analog_level_set_ = true;
190 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
191 return apm_->kBadParameterError;
192 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000193 analog_capture_level_ = level;
194
195 return apm_->kNoError;
196}
197
198int GainControlImpl::stream_analog_level() {
199 // TODO(ajm): enable this assertion?
200 //assert(mode_ == kAdaptiveAnalog);
201
202 return analog_capture_level_;
203}
204
205int GainControlImpl::Enable(bool enable) {
206 CriticalSectionScoped crit_scoped(apm_->crit());
207 return EnableComponent(enable);
208}
209
210bool GainControlImpl::is_enabled() const {
211 return is_component_enabled();
212}
213
214int GainControlImpl::set_mode(Mode mode) {
215 CriticalSectionScoped crit_scoped(apm_->crit());
216 if (MapSetting(mode) == -1) {
217 return apm_->kBadParameterError;
218 }
219
220 mode_ = mode;
221 return Initialize();
222}
223
224GainControl::Mode GainControlImpl::mode() const {
225 return mode_;
226}
227
228int GainControlImpl::set_analog_level_limits(int minimum,
229 int maximum) {
230 CriticalSectionScoped crit_scoped(apm_->crit());
231 if (minimum < 0) {
232 return apm_->kBadParameterError;
233 }
234
235 if (maximum > 65535) {
236 return apm_->kBadParameterError;
237 }
238
239 if (maximum < minimum) {
240 return apm_->kBadParameterError;
241 }
242
243 minimum_capture_level_ = minimum;
244 maximum_capture_level_ = maximum;
245
246 return Initialize();
247}
248
249int GainControlImpl::analog_level_minimum() const {
250 return minimum_capture_level_;
251}
252
253int GainControlImpl::analog_level_maximum() const {
254 return maximum_capture_level_;
255}
256
257bool GainControlImpl::stream_is_saturated() const {
258 return stream_is_saturated_;
259}
260
261int GainControlImpl::set_target_level_dbfs(int level) {
262 CriticalSectionScoped crit_scoped(apm_->crit());
263 if (level > 31 || level < 0) {
264 return apm_->kBadParameterError;
265 }
266
267 target_level_dbfs_ = level;
268 return Configure();
269}
270
271int GainControlImpl::target_level_dbfs() const {
272 return target_level_dbfs_;
273}
274
275int GainControlImpl::set_compression_gain_db(int gain) {
276 CriticalSectionScoped crit_scoped(apm_->crit());
277 if (gain < 0 || gain > 90) {
278 return apm_->kBadParameterError;
279 }
280
281 compression_gain_db_ = gain;
282 return Configure();
283}
284
285int GainControlImpl::compression_gain_db() const {
286 return compression_gain_db_;
287}
288
289int GainControlImpl::enable_limiter(bool enable) {
290 CriticalSectionScoped crit_scoped(apm_->crit());
291 limiter_enabled_ = enable;
292 return Configure();
293}
294
295bool GainControlImpl::is_limiter_enabled() const {
296 return limiter_enabled_;
297}
298
299int GainControlImpl::Initialize() {
300 int err = ProcessingComponent::Initialize();
301 if (err != apm_->kNoError || !is_component_enabled()) {
302 return err;
303 }
304
andrew@webrtc.org48b98922014-01-07 18:36:10 +0000305 capture_levels_.assign(num_handles(), analog_capture_level_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000306 return apm_->kNoError;
307}
308
309void* GainControlImpl::CreateHandle() const {
310 Handle* handle = NULL;
311 if (WebRtcAgc_Create(&handle) != apm_->kNoError) {
312 handle = NULL;
313 } else {
314 assert(handle != NULL);
315 }
316
317 return handle;
318}
319
320int GainControlImpl::DestroyHandle(void* handle) const {
321 return WebRtcAgc_Free(static_cast<Handle*>(handle));
322}
323
324int GainControlImpl::InitializeHandle(void* handle) const {
325 return WebRtcAgc_Init(static_cast<Handle*>(handle),
326 minimum_capture_level_,
327 maximum_capture_level_,
328 MapSetting(mode_),
329 apm_->sample_rate_hz());
330}
331
332int GainControlImpl::ConfigureHandle(void* handle) const {
333 WebRtcAgc_config_t config;
334 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
335 // change the interface.
336 //assert(target_level_dbfs_ <= 0);
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000337 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
338 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000339 config.compressionGaindB =
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000340 static_cast<int16_t>(compression_gain_db_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000341 config.limiterEnable = limiter_enabled_;
342
343 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
344}
345
346int GainControlImpl::num_handles_required() const {
347 return apm_->num_output_channels();
348}
349
350int GainControlImpl::GetHandleError(void* handle) const {
351 // The AGC has no get_error() function.
352 // (Despite listing errors in its interface...)
353 assert(handle != NULL);
354 return apm_->kUnspecifiedError;
355}
356} // namespace webrtc