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