blob: aa4316de28b67f1847c2d28e1222dddab9dba6de [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
aluebs11d4a422016-04-28 14:58:32 -0700278int GainControlImpl::compression_gain_db() const {
279 rtc::CritScope cs(crit_capture_);
280 return compression_gain_db_;
281}
282
niklase@google.com470e71d2011-07-07 08:21:25 +0000283// TODO(ajm): ensure this is called under kAdaptiveAnalog.
284int GainControlImpl::set_stream_analog_level(int level) {
peahdf3efa82015-11-28 12:35:15 -0800285 rtc::CritScope cs(crit_capture_);
286
niklase@google.com470e71d2011-07-07 08:21:25 +0000287 was_analog_level_set_ = true;
288 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
peahdf3efa82015-11-28 12:35:15 -0800289 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 analog_capture_level_ = level;
292
peahdf3efa82015-11-28 12:35:15 -0800293 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000294}
295
296int GainControlImpl::stream_analog_level() {
peahdf3efa82015-11-28 12:35:15 -0800297 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000298 // TODO(ajm): enable this assertion?
kwiberg9e2be5f2016-09-14 05:23:22 -0700299 //RTC_DCHECK_EQ(kAdaptiveAnalog, mode_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000300
301 return analog_capture_level_;
302}
303
304int GainControlImpl::Enable(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800305 rtc::CritScope cs_render(crit_render_);
306 rtc::CritScope cs_capture(crit_capture_);
peahbfa97112016-03-10 21:09:04 -0800307 if (enable && !enabled_) {
308 enabled_ = enable; // Must be set before Initialize() is called.
peahb8fbb542016-03-15 02:28:08 -0700309
310 RTC_DCHECK(num_proc_channels_);
311 RTC_DCHECK(sample_rate_hz_);
312 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-10 21:09:04 -0800313 } else {
314 enabled_ = enable;
315 }
316 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000317}
318
319bool GainControlImpl::is_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800320 rtc::CritScope cs(crit_capture_);
peahbfa97112016-03-10 21:09:04 -0800321 return enabled_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000322}
323
324int GainControlImpl::set_mode(Mode mode) {
peahdf3efa82015-11-28 12:35:15 -0800325 rtc::CritScope cs_render(crit_render_);
326 rtc::CritScope cs_capture(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000327 if (MapSetting(mode) == -1) {
peahdf3efa82015-11-28 12:35:15 -0800328 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000329 }
330
331 mode_ = mode;
peahb8fbb542016-03-15 02:28:08 -0700332 RTC_DCHECK(num_proc_channels_);
333 RTC_DCHECK(sample_rate_hz_);
334 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-10 21:09:04 -0800335 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000336}
337
338GainControl::Mode GainControlImpl::mode() const {
peahdf3efa82015-11-28 12:35:15 -0800339 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000340 return mode_;
341}
342
343int GainControlImpl::set_analog_level_limits(int minimum,
344 int maximum) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 if (minimum < 0) {
peahdf3efa82015-11-28 12:35:15 -0800346 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000347 }
348
349 if (maximum > 65535) {
peahdf3efa82015-11-28 12:35:15 -0800350 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000351 }
352
353 if (maximum < minimum) {
peahdf3efa82015-11-28 12:35:15 -0800354 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000355 }
356
peah7c931ad2016-03-24 12:52:02 -0700357 size_t num_proc_channels_local = 0u;
358 int sample_rate_hz_local = 0;
359 {
360 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000361
peah7c931ad2016-03-24 12:52:02 -0700362 minimum_capture_level_ = minimum;
363 maximum_capture_level_ = maximum;
364
365 RTC_DCHECK(num_proc_channels_);
366 RTC_DCHECK(sample_rate_hz_);
367 num_proc_channels_local = *num_proc_channels_;
368 sample_rate_hz_local = *sample_rate_hz_;
369 }
370 Initialize(num_proc_channels_local, sample_rate_hz_local);
peahbfa97112016-03-10 21:09:04 -0800371 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000372}
373
374int GainControlImpl::analog_level_minimum() const {
peahdf3efa82015-11-28 12:35:15 -0800375 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000376 return minimum_capture_level_;
377}
378
379int GainControlImpl::analog_level_maximum() const {
peahdf3efa82015-11-28 12:35:15 -0800380 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000381 return maximum_capture_level_;
382}
383
384bool GainControlImpl::stream_is_saturated() const {
peahdf3efa82015-11-28 12:35:15 -0800385 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 return stream_is_saturated_;
387}
388
389int GainControlImpl::set_target_level_dbfs(int level) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000390 if (level > 31 || level < 0) {
peahdf3efa82015-11-28 12:35:15 -0800391 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000392 }
peahbfa97112016-03-10 21:09:04 -0800393 {
394 rtc::CritScope cs(crit_capture_);
395 target_level_dbfs_ = level;
396 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 return Configure();
398}
399
400int GainControlImpl::target_level_dbfs() const {
peahdf3efa82015-11-28 12:35:15 -0800401 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 return target_level_dbfs_;
403}
404
405int GainControlImpl::set_compression_gain_db(int gain) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000406 if (gain < 0 || gain > 90) {
peahdf3efa82015-11-28 12:35:15 -0800407 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 }
peahbfa97112016-03-10 21:09:04 -0800409 {
410 rtc::CritScope cs(crit_capture_);
411 compression_gain_db_ = gain;
412 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 return Configure();
414}
415
niklase@google.com470e71d2011-07-07 08:21:25 +0000416int GainControlImpl::enable_limiter(bool enable) {
peahbfa97112016-03-10 21:09:04 -0800417 {
418 rtc::CritScope cs(crit_capture_);
419 limiter_enabled_ = enable;
420 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 return Configure();
422}
423
424bool GainControlImpl::is_limiter_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800425 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000426 return limiter_enabled_;
427}
428
peahb8fbb542016-03-15 02:28:08 -0700429void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
peahbfa97112016-03-10 21:09:04 -0800430 rtc::CritScope cs_render(crit_render_);
431 rtc::CritScope cs_capture(crit_capture_);
peahb8fbb542016-03-15 02:28:08 -0700432
433 num_proc_channels_ = rtc::Optional<size_t>(num_proc_channels);
434 sample_rate_hz_ = rtc::Optional<int>(sample_rate_hz);
435
peahbfa97112016-03-10 21:09:04 -0800436 if (!enabled_) {
437 return;
niklase@google.com470e71d2011-07-07 08:21:25 +0000438 }
439
peahb8fbb542016-03-15 02:28:08 -0700440 gain_controllers_.resize(*num_proc_channels_);
peahbfa97112016-03-10 21:09:04 -0800441 for (auto& gain_controller : gain_controllers_) {
442 if (!gain_controller) {
443 gain_controller.reset(new GainController());
444 }
445 gain_controller->Initialize(minimum_capture_level_, maximum_capture_level_,
peahb8fbb542016-03-15 02:28:08 -0700446 mode_, *sample_rate_hz_, analog_capture_level_);
peahbfa97112016-03-10 21:09:04 -0800447 }
448
449 Configure();
450
peah4d291f72015-11-16 23:52:25 -0800451 AllocateRenderQueue();
niklase@google.com470e71d2011-07-07 08:21:25 +0000452}
453
peah4d291f72015-11-16 23:52:25 -0800454void GainControlImpl::AllocateRenderQueue() {
peahdf3efa82015-11-28 12:35:15 -0800455 rtc::CritScope cs_render(crit_render_);
456 rtc::CritScope cs_capture(crit_capture_);
457
peahb8fbb542016-03-15 02:28:08 -0700458 RTC_DCHECK(num_proc_channels_);
459 const size_t new_render_queue_element_max_size = std::max<size_t>(
460 static_cast<size_t>(1),
461 kMaxAllowedValuesOfSamplesPerFrame * (*num_proc_channels_));
462
peah2446e5a2015-11-18 06:11:13 -0800463 if (render_queue_element_max_size_ < new_render_queue_element_max_size) {
464 render_queue_element_max_size_ = new_render_queue_element_max_size;
peah4d291f72015-11-16 23:52:25 -0800465 std::vector<int16_t> template_queue_element(render_queue_element_max_size_);
466
467 render_signal_queue_.reset(
468 new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>(
469 kMaxNumFramesToBuffer, template_queue_element,
470 RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_)));
peah2446e5a2015-11-18 06:11:13 -0800471
472 render_queue_buffer_.resize(render_queue_element_max_size_);
473 capture_queue_buffer_.resize(render_queue_element_max_size_);
peah4d291f72015-11-16 23:52:25 -0800474 } else {
475 render_signal_queue_->Clear();
476 }
peah4d291f72015-11-16 23:52:25 -0800477}
478
peahbfa97112016-03-10 21:09:04 -0800479int GainControlImpl::Configure() {
peahdf3efa82015-11-28 12:35:15 -0800480 rtc::CritScope cs_render(crit_render_);
481 rtc::CritScope cs_capture(crit_capture_);
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000482 WebRtcAgcConfig config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000483 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
484 // change the interface.
kwiberg9e2be5f2016-09-14 05:23:22 -0700485 //RTC_DCHECK_LE(target_level_dbfs_, 0);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000486 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
487 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000488 config.compressionGaindB =
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000489 static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000490 config.limiterEnable = limiter_enabled_;
491
peahbfa97112016-03-10 21:09:04 -0800492 int error = AudioProcessing::kNoError;
493 for (auto& gain_controller : gain_controllers_) {
494 const int handle_error =
495 WebRtcAgc_set_config(gain_controller->state(), config);
496 if (handle_error != AudioProcessing::kNoError) {
497 error = handle_error;
498 }
499 }
500 return error;
niklase@google.com470e71d2011-07-07 08:21:25 +0000501}
niklase@google.com470e71d2011-07-07 08:21:25 +0000502} // namespace webrtc