blob: c8175dc01f22685246af7255c3ddafe917db5b84 [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
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014
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 }
andrew@webrtc.org648af742012-02-08 01:57:29 +000032 assert(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
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000045GainControlImpl::GainControlImpl(const AudioProcessing* apm,
peahdf3efa82015-11-28 12:35:15 -080046 rtc::CriticalSection* crit_render,
47 rtc::CriticalSection* crit_capture)
peah4d291f72015-11-16 23:52:25 -080048 : ProcessingComponent(),
49 apm_(apm),
peahdf3efa82015-11-28 12:35:15 -080050 crit_render_(crit_render),
51 crit_capture_(crit_capture),
peah4d291f72015-11-16 23:52:25 -080052 mode_(kAdaptiveAnalog),
53 minimum_capture_level_(0),
54 maximum_capture_level_(255),
55 limiter_enabled_(true),
56 target_level_dbfs_(3),
57 compression_gain_db_(9),
58 analog_capture_level_(0),
59 was_analog_level_set_(false),
60 stream_is_saturated_(false),
peahdf3efa82015-11-28 12:35:15 -080061 render_queue_element_max_size_(0) {
62 RTC_DCHECK(apm);
63 RTC_DCHECK(crit_render);
64 RTC_DCHECK(crit_capture);
65}
niklase@google.com470e71d2011-07-07 08:21:25 +000066
67GainControlImpl::~GainControlImpl() {}
68
69int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -080070 rtc::CritScope cs(crit_render_);
niklase@google.com470e71d2011-07-07 08:21:25 +000071 if (!is_component_enabled()) {
peahdf3efa82015-11-28 12:35:15 -080072 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +000073 }
74
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +000075 assert(audio->num_frames_per_band() <= 160);
niklase@google.com470e71d2011-07-07 08:21:25 +000076
peah4d291f72015-11-16 23:52:25 -080077 render_queue_buffer_.resize(0);
niklase@google.com470e71d2011-07-07 08:21:25 +000078 for (int i = 0; i < num_handles(); i++) {
79 Handle* my_handle = static_cast<Handle*>(handle(i));
peah4d291f72015-11-16 23:52:25 -080080 int err =
81 WebRtcAgc_GetAddFarendError(my_handle, audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +000082
peahdf3efa82015-11-28 12:35:15 -080083 if (err != AudioProcessing::kNoError)
niklase@google.com470e71d2011-07-07 08:21:25 +000084 return GetHandleError(my_handle);
peah4d291f72015-11-16 23:52:25 -080085
86 // Buffer the samples in the render queue.
87 render_queue_buffer_.insert(
88 render_queue_buffer_.end(), audio->mixed_low_pass_data(),
89 (audio->mixed_low_pass_data() + audio->num_frames_per_band()));
90 }
91
92 // Insert the samples into the queue.
93 if (!render_signal_queue_->Insert(&render_queue_buffer_)) {
peahdf3efa82015-11-28 12:35:15 -080094 // The data queue is full and needs to be emptied.
peah4d291f72015-11-16 23:52:25 -080095 ReadQueuedRenderData();
96
97 // Retry the insert (should always work).
98 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true);
niklase@google.com470e71d2011-07-07 08:21:25 +000099 }
100
peahdf3efa82015-11-28 12:35:15 -0800101 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000102}
103
peah4d291f72015-11-16 23:52:25 -0800104// Read chunks of data that were received and queued on the render side from
105// a queue. All the data chunks are buffered into the farend signal of the AGC.
106void GainControlImpl::ReadQueuedRenderData() {
peahdf3efa82015-11-28 12:35:15 -0800107 rtc::CritScope cs(crit_capture_);
108
peah4d291f72015-11-16 23:52:25 -0800109 if (!is_component_enabled()) {
110 return;
111 }
112
113 while (render_signal_queue_->Remove(&capture_queue_buffer_)) {
114 int buffer_index = 0;
115 const int num_frames_per_band =
116 capture_queue_buffer_.size() / num_handles();
117 for (int i = 0; i < num_handles(); i++) {
118 Handle* my_handle = static_cast<Handle*>(handle(i));
119 WebRtcAgc_AddFarend(my_handle, &capture_queue_buffer_[buffer_index],
120 num_frames_per_band);
121
122 buffer_index += num_frames_per_band;
123 }
124 }
125}
126
niklase@google.com470e71d2011-07-07 08:21:25 +0000127int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800128 rtc::CritScope cs(crit_capture_);
129
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 if (!is_component_enabled()) {
peahdf3efa82015-11-28 12:35:15 -0800131 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000132 }
133
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000134 assert(audio->num_frames_per_band() <= 160);
niklase@google.com470e71d2011-07-07 08:21:25 +0000135 assert(audio->num_channels() == num_handles());
136
peahdf3efa82015-11-28 12:35:15 -0800137 int err = AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000138
139 if (mode_ == kAdaptiveAnalog) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000140 capture_levels_.assign(num_handles(), analog_capture_level_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 for (int i = 0; i < num_handles(); i++) {
142 Handle* my_handle = static_cast<Handle*>(handle(i));
143 err = WebRtcAgc_AddMic(
144 my_handle,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000145 audio->split_bands(i),
146 audio->num_bands(),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700147 audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
peahdf3efa82015-11-28 12:35:15 -0800149 if (err != AudioProcessing::kNoError) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000150 return GetHandleError(my_handle);
151 }
152 }
153 } else if (mode_ == kAdaptiveDigital) {
154
155 for (int i = 0; i < num_handles(); i++) {
156 Handle* my_handle = static_cast<Handle*>(handle(i));
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000157 int32_t capture_level_out = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
159 err = WebRtcAgc_VirtualMic(
160 my_handle,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000161 audio->split_bands(i),
162 audio->num_bands(),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700163 audio->num_frames_per_band(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000164 analog_capture_level_,
165 &capture_level_out);
166
167 capture_levels_[i] = capture_level_out;
168
peahdf3efa82015-11-28 12:35:15 -0800169 if (err != AudioProcessing::kNoError) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 return GetHandleError(my_handle);
171 }
172
173 }
174 }
175
peahdf3efa82015-11-28 12:35:15 -0800176 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000177}
178
179int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800180 rtc::CritScope cs(crit_capture_);
181
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 if (!is_component_enabled()) {
peahdf3efa82015-11-28 12:35:15 -0800183 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 }
185
186 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
peahdf3efa82015-11-28 12:35:15 -0800187 return AudioProcessing::kStreamParameterNotSetError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 }
189
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000190 assert(audio->num_frames_per_band() <= 160);
niklase@google.com470e71d2011-07-07 08:21:25 +0000191 assert(audio->num_channels() == num_handles());
192
193 stream_is_saturated_ = false;
194 for (int i = 0; i < num_handles(); i++) {
195 Handle* my_handle = static_cast<Handle*>(handle(i));
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000196 int32_t capture_level_out = 0;
197 uint8_t saturation_warning = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000198
peahdf3efa82015-11-28 12:35:15 -0800199 // The call to stream_has_echo() is ok from a deadlock perspective
200 // as the capture lock is allready held.
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 int err = WebRtcAgc_Process(
202 my_handle,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000203 audio->split_bands_const(i),
204 audio->num_bands(),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700205 audio->num_frames_per_band(),
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000206 audio->split_bands(i),
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 capture_levels_[i],
208 &capture_level_out,
209 apm_->echo_cancellation()->stream_has_echo(),
210 &saturation_warning);
211
peahdf3efa82015-11-28 12:35:15 -0800212 if (err != AudioProcessing::kNoError) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000213 return GetHandleError(my_handle);
214 }
215
216 capture_levels_[i] = capture_level_out;
217 if (saturation_warning == 1) {
218 stream_is_saturated_ = true;
219 }
220 }
221
222 if (mode_ == kAdaptiveAnalog) {
223 // Take the analog level to be the average across the handles.
224 analog_capture_level_ = 0;
225 for (int i = 0; i < num_handles(); i++) {
226 analog_capture_level_ += capture_levels_[i];
227 }
228
229 analog_capture_level_ /= num_handles();
230 }
231
232 was_analog_level_set_ = false;
peahdf3efa82015-11-28 12:35:15 -0800233 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000234}
235
236// TODO(ajm): ensure this is called under kAdaptiveAnalog.
237int GainControlImpl::set_stream_analog_level(int level) {
peahdf3efa82015-11-28 12:35:15 -0800238 rtc::CritScope cs(crit_capture_);
239
niklase@google.com470e71d2011-07-07 08:21:25 +0000240 was_analog_level_set_ = true;
241 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
peahdf3efa82015-11-28 12:35:15 -0800242 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000244 analog_capture_level_ = level;
245
peahdf3efa82015-11-28 12:35:15 -0800246 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000247}
248
249int GainControlImpl::stream_analog_level() {
peahdf3efa82015-11-28 12:35:15 -0800250 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 // TODO(ajm): enable this assertion?
252 //assert(mode_ == kAdaptiveAnalog);
253
254 return analog_capture_level_;
255}
256
257int GainControlImpl::Enable(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800258 rtc::CritScope cs_render(crit_render_);
259 rtc::CritScope cs_capture(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 return EnableComponent(enable);
261}
262
263bool GainControlImpl::is_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800264 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000265 return is_component_enabled();
266}
267
268int GainControlImpl::set_mode(Mode mode) {
peahdf3efa82015-11-28 12:35:15 -0800269 rtc::CritScope cs_render(crit_render_);
270 rtc::CritScope cs_capture(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000271 if (MapSetting(mode) == -1) {
peahdf3efa82015-11-28 12:35:15 -0800272 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000273 }
274
275 mode_ = mode;
276 return Initialize();
277}
278
279GainControl::Mode GainControlImpl::mode() const {
peahdf3efa82015-11-28 12:35:15 -0800280 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 return mode_;
282}
283
284int GainControlImpl::set_analog_level_limits(int minimum,
285 int maximum) {
peahdf3efa82015-11-28 12:35:15 -0800286 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000287 if (minimum < 0) {
peahdf3efa82015-11-28 12:35:15 -0800288 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000289 }
290
291 if (maximum > 65535) {
peahdf3efa82015-11-28 12:35:15 -0800292 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000293 }
294
295 if (maximum < minimum) {
peahdf3efa82015-11-28 12:35:15 -0800296 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000297 }
298
299 minimum_capture_level_ = minimum;
300 maximum_capture_level_ = maximum;
301
302 return Initialize();
303}
304
305int GainControlImpl::analog_level_minimum() const {
peahdf3efa82015-11-28 12:35:15 -0800306 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000307 return minimum_capture_level_;
308}
309
310int GainControlImpl::analog_level_maximum() const {
peahdf3efa82015-11-28 12:35:15 -0800311 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000312 return maximum_capture_level_;
313}
314
315bool GainControlImpl::stream_is_saturated() const {
peahdf3efa82015-11-28 12:35:15 -0800316 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000317 return stream_is_saturated_;
318}
319
320int GainControlImpl::set_target_level_dbfs(int level) {
peahdf3efa82015-11-28 12:35:15 -0800321 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000322 if (level > 31 || level < 0) {
peahdf3efa82015-11-28 12:35:15 -0800323 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000324 }
325
326 target_level_dbfs_ = level;
327 return Configure();
328}
329
330int GainControlImpl::target_level_dbfs() const {
peahdf3efa82015-11-28 12:35:15 -0800331 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000332 return target_level_dbfs_;
333}
334
335int GainControlImpl::set_compression_gain_db(int gain) {
peahdf3efa82015-11-28 12:35:15 -0800336 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000337 if (gain < 0 || gain > 90) {
peahdf3efa82015-11-28 12:35:15 -0800338 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000339 }
340
341 compression_gain_db_ = gain;
342 return Configure();
343}
344
345int GainControlImpl::compression_gain_db() const {
peahdf3efa82015-11-28 12:35:15 -0800346 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000347 return compression_gain_db_;
348}
349
350int GainControlImpl::enable_limiter(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800351 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 limiter_enabled_ = enable;
353 return Configure();
354}
355
356bool GainControlImpl::is_limiter_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800357 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000358 return limiter_enabled_;
359}
360
361int GainControlImpl::Initialize() {
362 int err = ProcessingComponent::Initialize();
peahdf3efa82015-11-28 12:35:15 -0800363 if (err != AudioProcessing::kNoError || !is_component_enabled()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000364 return err;
365 }
366
peah4d291f72015-11-16 23:52:25 -0800367 AllocateRenderQueue();
368
peahdf3efa82015-11-28 12:35:15 -0800369 rtc::CritScope cs_capture(crit_capture_);
kwibergcd19faf2015-11-05 05:11:19 -0800370 const int n = num_handles();
371 RTC_CHECK_GE(n, 0) << "Bad number of handles: " << n;
peahdf3efa82015-11-28 12:35:15 -0800372
kwibergcd19faf2015-11-05 05:11:19 -0800373 capture_levels_.assign(n, analog_capture_level_);
peahdf3efa82015-11-28 12:35:15 -0800374 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000375}
376
peah4d291f72015-11-16 23:52:25 -0800377void GainControlImpl::AllocateRenderQueue() {
peah2446e5a2015-11-18 06:11:13 -0800378 const size_t new_render_queue_element_max_size =
379 std::max<size_t>(static_cast<size_t>(1),
380 kMaxAllowedValuesOfSamplesPerFrame * num_handles());
peah4d291f72015-11-16 23:52:25 -0800381
peahdf3efa82015-11-28 12:35:15 -0800382 rtc::CritScope cs_render(crit_render_);
383 rtc::CritScope cs_capture(crit_capture_);
384
peah2446e5a2015-11-18 06:11:13 -0800385 if (render_queue_element_max_size_ < new_render_queue_element_max_size) {
386 render_queue_element_max_size_ = new_render_queue_element_max_size;
peah4d291f72015-11-16 23:52:25 -0800387 std::vector<int16_t> template_queue_element(render_queue_element_max_size_);
388
389 render_signal_queue_.reset(
390 new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>(
391 kMaxNumFramesToBuffer, template_queue_element,
392 RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_)));
peah2446e5a2015-11-18 06:11:13 -0800393
394 render_queue_buffer_.resize(render_queue_element_max_size_);
395 capture_queue_buffer_.resize(render_queue_element_max_size_);
peah4d291f72015-11-16 23:52:25 -0800396 } else {
397 render_signal_queue_->Clear();
398 }
peah4d291f72015-11-16 23:52:25 -0800399}
400
niklase@google.com470e71d2011-07-07 08:21:25 +0000401void* GainControlImpl::CreateHandle() const {
Bjorn Volcker9345e862015-06-10 21:43:36 +0200402 return WebRtcAgc_Create();
niklase@google.com470e71d2011-07-07 08:21:25 +0000403}
404
bjornv@webrtc.org5964fe02014-04-22 06:52:28 +0000405void GainControlImpl::DestroyHandle(void* handle) const {
406 WebRtcAgc_Free(static_cast<Handle*>(handle));
niklase@google.com470e71d2011-07-07 08:21:25 +0000407}
408
409int GainControlImpl::InitializeHandle(void* handle) const {
peahdf3efa82015-11-28 12:35:15 -0800410 rtc::CritScope cs_render(crit_render_);
411 rtc::CritScope cs_capture(crit_capture_);
412
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 return WebRtcAgc_Init(static_cast<Handle*>(handle),
414 minimum_capture_level_,
415 maximum_capture_level_,
416 MapSetting(mode_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000417 apm_->proc_sample_rate_hz());
niklase@google.com470e71d2011-07-07 08:21:25 +0000418}
419
420int GainControlImpl::ConfigureHandle(void* handle) const {
peahdf3efa82015-11-28 12:35:15 -0800421 rtc::CritScope cs_render(crit_render_);
422 rtc::CritScope cs_capture(crit_capture_);
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000423 WebRtcAgcConfig config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
425 // change the interface.
426 //assert(target_level_dbfs_ <= 0);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000427 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
428 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000429 config.compressionGaindB =
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000430 static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000431 config.limiterEnable = limiter_enabled_;
432
433 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
434}
435
436int GainControlImpl::num_handles_required() const {
peahdf3efa82015-11-28 12:35:15 -0800437 // Not locked as it only relies on APM public API which is threadsafe.
niklase@google.com470e71d2011-07-07 08:21:25 +0000438 return apm_->num_output_channels();
439}
440
441int GainControlImpl::GetHandleError(void* handle) const {
442 // The AGC has no get_error() function.
443 // (Despite listing errors in its interface...)
444 assert(handle != NULL);
peahdf3efa82015-11-28 12:35:15 -0800445 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000446}
447} // namespace webrtc