1 /*
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
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
21 namespace webrtc {
22
23 typedef void Handle;
24
25 namespace {
MapSetting(GainControl::Mode mode)26 WebRtc_Word16 MapSetting(GainControl::Mode mode) {
27 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
GainControlImpl(const AudioProcessingImpl * apm)40 GainControlImpl::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
~GainControlImpl()53 GainControlImpl::~GainControlImpl() {}
54
ProcessRenderAudio(AudioBuffer * audio)55 int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
56 if (!is_component_enabled()) {
57 return apm_->kNoError;
58 }
59
60 assert(audio->samples_per_split_channel() <= 160);
61
62 WebRtc_Word16* mixed_data = audio->low_pass_split_data(0);
63 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,
73 static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
74
75 if (err != apm_->kNoError) {
76 return GetHandleError(my_handle);
77 }
78 }
79
80 return apm_->kNoError;
81 }
82
AnalyzeCaptureAudio(AudioBuffer * audio)83 int 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),
100 static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
101
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));
110 WebRtc_Word32 capture_level_out = 0;
111
112 err = WebRtcAgc_VirtualMic(
113 my_handle,
114 audio->low_pass_split_data(i),
115 audio->high_pass_split_data(i),
116 static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
117 //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
ProcessCaptureAudio(AudioBuffer * audio)133 int 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));
148 WebRtc_Word32 capture_level_out = 0;
149 WebRtc_UWord8 saturation_warning = 0;
150
151 int err = WebRtcAgc_Process(
152 my_handle,
153 audio->low_pass_split_data(i),
154 audio->high_pass_split_data(i),
155 static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
156 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.
set_stream_analog_level(int level)188 int 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
stream_analog_level()205 int GainControlImpl::stream_analog_level() {
206 // TODO(ajm): enable this assertion?
207 //assert(mode_ == kAdaptiveAnalog);
208
209 return analog_capture_level_;
210 }
211
Enable(bool enable)212 int GainControlImpl::Enable(bool enable) {
213 CriticalSectionScoped crit_scoped(apm_->crit());
214 return EnableComponent(enable);
215 }
216
is_enabled() const217 bool GainControlImpl::is_enabled() const {
218 return is_component_enabled();
219 }
220
set_mode(Mode mode)221 int GainControlImpl::set_mode(Mode mode) {
222 CriticalSectionScoped crit_scoped(apm_->crit());
223 if (MapSetting(mode) == -1) {
224 return apm_->kBadParameterError;
225 }
226
227 mode_ = mode;
228 return Initialize();
229 }
230
mode() const231 GainControl::Mode GainControlImpl::mode() const {
232 return mode_;
233 }
234
set_analog_level_limits(int minimum,int maximum)235 int GainControlImpl::set_analog_level_limits(int minimum,
236 int maximum) {
237 CriticalSectionScoped crit_scoped(apm_->crit());
238 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
analog_level_minimum() const256 int GainControlImpl::analog_level_minimum() const {
257 return minimum_capture_level_;
258 }
259
analog_level_maximum() const260 int GainControlImpl::analog_level_maximum() const {
261 return maximum_capture_level_;
262 }
263
stream_is_saturated() const264 bool GainControlImpl::stream_is_saturated() const {
265 return stream_is_saturated_;
266 }
267
set_target_level_dbfs(int level)268 int GainControlImpl::set_target_level_dbfs(int level) {
269 CriticalSectionScoped crit_scoped(apm_->crit());
270 if (level > 31 || level < 0) {
271 return apm_->kBadParameterError;
272 }
273
274 target_level_dbfs_ = level;
275 return Configure();
276 }
277
target_level_dbfs() const278 int GainControlImpl::target_level_dbfs() const {
279 return target_level_dbfs_;
280 }
281
set_compression_gain_db(int gain)282 int GainControlImpl::set_compression_gain_db(int gain) {
283 CriticalSectionScoped crit_scoped(apm_->crit());
284 if (gain < 0 || gain > 90) {
285 return apm_->kBadParameterError;
286 }
287
288 compression_gain_db_ = gain;
289 return Configure();
290 }
291
compression_gain_db() const292 int GainControlImpl::compression_gain_db() const {
293 return compression_gain_db_;
294 }
295
enable_limiter(bool enable)296 int GainControlImpl::enable_limiter(bool enable) {
297 CriticalSectionScoped crit_scoped(apm_->crit());
298 limiter_enabled_ = enable;
299 return Configure();
300 }
301
is_limiter_enabled() const302 bool GainControlImpl::is_limiter_enabled() const {
303 return limiter_enabled_;
304 }
305
Initialize()306 int 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
CreateHandle() const320 void* 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
DestroyHandle(void * handle) const331 int GainControlImpl::DestroyHandle(void* handle) const {
332 return WebRtcAgc_Free(static_cast<Handle*>(handle));
333 }
334
InitializeHandle(void * handle) const335 int 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
ConfigureHandle(void * handle) const343 int 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);
348 //config.targetLevelDbfs = static_cast<WebRtc_Word16>(-target_level_dbfs_);
349 config.targetLevelDbfs = static_cast<WebRtc_Word16>(target_level_dbfs_);
350 config.compressionGaindB =
351 static_cast<WebRtc_Word16>(compression_gain_db_);
352 config.limiterEnable = limiter_enabled_;
353
354 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
355 }
356
num_handles_required() const357 int GainControlImpl::num_handles_required() const {
358 return apm_->num_output_channels();
359 }
360
GetHandleError(void * handle) const361 int 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
368