blob: 01a372ac787024b2850f827354d9aa09fa09ab4a [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
11#include "gain_control_impl.h"
12
13#include <cassert>
14
15#include "critical_section_wrapper.h"
16#include "gain_control.h"
17
18#include "audio_processing_impl.h"
19#include "audio_buffer.h"
20
21namespace webrtc {
22
23typedef void Handle;
24
niklase@google.com470e71d2011-07-07 08:21:25 +000025namespace {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000026int16_t MapSetting(GainControl::Mode mode) {
niklase@google.com470e71d2011-07-07 08:21:25 +000027 switch (mode) {
28 case GainControl::kAdaptiveAnalog:
29 return kAgcModeAdaptiveAnalog;
niklase@google.com470e71d2011-07-07 08:21:25 +000030 case GainControl::kAdaptiveDigital:
31 return kAgcModeAdaptiveDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000032 case GainControl::kFixedDigital:
33 return kAgcModeFixedDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000034 }
andrew@webrtc.org648af742012-02-08 01:57:29 +000035 assert(false);
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000036 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000037}
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.orgb7192b82013-04-10 07:50:54 +000062 int16_t* mixed_data = audio->low_pass_split_data(0);
niklase@google.com470e71d2011-07-07 08:21:25 +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.orgb7192b82013-04-10 07:50:54 +000073 static_cast<int16_t>(audio->samples_per_split_channel()));
niklase@google.com470e71d2011-07-07 08:21:25 +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) {
94 for (int i = 0; i < num_handles(); i++) {
95 Handle* my_handle = static_cast<Handle*>(handle(i));
96 err = WebRtcAgc_AddMic(
97 my_handle,
98 audio->low_pass_split_data(i),
99 audio->high_pass_split_data(i),
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000100 static_cast<int16_t>(audio->samples_per_split_channel()));
niklase@google.com470e71d2011-07-07 08:21:25 +0000101
102 if (err != apm_->kNoError) {
103 return GetHandleError(my_handle);
104 }
105 }
106 } else if (mode_ == kAdaptiveDigital) {
107
108 for (int i = 0; i < num_handles(); i++) {
109 Handle* my_handle = static_cast<Handle*>(handle(i));
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000110 int32_t capture_level_out = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000111
112 err = WebRtcAgc_VirtualMic(
113 my_handle,
114 audio->low_pass_split_data(i),
115 audio->high_pass_split_data(i),
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000116 static_cast<int16_t>(audio->samples_per_split_channel()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 //capture_levels_[i],
118 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.orgb7192b82013-04-10 07:50:54 +0000148 int32_t capture_level_out = 0;
149 uint8_t saturation_warning = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +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.orgb7192b82013-04-10 07:50:54 +0000155 static_cast<int16_t>(audio->samples_per_split_channel()),
niklase@google.com470e71d2011-07-07 08:21:25 +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 }
193
194 if (mode_ == kAdaptiveAnalog) {
195 if (level != analog_capture_level_) {
196 // The analog level has been changed; update our internal levels.
197 capture_levels_.assign(num_handles(), level);
198 }
199 }
200 analog_capture_level_ = level;
201
202 return apm_->kNoError;
203}
204
205int GainControlImpl::stream_analog_level() {
206 // TODO(ajm): enable this assertion?
207 //assert(mode_ == kAdaptiveAnalog);
208
209 return analog_capture_level_;
210}
211
212int GainControlImpl::Enable(bool enable) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000213 CriticalSectionScoped crit_scoped(apm_->crit());
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 return EnableComponent(enable);
215}
216
217bool GainControlImpl::is_enabled() const {
218 return is_component_enabled();
219}
220
221int GainControlImpl::set_mode(Mode mode) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000222 CriticalSectionScoped crit_scoped(apm_->crit());
niklase@google.com470e71d2011-07-07 08:21:25 +0000223 if (MapSetting(mode) == -1) {
224 return apm_->kBadParameterError;
225 }
226
227 mode_ = mode;
228 return Initialize();
229}
230
231GainControl::Mode GainControlImpl::mode() const {
232 return mode_;
233}
234
235int GainControlImpl::set_analog_level_limits(int minimum,
236 int maximum) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000237 CriticalSectionScoped crit_scoped(apm_->crit());
niklase@google.com470e71d2011-07-07 08:21:25 +0000238 if (minimum < 0) {
239 return apm_->kBadParameterError;
240 }
241
242 if (maximum > 65535) {
243 return apm_->kBadParameterError;
244 }
245
246 if (maximum < minimum) {
247 return apm_->kBadParameterError;
248 }
249
250 minimum_capture_level_ = minimum;
251 maximum_capture_level_ = maximum;
252
253 return Initialize();
254}
255
256int GainControlImpl::analog_level_minimum() const {
257 return minimum_capture_level_;
258}
259
260int GainControlImpl::analog_level_maximum() const {
261 return maximum_capture_level_;
262}
263
264bool GainControlImpl::stream_is_saturated() const {
265 return stream_is_saturated_;
266}
267
268int GainControlImpl::set_target_level_dbfs(int level) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000269 CriticalSectionScoped crit_scoped(apm_->crit());
niklase@google.com470e71d2011-07-07 08:21:25 +0000270 if (level > 31 || level < 0) {
271 return apm_->kBadParameterError;
272 }
273
274 target_level_dbfs_ = level;
275 return Configure();
276}
277
278int GainControlImpl::target_level_dbfs() const {
279 return target_level_dbfs_;
280}
281
282int GainControlImpl::set_compression_gain_db(int gain) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000283 CriticalSectionScoped crit_scoped(apm_->crit());
niklase@google.com470e71d2011-07-07 08:21:25 +0000284 if (gain < 0 || gain > 90) {
285 return apm_->kBadParameterError;
286 }
287
288 compression_gain_db_ = gain;
289 return Configure();
290}
291
292int GainControlImpl::compression_gain_db() const {
293 return compression_gain_db_;
294}
295
296int GainControlImpl::enable_limiter(bool enable) {
andrew@webrtc.org40654032012-01-30 20:51:15 +0000297 CriticalSectionScoped crit_scoped(apm_->crit());
niklase@google.com470e71d2011-07-07 08:21:25 +0000298 limiter_enabled_ = enable;
299 return Configure();
300}
301
302bool GainControlImpl::is_limiter_enabled() const {
303 return limiter_enabled_;
304}
305
306int GainControlImpl::Initialize() {
307 int err = ProcessingComponent::Initialize();
308 if (err != apm_->kNoError || !is_component_enabled()) {
309 return err;
310 }
311
312 analog_capture_level_ =
313 (maximum_capture_level_ - minimum_capture_level_) >> 1;
314 capture_levels_.assign(num_handles(), analog_capture_level_);
315 was_analog_level_set_ = false;
316
317 return apm_->kNoError;
318}
319
niklase@google.com470e71d2011-07-07 08:21:25 +0000320void* GainControlImpl::CreateHandle() const {
321 Handle* handle = NULL;
322 if (WebRtcAgc_Create(&handle) != apm_->kNoError) {
323 handle = NULL;
324 } else {
325 assert(handle != NULL);
326 }
327
328 return handle;
329}
330
331int GainControlImpl::DestroyHandle(void* handle) const {
332 return WebRtcAgc_Free(static_cast<Handle*>(handle));
333}
334
335int GainControlImpl::InitializeHandle(void* handle) const {
336 return WebRtcAgc_Init(static_cast<Handle*>(handle),
337 minimum_capture_level_,
338 maximum_capture_level_,
339 MapSetting(mode_),
340 apm_->sample_rate_hz());
341}
342
343int GainControlImpl::ConfigureHandle(void* handle) const {
344 WebRtcAgc_config_t config;
345 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
346 // change the interface.
347 //assert(target_level_dbfs_ <= 0);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000348 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
349 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000350 config.compressionGaindB =
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000351 static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 config.limiterEnable = limiter_enabled_;
353
354 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
355}
356
357int GainControlImpl::num_handles_required() const {
358 return apm_->num_output_channels();
359}
360
361int GainControlImpl::GetHandleError(void* handle) const {
362 // The AGC has no get_error() function.
363 // (Despite listing errors in its interface...)
364 assert(handle != NULL);
365 return apm_->kUnspecifiedError;
366}
367} // namespace webrtc