blob: 9f381d26f167b4efecebb71bf24cc60ca1605763 [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
kwiberg4485ffb2016-04-26 08:14:39 -070013#include "webrtc/base/constructormagic.h"
peahbfa97112016-03-10 21:09:04 -080014#include "webrtc/base/optional.h"
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000015#include "webrtc/modules/audio_processing/audio_buffer.h"
bjornv@webrtc.orgb395a5e2014-12-16 10:38:10 +000016#include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000017
niklase@google.com470e71d2011-07-07 08:21:25 +000018namespace webrtc {
19
20typedef void Handle;
21
niklase@google.com470e71d2011-07-07 08:21:25 +000022namespace {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000023int16_t MapSetting(GainControl::Mode mode) {
niklase@google.com470e71d2011-07-07 08:21:25 +000024 switch (mode) {
25 case GainControl::kAdaptiveAnalog:
26 return kAgcModeAdaptiveAnalog;
niklase@google.com470e71d2011-07-07 08:21:25 +000027 case GainControl::kAdaptiveDigital:
28 return kAgcModeAdaptiveDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000029 case GainControl::kFixedDigital:
30 return kAgcModeFixedDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000031 }
peahbfa97112016-03-10 21:09:04 -080032 RTC_DCHECK(false);
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000033 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000034}
niklase@google.com470e71d2011-07-07 08:21:25 +000035
peah2446e5a2015-11-18 06:11:13 -080036// Maximum length that a frame of samples can have.
37static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160;
38// Maximum number of frames to buffer in the render queue.
39// TODO(peah): Decrease this once we properly handle hugely unbalanced
40// reverse and forward call numbers.
41static const size_t kMaxNumFramesToBuffer = 100;
42
43} // namespace
peah4d291f72015-11-16 23:52:25 -080044
peahbfa97112016-03-10 21:09:04 -080045class GainControlImpl::GainController {
46 public:
47 explicit GainController() {
48 state_ = WebRtcAgc_Create();
49 RTC_CHECK(state_);
50 }
51
52 ~GainController() {
53 RTC_DCHECK(state_);
54 WebRtcAgc_Free(state_);
55 }
56
57 Handle* state() {
58 RTC_DCHECK(state_);
59 return state_;
60 }
61
62 void Initialize(int minimum_capture_level,
63 int maximum_capture_level,
64 Mode mode,
65 int sample_rate_hz,
66 int capture_level) {
67 RTC_DCHECK(state_);
68 int error =
69 WebRtcAgc_Init(state_, minimum_capture_level, maximum_capture_level,
70 MapSetting(mode), sample_rate_hz);
71 RTC_DCHECK_EQ(0, error);
72
73 set_capture_level(capture_level);
74 }
75
76 void set_capture_level(int capture_level) {
77 capture_level_ = rtc::Optional<int>(capture_level);
78 }
79
80 int get_capture_level() {
81 RTC_DCHECK(capture_level_);
82 return *capture_level_;
83 }
84
85 private:
86 Handle* state_;
87 // TODO(peah): Remove the optional once the initialization is moved into the
88 // ctor.
89 rtc::Optional<int> capture_level_;
90
91 RTC_DISALLOW_COPY_AND_ASSIGN(GainController);
92};
93
peahb8fbb542016-03-15 02:28:08 -070094GainControlImpl::GainControlImpl(rtc::CriticalSection* crit_render,
peahdf3efa82015-11-28 12:35:15 -080095 rtc::CriticalSection* crit_capture)
peahb8fbb542016-03-15 02:28:08 -070096 : crit_render_(crit_render),
peahdf3efa82015-11-28 12:35:15 -080097 crit_capture_(crit_capture),
peah4d291f72015-11-16 23:52:25 -080098 mode_(kAdaptiveAnalog),
99 minimum_capture_level_(0),
100 maximum_capture_level_(255),
101 limiter_enabled_(true),
102 target_level_dbfs_(3),
103 compression_gain_db_(9),
104 analog_capture_level_(0),
105 was_analog_level_set_(false),
106 stream_is_saturated_(false),
peahdf3efa82015-11-28 12:35:15 -0800107 render_queue_element_max_size_(0) {
peahdf3efa82015-11-28 12:35:15 -0800108 RTC_DCHECK(crit_render);
109 RTC_DCHECK(crit_capture);
110}
niklase@google.com470e71d2011-07-07 08:21:25 +0000111
112GainControlImpl::~GainControlImpl() {}
113
114int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800115 rtc::CritScope cs(crit_render_);
peahbfa97112016-03-10 21:09:04 -0800116 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800117 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 }
119
peahbfa97112016-03-10 21:09:04 -0800120 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000121
peah4d291f72015-11-16 23:52:25 -0800122 render_queue_buffer_.resize(0);
peahbfa97112016-03-10 21:09:04 -0800123 for (auto& gain_controller : gain_controllers_) {
124 int err = WebRtcAgc_GetAddFarendError(gain_controller->state(),
125 audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000126
peahbfa97112016-03-10 21:09:04 -0800127 if (err != AudioProcessing::kNoError) {
128 return AudioProcessing::kUnspecifiedError;
129 }
peah4d291f72015-11-16 23:52:25 -0800130
131 // Buffer the samples in the render queue.
132 render_queue_buffer_.insert(
133 render_queue_buffer_.end(), audio->mixed_low_pass_data(),
134 (audio->mixed_low_pass_data() + audio->num_frames_per_band()));
135 }
136
137 // Insert the samples into the queue.
138 if (!render_signal_queue_->Insert(&render_queue_buffer_)) {
peahdf3efa82015-11-28 12:35:15 -0800139 // The data queue is full and needs to be emptied.
peah4d291f72015-11-16 23:52:25 -0800140 ReadQueuedRenderData();
141
142 // Retry the insert (should always work).
143 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true);
niklase@google.com470e71d2011-07-07 08:21:25 +0000144 }
145
peahdf3efa82015-11-28 12:35:15 -0800146 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000147}
148
peah4d291f72015-11-16 23:52:25 -0800149// Read chunks of data that were received and queued on the render side from
150// a queue. All the data chunks are buffered into the farend signal of the AGC.
151void GainControlImpl::ReadQueuedRenderData() {
peahdf3efa82015-11-28 12:35:15 -0800152 rtc::CritScope cs(crit_capture_);
153
peahbfa97112016-03-10 21:09:04 -0800154 if (!enabled_) {
peah4d291f72015-11-16 23:52:25 -0800155 return;
156 }
157
158 while (render_signal_queue_->Remove(&capture_queue_buffer_)) {
pkasting25702cb2016-01-08 13:50:27 -0800159 size_t buffer_index = 0;
peahb8fbb542016-03-15 02:28:08 -0700160 RTC_DCHECK(num_proc_channels_);
161 RTC_DCHECK_LT(0ul, *num_proc_channels_);
pkasting25702cb2016-01-08 13:50:27 -0800162 const size_t num_frames_per_band =
peahb8fbb542016-03-15 02:28:08 -0700163 capture_queue_buffer_.size() / (*num_proc_channels_);
peahbfa97112016-03-10 21:09:04 -0800164 for (auto& gain_controller : gain_controllers_) {
165 WebRtcAgc_AddFarend(gain_controller->state(),
166 &capture_queue_buffer_[buffer_index],
peah4d291f72015-11-16 23:52:25 -0800167 num_frames_per_band);
168
169 buffer_index += num_frames_per_band;
170 }
171 }
172}
173
niklase@google.com470e71d2011-07-07 08:21:25 +0000174int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800175 rtc::CritScope cs(crit_capture_);
176
peahbfa97112016-03-10 21:09:04 -0800177 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800178 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000179 }
180
peahb8fbb542016-03-15 02:28:08 -0700181 RTC_DCHECK(num_proc_channels_);
peahbfa97112016-03-10 21:09:04 -0800182 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
peahb8fbb542016-03-15 02:28:08 -0700183 RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
184 RTC_DCHECK_LE(*num_proc_channels_, gain_controllers_.size());
niklase@google.com470e71d2011-07-07 08:21:25 +0000185
186 if (mode_ == kAdaptiveAnalog) {
peahbfa97112016-03-10 21:09:04 -0800187 int capture_channel = 0;
188 for (auto& gain_controller : gain_controllers_) {
189 gain_controller->set_capture_level(analog_capture_level_);
190 int err = WebRtcAgc_AddMic(
191 gain_controller->state(), audio->split_bands(capture_channel),
192 audio->num_bands(), audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000193
peahdf3efa82015-11-28 12:35:15 -0800194 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-10 21:09:04 -0800195 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000196 }
peahbfa97112016-03-10 21:09:04 -0800197 ++capture_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 }
199 } else if (mode_ == kAdaptiveDigital) {
peahbfa97112016-03-10 21:09:04 -0800200 int capture_channel = 0;
201 for (auto& gain_controller : gain_controllers_) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000202 int32_t capture_level_out = 0;
peahbfa97112016-03-10 21:09:04 -0800203 int err = WebRtcAgc_VirtualMic(
204 gain_controller->state(), audio->split_bands(capture_channel),
205 audio->num_bands(), audio->num_frames_per_band(),
206 analog_capture_level_, &capture_level_out);
niklase@google.com470e71d2011-07-07 08:21:25 +0000207
peahbfa97112016-03-10 21:09:04 -0800208 gain_controller->set_capture_level(capture_level_out);
niklase@google.com470e71d2011-07-07 08:21:25 +0000209
peahdf3efa82015-11-28 12:35:15 -0800210 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-10 21:09:04 -0800211 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 }
peahbfa97112016-03-10 21:09:04 -0800213 ++capture_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 }
215 }
216
peahdf3efa82015-11-28 12:35:15 -0800217 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000218}
219
peahb8fbb542016-03-15 02:28:08 -0700220int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
221 bool stream_has_echo) {
peahdf3efa82015-11-28 12:35:15 -0800222 rtc::CritScope cs(crit_capture_);
223
peahbfa97112016-03-10 21:09:04 -0800224 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800225 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000226 }
227
228 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
peahdf3efa82015-11-28 12:35:15 -0800229 return AudioProcessing::kStreamParameterNotSetError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000230 }
231
peahb8fbb542016-03-15 02:28:08 -0700232 RTC_DCHECK(num_proc_channels_);
peahbfa97112016-03-10 21:09:04 -0800233 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
peahb8fbb542016-03-15 02:28:08 -0700234 RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000235
236 stream_is_saturated_ = false;
peahbfa97112016-03-10 21:09:04 -0800237 int capture_channel = 0;
238 for (auto& gain_controller : gain_controllers_) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000239 int32_t capture_level_out = 0;
240 uint8_t saturation_warning = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000241
peahdf3efa82015-11-28 12:35:15 -0800242 // The call to stream_has_echo() is ok from a deadlock perspective
243 // as the capture lock is allready held.
niklase@google.com470e71d2011-07-07 08:21:25 +0000244 int err = WebRtcAgc_Process(
peahbfa97112016-03-10 21:09:04 -0800245 gain_controller->state(), audio->split_bands_const(capture_channel),
246 audio->num_bands(), audio->num_frames_per_band(),
247 audio->split_bands(capture_channel),
248 gain_controller->get_capture_level(), &capture_level_out,
peahb8fbb542016-03-15 02:28:08 -0700249 stream_has_echo, &saturation_warning);
niklase@google.com470e71d2011-07-07 08:21:25 +0000250
peahdf3efa82015-11-28 12:35:15 -0800251 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-10 21:09:04 -0800252 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 }
254
peahbfa97112016-03-10 21:09:04 -0800255 gain_controller->set_capture_level(capture_level_out);
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 if (saturation_warning == 1) {
257 stream_is_saturated_ = true;
258 }
peahbfa97112016-03-10 21:09:04 -0800259
260 ++capture_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000261 }
262
peahb8fbb542016-03-15 02:28:08 -0700263 RTC_DCHECK_LT(0ul, *num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000264 if (mode_ == kAdaptiveAnalog) {
265 // Take the analog level to be the average across the handles.
266 analog_capture_level_ = 0;
peahbfa97112016-03-10 21:09:04 -0800267 for (auto& gain_controller : gain_controllers_) {
268 analog_capture_level_ += gain_controller->get_capture_level();
niklase@google.com470e71d2011-07-07 08:21:25 +0000269 }
270
peahb8fbb542016-03-15 02:28:08 -0700271 analog_capture_level_ /= (*num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000272 }
273
274 was_analog_level_set_ = false;
peahdf3efa82015-11-28 12:35:15 -0800275 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000276}
277
278// TODO(ajm): ensure this is called under kAdaptiveAnalog.
279int GainControlImpl::set_stream_analog_level(int level) {
peahdf3efa82015-11-28 12:35:15 -0800280 rtc::CritScope cs(crit_capture_);
281
niklase@google.com470e71d2011-07-07 08:21:25 +0000282 was_analog_level_set_ = true;
283 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
peahdf3efa82015-11-28 12:35:15 -0800284 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000286 analog_capture_level_ = level;
287
peahdf3efa82015-11-28 12:35:15 -0800288 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000289}
290
291int GainControlImpl::stream_analog_level() {
peahdf3efa82015-11-28 12:35:15 -0800292 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000293 // TODO(ajm): enable this assertion?
294 //assert(mode_ == kAdaptiveAnalog);
295
296 return analog_capture_level_;
297}
298
299int GainControlImpl::Enable(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800300 rtc::CritScope cs_render(crit_render_);
301 rtc::CritScope cs_capture(crit_capture_);
peahbfa97112016-03-10 21:09:04 -0800302 if (enable && !enabled_) {
303 enabled_ = enable; // Must be set before Initialize() is called.
peahb8fbb542016-03-15 02:28:08 -0700304
305 RTC_DCHECK(num_proc_channels_);
306 RTC_DCHECK(sample_rate_hz_);
307 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-10 21:09:04 -0800308 } else {
309 enabled_ = enable;
310 }
311 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000312}
313
peahdc2242d2016-04-06 09:30:58 -0700314bool GainControlImpl::is_enabled_render_side_query() const {
315 // TODO(peah): Add threadchecker.
316 rtc::CritScope cs(crit_render_);
317 return enabled_;
318}
319
niklase@google.com470e71d2011-07-07 08:21:25 +0000320bool GainControlImpl::is_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800321 rtc::CritScope cs(crit_capture_);
peahbfa97112016-03-10 21:09:04 -0800322 return enabled_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000323}
324
325int GainControlImpl::set_mode(Mode mode) {
peahdf3efa82015-11-28 12:35:15 -0800326 rtc::CritScope cs_render(crit_render_);
327 rtc::CritScope cs_capture(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 if (MapSetting(mode) == -1) {
peahdf3efa82015-11-28 12:35:15 -0800329 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000330 }
331
332 mode_ = mode;
peahb8fbb542016-03-15 02:28:08 -0700333 RTC_DCHECK(num_proc_channels_);
334 RTC_DCHECK(sample_rate_hz_);
335 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-10 21:09:04 -0800336 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000337}
338
339GainControl::Mode GainControlImpl::mode() const {
peahdf3efa82015-11-28 12:35:15 -0800340 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000341 return mode_;
342}
343
344int GainControlImpl::set_analog_level_limits(int minimum,
345 int maximum) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000346 if (minimum < 0) {
peahdf3efa82015-11-28 12:35:15 -0800347 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000348 }
349
350 if (maximum > 65535) {
peahdf3efa82015-11-28 12:35:15 -0800351 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 }
353
354 if (maximum < minimum) {
peahdf3efa82015-11-28 12:35:15 -0800355 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000356 }
357
peah7c931ad2016-03-24 12:52:02 -0700358 size_t num_proc_channels_local = 0u;
359 int sample_rate_hz_local = 0;
360 {
361 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000362
peah7c931ad2016-03-24 12:52:02 -0700363 minimum_capture_level_ = minimum;
364 maximum_capture_level_ = maximum;
365
366 RTC_DCHECK(num_proc_channels_);
367 RTC_DCHECK(sample_rate_hz_);
368 num_proc_channels_local = *num_proc_channels_;
369 sample_rate_hz_local = *sample_rate_hz_;
370 }
371 Initialize(num_proc_channels_local, sample_rate_hz_local);
peahbfa97112016-03-10 21:09:04 -0800372 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000373}
374
375int GainControlImpl::analog_level_minimum() const {
peahdf3efa82015-11-28 12:35:15 -0800376 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000377 return minimum_capture_level_;
378}
379
380int GainControlImpl::analog_level_maximum() const {
peahdf3efa82015-11-28 12:35:15 -0800381 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000382 return maximum_capture_level_;
383}
384
385bool GainControlImpl::stream_is_saturated() const {
peahdf3efa82015-11-28 12:35:15 -0800386 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 return stream_is_saturated_;
388}
389
390int GainControlImpl::set_target_level_dbfs(int level) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 if (level > 31 || level < 0) {
peahdf3efa82015-11-28 12:35:15 -0800392 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 }
peahbfa97112016-03-10 21:09:04 -0800394 {
395 rtc::CritScope cs(crit_capture_);
396 target_level_dbfs_ = level;
397 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000398 return Configure();
399}
400
401int GainControlImpl::target_level_dbfs() const {
peahdf3efa82015-11-28 12:35:15 -0800402 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000403 return target_level_dbfs_;
404}
405
406int GainControlImpl::set_compression_gain_db(int gain) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 if (gain < 0 || gain > 90) {
peahdf3efa82015-11-28 12:35:15 -0800408 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000409 }
peahbfa97112016-03-10 21:09:04 -0800410 {
411 rtc::CritScope cs(crit_capture_);
412 compression_gain_db_ = gain;
413 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000414 return Configure();
415}
416
417int GainControlImpl::compression_gain_db() const {
peahdf3efa82015-11-28 12:35:15 -0800418 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000419 return compression_gain_db_;
420}
421
422int GainControlImpl::enable_limiter(bool enable) {
peahbfa97112016-03-10 21:09:04 -0800423 {
424 rtc::CritScope cs(crit_capture_);
425 limiter_enabled_ = enable;
426 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000427 return Configure();
428}
429
430bool GainControlImpl::is_limiter_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800431 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000432 return limiter_enabled_;
433}
434
peahb8fbb542016-03-15 02:28:08 -0700435void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
peahbfa97112016-03-10 21:09:04 -0800436 rtc::CritScope cs_render(crit_render_);
437 rtc::CritScope cs_capture(crit_capture_);
peahb8fbb542016-03-15 02:28:08 -0700438
439 num_proc_channels_ = rtc::Optional<size_t>(num_proc_channels);
440 sample_rate_hz_ = rtc::Optional<int>(sample_rate_hz);
441
peahbfa97112016-03-10 21:09:04 -0800442 if (!enabled_) {
443 return;
niklase@google.com470e71d2011-07-07 08:21:25 +0000444 }
445
peahb8fbb542016-03-15 02:28:08 -0700446 gain_controllers_.resize(*num_proc_channels_);
peahbfa97112016-03-10 21:09:04 -0800447 for (auto& gain_controller : gain_controllers_) {
448 if (!gain_controller) {
449 gain_controller.reset(new GainController());
450 }
451 gain_controller->Initialize(minimum_capture_level_, maximum_capture_level_,
peahb8fbb542016-03-15 02:28:08 -0700452 mode_, *sample_rate_hz_, analog_capture_level_);
peahbfa97112016-03-10 21:09:04 -0800453 }
454
455 Configure();
456
peah4d291f72015-11-16 23:52:25 -0800457 AllocateRenderQueue();
niklase@google.com470e71d2011-07-07 08:21:25 +0000458}
459
peah4d291f72015-11-16 23:52:25 -0800460void GainControlImpl::AllocateRenderQueue() {
peahdf3efa82015-11-28 12:35:15 -0800461 rtc::CritScope cs_render(crit_render_);
462 rtc::CritScope cs_capture(crit_capture_);
463
peahb8fbb542016-03-15 02:28:08 -0700464 RTC_DCHECK(num_proc_channels_);
465 const size_t new_render_queue_element_max_size = std::max<size_t>(
466 static_cast<size_t>(1),
467 kMaxAllowedValuesOfSamplesPerFrame * (*num_proc_channels_));
468
peah2446e5a2015-11-18 06:11:13 -0800469 if (render_queue_element_max_size_ < new_render_queue_element_max_size) {
470 render_queue_element_max_size_ = new_render_queue_element_max_size;
peah4d291f72015-11-16 23:52:25 -0800471 std::vector<int16_t> template_queue_element(render_queue_element_max_size_);
472
473 render_signal_queue_.reset(
474 new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>(
475 kMaxNumFramesToBuffer, template_queue_element,
476 RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_)));
peah2446e5a2015-11-18 06:11:13 -0800477
478 render_queue_buffer_.resize(render_queue_element_max_size_);
479 capture_queue_buffer_.resize(render_queue_element_max_size_);
peah4d291f72015-11-16 23:52:25 -0800480 } else {
481 render_signal_queue_->Clear();
482 }
peah4d291f72015-11-16 23:52:25 -0800483}
484
peahbfa97112016-03-10 21:09:04 -0800485int GainControlImpl::Configure() {
peahdf3efa82015-11-28 12:35:15 -0800486 rtc::CritScope cs_render(crit_render_);
487 rtc::CritScope cs_capture(crit_capture_);
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000488 WebRtcAgcConfig config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000489 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
490 // change the interface.
491 //assert(target_level_dbfs_ <= 0);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000492 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
493 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000494 config.compressionGaindB =
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000495 static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000496 config.limiterEnable = limiter_enabled_;
497
peahbfa97112016-03-10 21:09:04 -0800498 int error = AudioProcessing::kNoError;
499 for (auto& gain_controller : gain_controllers_) {
500 const int handle_error =
501 WebRtcAgc_set_config(gain_controller->state(), config);
502 if (handle_error != AudioProcessing::kNoError) {
503 error = handle_error;
504 }
505 }
506 return error;
niklase@google.com470e71d2011-07-07 08:21:25 +0000507}
niklase@google.com470e71d2011-07-07 08:21:25 +0000508} // namespace webrtc