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
21namespace webrtc {
22
23typedef void Handle;
24
25/*template <class T>
26class 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
38namespace {
39WebRtc_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
56GainControlImpl::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
69GainControlImpl::~GainControlImpl() {}
70
71int 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
99int 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
149int 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.
204int 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
221int GainControlImpl::stream_analog_level() {
222  // TODO(ajm): enable this assertion?
223  //assert(mode_ == kAdaptiveAnalog);
224
225  return analog_capture_level_;
226}
227
228int GainControlImpl::Enable(bool enable) {
229  CriticalSectionScoped crit_scoped(*apm_->crit());
230  return EnableComponent(enable);
231}
232
233bool GainControlImpl::is_enabled() const {
234  return is_component_enabled();
235}
236
237int 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
247GainControl::Mode GainControlImpl::mode() const {
248  return mode_;
249}
250
251int 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
272int GainControlImpl::analog_level_minimum() const {
273  return minimum_capture_level_;
274}
275
276int GainControlImpl::analog_level_maximum() const {
277  return maximum_capture_level_;
278}
279
280bool GainControlImpl::stream_is_saturated() const {
281  return stream_is_saturated_;
282}
283
284int 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
294int GainControlImpl::target_level_dbfs() const {
295  return target_level_dbfs_;
296}
297
298int 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
308int GainControlImpl::compression_gain_db() const {
309  return compression_gain_db_;
310}
311
312int GainControlImpl::enable_limiter(bool enable) {
313  CriticalSectionScoped crit_scoped(*apm_->crit());
314  limiter_enabled_ = enable;
315  return Configure();
316}
317
318bool GainControlImpl::is_limiter_enabled() const {
319  return limiter_enabled_;
320}
321
322int 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
336int 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
344void* 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
355int GainControlImpl::DestroyHandle(void* handle) const {
356  return WebRtcAgc_Free(static_cast<Handle*>(handle));
357}
358
359int 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
367int 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
381int GainControlImpl::num_handles_required() const {
382  return apm_->num_output_channels();
383}
384
385int 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