1 /*
2  *  Copyright (c) 2011 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 /*template <class T>
26 class GainControlHandle : public ComponentHandle<T> {
27   public:
28     GainControlHandle();
29     virtual ~GainControlHandle();
30 
31     virtual int Create();
32     virtual T* ptr() const;
33 
34   private:
35     T* handle;
36 };*/
37 
38 namespace {
MapSetting(GainControl::Mode mode)39 WebRtc_Word16 MapSetting(GainControl::Mode mode) {
40   switch (mode) {
41     case GainControl::kAdaptiveAnalog:
42       return kAgcModeAdaptiveAnalog;
43       break;
44     case GainControl::kAdaptiveDigital:
45       return kAgcModeAdaptiveDigital;
46       break;
47     case GainControl::kFixedDigital:
48       return kAgcModeFixedDigital;
49       break;
50     default:
51       return -1;
52   }
53 }
54 }  // namespace
55 
GainControlImpl(const AudioProcessingImpl * apm)56 GainControlImpl::GainControlImpl(const AudioProcessingImpl* apm)
57   : ProcessingComponent(apm),
58     apm_(apm),
59     mode_(kAdaptiveAnalog),
60     minimum_capture_level_(0),
61     maximum_capture_level_(255),
62     limiter_enabled_(true),
63     target_level_dbfs_(3),
64     compression_gain_db_(9),
65     analog_capture_level_(0),
66     was_analog_level_set_(false),
67     stream_is_saturated_(false) {}
68 
~GainControlImpl()69 GainControlImpl::~GainControlImpl() {}
70 
ProcessRenderAudio(AudioBuffer * audio)71 int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
72   if (!is_component_enabled()) {
73     return apm_->kNoError;
74   }
75 
76   assert(audio->samples_per_split_channel() <= 160);
77 
78   WebRtc_Word16* mixed_data = audio->low_pass_split_data(0);
79   if (audio->num_channels() > 1) {
80     audio->CopyAndMixLowPass(1);
81     mixed_data = audio->mixed_low_pass_data(0);
82   }
83 
84   for (int i = 0; i < num_handles(); i++) {
85     Handle* my_handle = static_cast<Handle*>(handle(i));
86     int err = WebRtcAgc_AddFarend(
87         my_handle,
88         mixed_data,
89         static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
90 
91     if (err != apm_->kNoError) {
92       return GetHandleError(my_handle);
93     }
94   }
95 
96   return apm_->kNoError;
97 }
98 
AnalyzeCaptureAudio(AudioBuffer * audio)99 int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
100   if (!is_component_enabled()) {
101     return apm_->kNoError;
102   }
103 
104   assert(audio->samples_per_split_channel() <= 160);
105   assert(audio->num_channels() == num_handles());
106 
107   int err = apm_->kNoError;
108 
109   if (mode_ == kAdaptiveAnalog) {
110     for (int i = 0; i < num_handles(); i++) {
111       Handle* my_handle = static_cast<Handle*>(handle(i));
112       err = WebRtcAgc_AddMic(
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 
118       if (err != apm_->kNoError) {
119         return GetHandleError(my_handle);
120       }
121     }
122   } else if (mode_ == kAdaptiveDigital) {
123 
124     for (int i = 0; i < num_handles(); i++) {
125       Handle* my_handle = static_cast<Handle*>(handle(i));
126       WebRtc_Word32 capture_level_out = 0;
127 
128       err = WebRtcAgc_VirtualMic(
129           my_handle,
130           audio->low_pass_split_data(i),
131           audio->high_pass_split_data(i),
132           static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
133           //capture_levels_[i],
134           analog_capture_level_,
135           &capture_level_out);
136 
137       capture_levels_[i] = capture_level_out;
138 
139       if (err != apm_->kNoError) {
140         return GetHandleError(my_handle);
141       }
142 
143     }
144   }
145 
146   return apm_->kNoError;
147 }
148 
ProcessCaptureAudio(AudioBuffer * audio)149 int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) {
150   if (!is_component_enabled()) {
151     return apm_->kNoError;
152   }
153 
154   if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
155     return apm_->kStreamParameterNotSetError;
156   }
157 
158   assert(audio->samples_per_split_channel() <= 160);
159   assert(audio->num_channels() == num_handles());
160 
161   stream_is_saturated_ = false;
162   for (int i = 0; i < num_handles(); i++) {
163     Handle* my_handle = static_cast<Handle*>(handle(i));
164     WebRtc_Word32 capture_level_out = 0;
165     WebRtc_UWord8 saturation_warning = 0;
166 
167     int err = WebRtcAgc_Process(
168         my_handle,
169         audio->low_pass_split_data(i),
170         audio->high_pass_split_data(i),
171         static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
172         audio->low_pass_split_data(i),
173         audio->high_pass_split_data(i),
174         capture_levels_[i],
175         &capture_level_out,
176         apm_->echo_cancellation()->stream_has_echo(),
177         &saturation_warning);
178 
179     if (err != apm_->kNoError) {
180       return GetHandleError(my_handle);
181     }
182 
183     capture_levels_[i] = capture_level_out;
184     if (saturation_warning == 1) {
185       stream_is_saturated_ = true;
186     }
187   }
188 
189   if (mode_ == kAdaptiveAnalog) {
190     // Take the analog level to be the average across the handles.
191     analog_capture_level_ = 0;
192     for (int i = 0; i < num_handles(); i++) {
193       analog_capture_level_ += capture_levels_[i];
194     }
195 
196     analog_capture_level_ /= num_handles();
197   }
198 
199   was_analog_level_set_ = false;
200   return apm_->kNoError;
201 }
202 
203 // TODO(ajm): ensure this is called under kAdaptiveAnalog.
set_stream_analog_level(int level)204 int GainControlImpl::set_stream_analog_level(int level) {
205   was_analog_level_set_ = true;
206   if (level < minimum_capture_level_ || level > maximum_capture_level_) {
207     return apm_->kBadParameterError;
208   }
209 
210   if (mode_ == kAdaptiveAnalog) {
211     if (level != analog_capture_level_) {
212       // The analog level has been changed; update our internal levels.
213       capture_levels_.assign(num_handles(), level);
214     }
215   }
216   analog_capture_level_ = level;
217 
218   return apm_->kNoError;
219 }
220 
stream_analog_level()221 int GainControlImpl::stream_analog_level() {
222   // TODO(ajm): enable this assertion?
223   //assert(mode_ == kAdaptiveAnalog);
224 
225   return analog_capture_level_;
226 }
227 
Enable(bool enable)228 int GainControlImpl::Enable(bool enable) {
229   CriticalSectionScoped crit_scoped(*apm_->crit());
230   return EnableComponent(enable);
231 }
232 
is_enabled() const233 bool GainControlImpl::is_enabled() const {
234   return is_component_enabled();
235 }
236 
set_mode(Mode mode)237 int GainControlImpl::set_mode(Mode mode) {
238   CriticalSectionScoped crit_scoped(*apm_->crit());
239   if (MapSetting(mode) == -1) {
240     return apm_->kBadParameterError;
241   }
242 
243   mode_ = mode;
244   return Initialize();
245 }
246 
mode() const247 GainControl::Mode GainControlImpl::mode() const {
248   return mode_;
249 }
250 
set_analog_level_limits(int minimum,int maximum)251 int GainControlImpl::set_analog_level_limits(int minimum,
252                                              int maximum) {
253   CriticalSectionScoped crit_scoped(*apm_->crit());
254   if (minimum < 0) {
255     return apm_->kBadParameterError;
256   }
257 
258   if (maximum > 65535) {
259     return apm_->kBadParameterError;
260   }
261 
262   if (maximum < minimum) {
263     return apm_->kBadParameterError;
264   }
265 
266   minimum_capture_level_ = minimum;
267   maximum_capture_level_ = maximum;
268 
269   return Initialize();
270 }
271 
analog_level_minimum() const272 int GainControlImpl::analog_level_minimum() const {
273   return minimum_capture_level_;
274 }
275 
analog_level_maximum() const276 int GainControlImpl::analog_level_maximum() const {
277   return maximum_capture_level_;
278 }
279 
stream_is_saturated() const280 bool GainControlImpl::stream_is_saturated() const {
281   return stream_is_saturated_;
282 }
283 
set_target_level_dbfs(int level)284 int GainControlImpl::set_target_level_dbfs(int level) {
285   CriticalSectionScoped crit_scoped(*apm_->crit());
286   if (level > 31 || level < 0) {
287     return apm_->kBadParameterError;
288   }
289 
290   target_level_dbfs_ = level;
291   return Configure();
292 }
293 
target_level_dbfs() const294 int GainControlImpl::target_level_dbfs() const {
295   return target_level_dbfs_;
296 }
297 
set_compression_gain_db(int gain)298 int GainControlImpl::set_compression_gain_db(int gain) {
299   CriticalSectionScoped crit_scoped(*apm_->crit());
300   if (gain < 0 || gain > 90) {
301     return apm_->kBadParameterError;
302   }
303 
304   compression_gain_db_ = gain;
305   return Configure();
306 }
307 
compression_gain_db() const308 int GainControlImpl::compression_gain_db() const {
309   return compression_gain_db_;
310 }
311 
enable_limiter(bool enable)312 int GainControlImpl::enable_limiter(bool enable) {
313   CriticalSectionScoped crit_scoped(*apm_->crit());
314   limiter_enabled_ = enable;
315   return Configure();
316 }
317 
is_limiter_enabled() const318 bool GainControlImpl::is_limiter_enabled() const {
319   return limiter_enabled_;
320 }
321 
Initialize()322 int GainControlImpl::Initialize() {
323   int err = ProcessingComponent::Initialize();
324   if (err != apm_->kNoError || !is_component_enabled()) {
325     return err;
326   }
327 
328   analog_capture_level_ =
329       (maximum_capture_level_ - minimum_capture_level_) >> 1;
330   capture_levels_.assign(num_handles(), analog_capture_level_);
331   was_analog_level_set_ = false;
332 
333   return apm_->kNoError;
334 }
335 
get_version(char * version,int version_len_bytes) const336 int GainControlImpl::get_version(char* version, int version_len_bytes) const {
337   if (WebRtcAgc_Version(version, version_len_bytes) != 0) {
338       return apm_->kBadParameterError;
339   }
340 
341   return apm_->kNoError;
342 }
343 
CreateHandle() const344 void* GainControlImpl::CreateHandle() const {
345   Handle* handle = NULL;
346   if (WebRtcAgc_Create(&handle) != apm_->kNoError) {
347     handle = NULL;
348   } else {
349     assert(handle != NULL);
350   }
351 
352   return handle;
353 }
354 
DestroyHandle(void * handle) const355 int GainControlImpl::DestroyHandle(void* handle) const {
356   return WebRtcAgc_Free(static_cast<Handle*>(handle));
357 }
358 
InitializeHandle(void * handle) const359 int GainControlImpl::InitializeHandle(void* handle) const {
360   return WebRtcAgc_Init(static_cast<Handle*>(handle),
361                           minimum_capture_level_,
362                           maximum_capture_level_,
363                           MapSetting(mode_),
364                           apm_->sample_rate_hz());
365 }
366 
ConfigureHandle(void * handle) const367 int GainControlImpl::ConfigureHandle(void* handle) const {
368   WebRtcAgc_config_t config;
369   // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
370   //            change the interface.
371   //assert(target_level_dbfs_ <= 0);
372   //config.targetLevelDbfs = static_cast<WebRtc_Word16>(-target_level_dbfs_);
373   config.targetLevelDbfs = static_cast<WebRtc_Word16>(target_level_dbfs_);
374   config.compressionGaindB =
375       static_cast<WebRtc_Word16>(compression_gain_db_);
376   config.limiterEnable = limiter_enabled_;
377 
378   return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
379 }
380 
num_handles_required() const381 int GainControlImpl::num_handles_required() const {
382   return apm_->num_output_channels();
383 }
384 
GetHandleError(void * handle) const385 int GainControlImpl::GetHandleError(void* handle) const {
386   // The AGC has no get_error() function.
387   // (Despite listing errors in its interface...)
388   assert(handle != NULL);
389   return apm_->kUnspecifiedError;
390 }
391 }  // namespace webrtc
392