blob: d190284063cc1861f26175df90b5d7772a3fdc3f [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
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000011#include "webrtc/modules/audio_processing/gain_control_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
peahbfa97112016-03-10 21:09:04 -080013#include "webrtc/base/optional.h"
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000014#include "webrtc/modules/audio_processing/audio_buffer.h"
bjornv@webrtc.orgb395a5e2014-12-16 10:38:10 +000015#include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000016
niklase@google.com470e71d2011-07-07 08:21:25 +000017namespace webrtc {
18
19typedef void Handle;
20
niklase@google.com470e71d2011-07-07 08:21:25 +000021namespace {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000022int16_t MapSetting(GainControl::Mode mode) {
niklase@google.com470e71d2011-07-07 08:21:25 +000023 switch (mode) {
24 case GainControl::kAdaptiveAnalog:
25 return kAgcModeAdaptiveAnalog;
niklase@google.com470e71d2011-07-07 08:21:25 +000026 case GainControl::kAdaptiveDigital:
27 return kAgcModeAdaptiveDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000028 case GainControl::kFixedDigital:
29 return kAgcModeFixedDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000030 }
peahbfa97112016-03-10 21:09:04 -080031 RTC_DCHECK(false);
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000032 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000033}
niklase@google.com470e71d2011-07-07 08:21:25 +000034
peah2446e5a2015-11-18 06:11:13 -080035// Maximum length that a frame of samples can have.
36static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160;
37// Maximum number of frames to buffer in the render queue.
38// TODO(peah): Decrease this once we properly handle hugely unbalanced
39// reverse and forward call numbers.
40static const size_t kMaxNumFramesToBuffer = 100;
41
42} // namespace
peah4d291f72015-11-16 23:52:25 -080043
peahbfa97112016-03-10 21:09:04 -080044class GainControlImpl::GainController {
45 public:
46 explicit GainController() {
47 state_ = WebRtcAgc_Create();
48 RTC_CHECK(state_);
49 }
50
51 ~GainController() {
52 RTC_DCHECK(state_);
53 WebRtcAgc_Free(state_);
54 }
55
56 Handle* state() {
57 RTC_DCHECK(state_);
58 return state_;
59 }
60
61 void Initialize(int minimum_capture_level,
62 int maximum_capture_level,
63 Mode mode,
64 int sample_rate_hz,
65 int capture_level) {
66 RTC_DCHECK(state_);
67 int error =
68 WebRtcAgc_Init(state_, minimum_capture_level, maximum_capture_level,
69 MapSetting(mode), sample_rate_hz);
70 RTC_DCHECK_EQ(0, error);
71
72 set_capture_level(capture_level);
73 }
74
75 void set_capture_level(int capture_level) {
76 capture_level_ = rtc::Optional<int>(capture_level);
77 }
78
79 int get_capture_level() {
80 RTC_DCHECK(capture_level_);
81 return *capture_level_;
82 }
83
84 private:
85 Handle* state_;
86 // TODO(peah): Remove the optional once the initialization is moved into the
87 // ctor.
88 rtc::Optional<int> capture_level_;
89
90 RTC_DISALLOW_COPY_AND_ASSIGN(GainController);
91};
92
peahb8fbb542016-03-15 02:28:08 -070093GainControlImpl::GainControlImpl(rtc::CriticalSection* crit_render,
peahdf3efa82015-11-28 12:35:15 -080094 rtc::CriticalSection* crit_capture)
peahb8fbb542016-03-15 02:28:08 -070095 : crit_render_(crit_render),
peahdf3efa82015-11-28 12:35:15 -080096 crit_capture_(crit_capture),
peah4d291f72015-11-16 23:52:25 -080097 mode_(kAdaptiveAnalog),
98 minimum_capture_level_(0),
99 maximum_capture_level_(255),
100 limiter_enabled_(true),
101 target_level_dbfs_(3),
102 compression_gain_db_(9),
103 analog_capture_level_(0),
104 was_analog_level_set_(false),
105 stream_is_saturated_(false),
peahdf3efa82015-11-28 12:35:15 -0800106 render_queue_element_max_size_(0) {
peahdf3efa82015-11-28 12:35:15 -0800107 RTC_DCHECK(crit_render);
108 RTC_DCHECK(crit_capture);
109}
niklase@google.com470e71d2011-07-07 08:21:25 +0000110
111GainControlImpl::~GainControlImpl() {}
112
113int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800114 rtc::CritScope cs(crit_render_);
peahbfa97112016-03-10 21:09:04 -0800115 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800116 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 }
118
peahbfa97112016-03-10 21:09:04 -0800119 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000120
peah4d291f72015-11-16 23:52:25 -0800121 render_queue_buffer_.resize(0);
peahbfa97112016-03-10 21:09:04 -0800122 for (auto& gain_controller : gain_controllers_) {
123 int err = WebRtcAgc_GetAddFarendError(gain_controller->state(),
124 audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000125
peahbfa97112016-03-10 21:09:04 -0800126 if (err != AudioProcessing::kNoError) {
127 return AudioProcessing::kUnspecifiedError;
128 }
peah4d291f72015-11-16 23:52:25 -0800129
130 // Buffer the samples in the render queue.
131 render_queue_buffer_.insert(
132 render_queue_buffer_.end(), audio->mixed_low_pass_data(),
133 (audio->mixed_low_pass_data() + audio->num_frames_per_band()));
134 }
135
136 // Insert the samples into the queue.
137 if (!render_signal_queue_->Insert(&render_queue_buffer_)) {
peahdf3efa82015-11-28 12:35:15 -0800138 // The data queue is full and needs to be emptied.
peah4d291f72015-11-16 23:52:25 -0800139 ReadQueuedRenderData();
140
141 // Retry the insert (should always work).
142 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 }
144
peahdf3efa82015-11-28 12:35:15 -0800145 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000146}
147
peah4d291f72015-11-16 23:52:25 -0800148// Read chunks of data that were received and queued on the render side from
149// a queue. All the data chunks are buffered into the farend signal of the AGC.
150void GainControlImpl::ReadQueuedRenderData() {
peahdf3efa82015-11-28 12:35:15 -0800151 rtc::CritScope cs(crit_capture_);
152
peahbfa97112016-03-10 21:09:04 -0800153 if (!enabled_) {
peah4d291f72015-11-16 23:52:25 -0800154 return;
155 }
156
157 while (render_signal_queue_->Remove(&capture_queue_buffer_)) {
pkasting25702cb2016-01-08 13:50:27 -0800158 size_t buffer_index = 0;
peahb8fbb542016-03-15 02:28:08 -0700159 RTC_DCHECK(num_proc_channels_);
160 RTC_DCHECK_LT(0ul, *num_proc_channels_);
pkasting25702cb2016-01-08 13:50:27 -0800161 const size_t num_frames_per_band =
peahb8fbb542016-03-15 02:28:08 -0700162 capture_queue_buffer_.size() / (*num_proc_channels_);
peahbfa97112016-03-10 21:09:04 -0800163 for (auto& gain_controller : gain_controllers_) {
164 WebRtcAgc_AddFarend(gain_controller->state(),
165 &capture_queue_buffer_[buffer_index],
peah4d291f72015-11-16 23:52:25 -0800166 num_frames_per_band);
167
168 buffer_index += num_frames_per_band;
169 }
170 }
171}
172
niklase@google.com470e71d2011-07-07 08:21:25 +0000173int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800174 rtc::CritScope cs(crit_capture_);
175
peahbfa97112016-03-10 21:09:04 -0800176 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800177 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000178 }
179
peahb8fbb542016-03-15 02:28:08 -0700180 RTC_DCHECK(num_proc_channels_);
peahbfa97112016-03-10 21:09:04 -0800181 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
peahb8fbb542016-03-15 02:28:08 -0700182 RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
183 RTC_DCHECK_LE(*num_proc_channels_, gain_controllers_.size());
niklase@google.com470e71d2011-07-07 08:21:25 +0000184
185 if (mode_ == kAdaptiveAnalog) {
peahbfa97112016-03-10 21:09:04 -0800186 int capture_channel = 0;
187 for (auto& gain_controller : gain_controllers_) {
188 gain_controller->set_capture_level(analog_capture_level_);
189 int err = WebRtcAgc_AddMic(
190 gain_controller->state(), audio->split_bands(capture_channel),
191 audio->num_bands(), audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000192
peahdf3efa82015-11-28 12:35:15 -0800193 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-10 21:09:04 -0800194 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 }
peahbfa97112016-03-10 21:09:04 -0800196 ++capture_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 }
198 } else if (mode_ == kAdaptiveDigital) {
peahbfa97112016-03-10 21:09:04 -0800199 int capture_channel = 0;
200 for (auto& gain_controller : gain_controllers_) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000201 int32_t capture_level_out = 0;
peahbfa97112016-03-10 21:09:04 -0800202 int err = WebRtcAgc_VirtualMic(
203 gain_controller->state(), audio->split_bands(capture_channel),
204 audio->num_bands(), audio->num_frames_per_band(),
205 analog_capture_level_, &capture_level_out);
niklase@google.com470e71d2011-07-07 08:21:25 +0000206
peahbfa97112016-03-10 21:09:04 -0800207 gain_controller->set_capture_level(capture_level_out);
niklase@google.com470e71d2011-07-07 08:21:25 +0000208
peahdf3efa82015-11-28 12:35:15 -0800209 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-10 21:09:04 -0800210 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000211 }
peahbfa97112016-03-10 21:09:04 -0800212 ++capture_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000213 }
214 }
215
peahdf3efa82015-11-28 12:35:15 -0800216 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000217}
218
peahb8fbb542016-03-15 02:28:08 -0700219int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
220 bool stream_has_echo) {
peahdf3efa82015-11-28 12:35:15 -0800221 rtc::CritScope cs(crit_capture_);
222
peahbfa97112016-03-10 21:09:04 -0800223 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800224 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000225 }
226
227 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
peahdf3efa82015-11-28 12:35:15 -0800228 return AudioProcessing::kStreamParameterNotSetError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000229 }
230
peahb8fbb542016-03-15 02:28:08 -0700231 RTC_DCHECK(num_proc_channels_);
peahbfa97112016-03-10 21:09:04 -0800232 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
peahb8fbb542016-03-15 02:28:08 -0700233 RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000234
235 stream_is_saturated_ = false;
peahbfa97112016-03-10 21:09:04 -0800236 int capture_channel = 0;
237 for (auto& gain_controller : gain_controllers_) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000238 int32_t capture_level_out = 0;
239 uint8_t saturation_warning = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000240
peahdf3efa82015-11-28 12:35:15 -0800241 // The call to stream_has_echo() is ok from a deadlock perspective
242 // as the capture lock is allready held.
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 int err = WebRtcAgc_Process(
peahbfa97112016-03-10 21:09:04 -0800244 gain_controller->state(), audio->split_bands_const(capture_channel),
245 audio->num_bands(), audio->num_frames_per_band(),
246 audio->split_bands(capture_channel),
247 gain_controller->get_capture_level(), &capture_level_out,
peahb8fbb542016-03-15 02:28:08 -0700248 stream_has_echo, &saturation_warning);
niklase@google.com470e71d2011-07-07 08:21:25 +0000249
peahdf3efa82015-11-28 12:35:15 -0800250 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-10 21:09:04 -0800251 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 }
253
peahbfa97112016-03-10 21:09:04 -0800254 gain_controller->set_capture_level(capture_level_out);
niklase@google.com470e71d2011-07-07 08:21:25 +0000255 if (saturation_warning == 1) {
256 stream_is_saturated_ = true;
257 }
peahbfa97112016-03-10 21:09:04 -0800258
259 ++capture_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 }
261
peahb8fbb542016-03-15 02:28:08 -0700262 RTC_DCHECK_LT(0ul, *num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 if (mode_ == kAdaptiveAnalog) {
264 // Take the analog level to be the average across the handles.
265 analog_capture_level_ = 0;
peahbfa97112016-03-10 21:09:04 -0800266 for (auto& gain_controller : gain_controllers_) {
267 analog_capture_level_ += gain_controller->get_capture_level();
niklase@google.com470e71d2011-07-07 08:21:25 +0000268 }
269
peahb8fbb542016-03-15 02:28:08 -0700270 analog_capture_level_ /= (*num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000271 }
272
273 was_analog_level_set_ = false;
peahdf3efa82015-11-28 12:35:15 -0800274 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275}
276
277// TODO(ajm): ensure this is called under kAdaptiveAnalog.
278int GainControlImpl::set_stream_analog_level(int level) {
peahdf3efa82015-11-28 12:35:15 -0800279 rtc::CritScope cs(crit_capture_);
280
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 was_analog_level_set_ = true;
282 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
peahdf3efa82015-11-28 12:35:15 -0800283 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000284 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 analog_capture_level_ = level;
286
peahdf3efa82015-11-28 12:35:15 -0800287 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000288}
289
290int GainControlImpl::stream_analog_level() {
peahdf3efa82015-11-28 12:35:15 -0800291 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000292 // TODO(ajm): enable this assertion?
293 //assert(mode_ == kAdaptiveAnalog);
294
295 return analog_capture_level_;
296}
297
298int GainControlImpl::Enable(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800299 rtc::CritScope cs_render(crit_render_);
300 rtc::CritScope cs_capture(crit_capture_);
peahbfa97112016-03-10 21:09:04 -0800301 if (enable && !enabled_) {
302 enabled_ = enable; // Must be set before Initialize() is called.
peahb8fbb542016-03-15 02:28:08 -0700303
304 RTC_DCHECK(num_proc_channels_);
305 RTC_DCHECK(sample_rate_hz_);
306 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-10 21:09:04 -0800307 } else {
308 enabled_ = enable;
309 }
310 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000311}
312
313bool GainControlImpl::is_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800314 rtc::CritScope cs(crit_capture_);
peahbfa97112016-03-10 21:09:04 -0800315 return enabled_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000316}
317
318int GainControlImpl::set_mode(Mode mode) {
peahdf3efa82015-11-28 12:35:15 -0800319 rtc::CritScope cs_render(crit_render_);
320 rtc::CritScope cs_capture(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 if (MapSetting(mode) == -1) {
peahdf3efa82015-11-28 12:35:15 -0800322 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000323 }
324
325 mode_ = mode;
peahb8fbb542016-03-15 02:28:08 -0700326 RTC_DCHECK(num_proc_channels_);
327 RTC_DCHECK(sample_rate_hz_);
328 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-10 21:09:04 -0800329 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000330}
331
332GainControl::Mode GainControlImpl::mode() const {
peahdf3efa82015-11-28 12:35:15 -0800333 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000334 return mode_;
335}
336
337int GainControlImpl::set_analog_level_limits(int minimum,
338 int maximum) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000339 if (minimum < 0) {
peahdf3efa82015-11-28 12:35:15 -0800340 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000341 }
342
343 if (maximum > 65535) {
peahdf3efa82015-11-28 12:35:15 -0800344 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 }
346
347 if (maximum < minimum) {
peahdf3efa82015-11-28 12:35:15 -0800348 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000349 }
350
peah7c931ad2016-03-24 12:52:02 -0700351 size_t num_proc_channels_local = 0u;
352 int sample_rate_hz_local = 0;
353 {
354 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000355
peah7c931ad2016-03-24 12:52:02 -0700356 minimum_capture_level_ = minimum;
357 maximum_capture_level_ = maximum;
358
359 RTC_DCHECK(num_proc_channels_);
360 RTC_DCHECK(sample_rate_hz_);
361 num_proc_channels_local = *num_proc_channels_;
362 sample_rate_hz_local = *sample_rate_hz_;
363 }
364 Initialize(num_proc_channels_local, sample_rate_hz_local);
peahbfa97112016-03-10 21:09:04 -0800365 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000366}
367
368int GainControlImpl::analog_level_minimum() const {
peahdf3efa82015-11-28 12:35:15 -0800369 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 return minimum_capture_level_;
371}
372
373int GainControlImpl::analog_level_maximum() const {
peahdf3efa82015-11-28 12:35:15 -0800374 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000375 return maximum_capture_level_;
376}
377
378bool GainControlImpl::stream_is_saturated() const {
peahdf3efa82015-11-28 12:35:15 -0800379 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000380 return stream_is_saturated_;
381}
382
383int GainControlImpl::set_target_level_dbfs(int level) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 if (level > 31 || level < 0) {
peahdf3efa82015-11-28 12:35:15 -0800385 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 }
peahbfa97112016-03-10 21:09:04 -0800387 {
388 rtc::CritScope cs(crit_capture_);
389 target_level_dbfs_ = level;
390 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 return Configure();
392}
393
394int GainControlImpl::target_level_dbfs() const {
peahdf3efa82015-11-28 12:35:15 -0800395 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000396 return target_level_dbfs_;
397}
398
399int GainControlImpl::set_compression_gain_db(int gain) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 if (gain < 0 || gain > 90) {
peahdf3efa82015-11-28 12:35:15 -0800401 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 }
peahbfa97112016-03-10 21:09:04 -0800403 {
404 rtc::CritScope cs(crit_capture_);
405 compression_gain_db_ = gain;
406 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 return Configure();
408}
409
410int GainControlImpl::compression_gain_db() const {
peahdf3efa82015-11-28 12:35:15 -0800411 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000412 return compression_gain_db_;
413}
414
415int GainControlImpl::enable_limiter(bool enable) {
peahbfa97112016-03-10 21:09:04 -0800416 {
417 rtc::CritScope cs(crit_capture_);
418 limiter_enabled_ = enable;
419 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000420 return Configure();
421}
422
423bool GainControlImpl::is_limiter_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800424 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 return limiter_enabled_;
426}
427
peahb8fbb542016-03-15 02:28:08 -0700428void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
peahbfa97112016-03-10 21:09:04 -0800429 rtc::CritScope cs_render(crit_render_);
430 rtc::CritScope cs_capture(crit_capture_);
peahb8fbb542016-03-15 02:28:08 -0700431
432 num_proc_channels_ = rtc::Optional<size_t>(num_proc_channels);
433 sample_rate_hz_ = rtc::Optional<int>(sample_rate_hz);
434
peahbfa97112016-03-10 21:09:04 -0800435 if (!enabled_) {
436 return;
niklase@google.com470e71d2011-07-07 08:21:25 +0000437 }
438
peahb8fbb542016-03-15 02:28:08 -0700439 gain_controllers_.resize(*num_proc_channels_);
peahbfa97112016-03-10 21:09:04 -0800440 for (auto& gain_controller : gain_controllers_) {
441 if (!gain_controller) {
442 gain_controller.reset(new GainController());
443 }
444 gain_controller->Initialize(minimum_capture_level_, maximum_capture_level_,
peahb8fbb542016-03-15 02:28:08 -0700445 mode_, *sample_rate_hz_, analog_capture_level_);
peahbfa97112016-03-10 21:09:04 -0800446 }
447
448 Configure();
449
peah4d291f72015-11-16 23:52:25 -0800450 AllocateRenderQueue();
niklase@google.com470e71d2011-07-07 08:21:25 +0000451}
452
peah4d291f72015-11-16 23:52:25 -0800453void GainControlImpl::AllocateRenderQueue() {
peahdf3efa82015-11-28 12:35:15 -0800454 rtc::CritScope cs_render(crit_render_);
455 rtc::CritScope cs_capture(crit_capture_);
456
peahb8fbb542016-03-15 02:28:08 -0700457 RTC_DCHECK(num_proc_channels_);
458 const size_t new_render_queue_element_max_size = std::max<size_t>(
459 static_cast<size_t>(1),
460 kMaxAllowedValuesOfSamplesPerFrame * (*num_proc_channels_));
461
peah2446e5a2015-11-18 06:11:13 -0800462 if (render_queue_element_max_size_ < new_render_queue_element_max_size) {
463 render_queue_element_max_size_ = new_render_queue_element_max_size;
peah4d291f72015-11-16 23:52:25 -0800464 std::vector<int16_t> template_queue_element(render_queue_element_max_size_);
465
466 render_signal_queue_.reset(
467 new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>(
468 kMaxNumFramesToBuffer, template_queue_element,
469 RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_)));
peah2446e5a2015-11-18 06:11:13 -0800470
471 render_queue_buffer_.resize(render_queue_element_max_size_);
472 capture_queue_buffer_.resize(render_queue_element_max_size_);
peah4d291f72015-11-16 23:52:25 -0800473 } else {
474 render_signal_queue_->Clear();
475 }
peah4d291f72015-11-16 23:52:25 -0800476}
477
peahbfa97112016-03-10 21:09:04 -0800478int GainControlImpl::Configure() {
peahdf3efa82015-11-28 12:35:15 -0800479 rtc::CritScope cs_render(crit_render_);
480 rtc::CritScope cs_capture(crit_capture_);
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000481 WebRtcAgcConfig config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000482 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
483 // change the interface.
484 //assert(target_level_dbfs_ <= 0);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000485 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
486 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000487 config.compressionGaindB =
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000488 static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000489 config.limiterEnable = limiter_enabled_;
490
peahbfa97112016-03-10 21:09:04 -0800491 int error = AudioProcessing::kNoError;
492 for (auto& gain_controller : gain_controllers_) {
493 const int handle_error =
494 WebRtcAgc_set_config(gain_controller->state(), config);
495 if (handle_error != AudioProcessing::kNoError) {
496 error = handle_error;
497 }
498 }
499 return error;
niklase@google.com470e71d2011-07-07 08:21:25 +0000500}
niklase@google.com470e71d2011-07-07 08:21:25 +0000501} // namespace webrtc