blob: 0eacd28686382c2bd8cffb17b340495915d47eb8 [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"
Henrik Kjellander98f53512015-10-28 18:17:40 +010017#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018
niklase@google.com470e71d2011-07-07 08:21:25 +000019namespace webrtc {
20
21typedef void Handle;
22
niklase@google.com470e71d2011-07-07 08:21:25 +000023namespace {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000024int16_t MapSetting(GainControl::Mode mode) {
niklase@google.com470e71d2011-07-07 08:21:25 +000025 switch (mode) {
26 case GainControl::kAdaptiveAnalog:
27 return kAgcModeAdaptiveAnalog;
niklase@google.com470e71d2011-07-07 08:21:25 +000028 case GainControl::kAdaptiveDigital:
29 return kAgcModeAdaptiveDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000030 case GainControl::kFixedDigital:
31 return kAgcModeFixedDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000032 }
andrew@webrtc.org648af742012-02-08 01:57:29 +000033 assert(false);
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000034 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
niklase@google.com470e71d2011-07-07 08:21:25 +000036
peah2446e5a2015-11-18 06:11:13 -080037// Maximum length that a frame of samples can have.
38static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160;
39// Maximum number of frames to buffer in the render queue.
40// TODO(peah): Decrease this once we properly handle hugely unbalanced
41// reverse and forward call numbers.
42static const size_t kMaxNumFramesToBuffer = 100;
43
44} // namespace
peah4d291f72015-11-16 23:52:25 -080045
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000046GainControlImpl::GainControlImpl(const AudioProcessing* apm,
47 CriticalSectionWrapper* crit)
peah4d291f72015-11-16 23:52:25 -080048 : ProcessingComponent(),
49 apm_(apm),
50 crit_(crit),
51 mode_(kAdaptiveAnalog),
52 minimum_capture_level_(0),
53 maximum_capture_level_(255),
54 limiter_enabled_(true),
55 target_level_dbfs_(3),
56 compression_gain_db_(9),
57 analog_capture_level_(0),
58 was_analog_level_set_(false),
59 stream_is_saturated_(false),
peah2446e5a2015-11-18 06:11:13 -080060 render_queue_element_max_size_(0) {}
niklase@google.com470e71d2011-07-07 08:21:25 +000061
62GainControlImpl::~GainControlImpl() {}
63
64int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
65 if (!is_component_enabled()) {
66 return apm_->kNoError;
67 }
68
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +000069 assert(audio->num_frames_per_band() <= 160);
niklase@google.com470e71d2011-07-07 08:21:25 +000070
peah4d291f72015-11-16 23:52:25 -080071 render_queue_buffer_.resize(0);
niklase@google.com470e71d2011-07-07 08:21:25 +000072 for (int i = 0; i < num_handles(); i++) {
73 Handle* my_handle = static_cast<Handle*>(handle(i));
peah4d291f72015-11-16 23:52:25 -080074 int err =
75 WebRtcAgc_GetAddFarendError(my_handle, audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +000076
peah4d291f72015-11-16 23:52:25 -080077 if (err != apm_->kNoError)
niklase@google.com470e71d2011-07-07 08:21:25 +000078 return GetHandleError(my_handle);
peah4d291f72015-11-16 23:52:25 -080079
80 // Buffer the samples in the render queue.
81 render_queue_buffer_.insert(
82 render_queue_buffer_.end(), audio->mixed_low_pass_data(),
83 (audio->mixed_low_pass_data() + audio->num_frames_per_band()));
84 }
85
86 // Insert the samples into the queue.
87 if (!render_signal_queue_->Insert(&render_queue_buffer_)) {
88 ReadQueuedRenderData();
89
90 // Retry the insert (should always work).
91 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true);
niklase@google.com470e71d2011-07-07 08:21:25 +000092 }
93
94 return apm_->kNoError;
95}
96
peah4d291f72015-11-16 23:52:25 -080097// Read chunks of data that were received and queued on the render side from
98// a queue. All the data chunks are buffered into the farend signal of the AGC.
99void GainControlImpl::ReadQueuedRenderData() {
100 if (!is_component_enabled()) {
101 return;
102 }
103
104 while (render_signal_queue_->Remove(&capture_queue_buffer_)) {
105 int buffer_index = 0;
106 const int num_frames_per_band =
107 capture_queue_buffer_.size() / num_handles();
108 for (int i = 0; i < num_handles(); i++) {
109 Handle* my_handle = static_cast<Handle*>(handle(i));
110 WebRtcAgc_AddFarend(my_handle, &capture_queue_buffer_[buffer_index],
111 num_frames_per_band);
112
113 buffer_index += num_frames_per_band;
114 }
115 }
116}
117
niklase@google.com470e71d2011-07-07 08:21:25 +0000118int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
119 if (!is_component_enabled()) {
120 return apm_->kNoError;
121 }
122
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000123 assert(audio->num_frames_per_band() <= 160);
niklase@google.com470e71d2011-07-07 08:21:25 +0000124 assert(audio->num_channels() == num_handles());
125
126 int err = apm_->kNoError;
127
128 if (mode_ == kAdaptiveAnalog) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000129 capture_levels_.assign(num_handles(), analog_capture_level_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 for (int i = 0; i < num_handles(); i++) {
131 Handle* my_handle = static_cast<Handle*>(handle(i));
132 err = WebRtcAgc_AddMic(
133 my_handle,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000134 audio->split_bands(i),
135 audio->num_bands(),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700136 audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000137
138 if (err != apm_->kNoError) {
139 return GetHandleError(my_handle);
140 }
141 }
142 } else if (mode_ == kAdaptiveDigital) {
143
144 for (int i = 0; i < num_handles(); i++) {
145 Handle* my_handle = static_cast<Handle*>(handle(i));
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000146 int32_t capture_level_out = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000147
148 err = WebRtcAgc_VirtualMic(
149 my_handle,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000150 audio->split_bands(i),
151 audio->num_bands(),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700152 audio->num_frames_per_band(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 analog_capture_level_,
154 &capture_level_out);
155
156 capture_levels_[i] = capture_level_out;
157
158 if (err != apm_->kNoError) {
159 return GetHandleError(my_handle);
160 }
161
162 }
163 }
164
165 return apm_->kNoError;
166}
167
168int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) {
169 if (!is_component_enabled()) {
170 return apm_->kNoError;
171 }
172
173 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
174 return apm_->kStreamParameterNotSetError;
175 }
176
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000177 assert(audio->num_frames_per_band() <= 160);
niklase@google.com470e71d2011-07-07 08:21:25 +0000178 assert(audio->num_channels() == num_handles());
179
180 stream_is_saturated_ = false;
181 for (int i = 0; i < num_handles(); i++) {
182 Handle* my_handle = static_cast<Handle*>(handle(i));
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000183 int32_t capture_level_out = 0;
184 uint8_t saturation_warning = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000185
186 int err = WebRtcAgc_Process(
187 my_handle,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000188 audio->split_bands_const(i),
189 audio->num_bands(),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700190 audio->num_frames_per_band(),
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000191 audio->split_bands(i),
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 capture_levels_[i],
193 &capture_level_out,
194 apm_->echo_cancellation()->stream_has_echo(),
195 &saturation_warning);
196
197 if (err != apm_->kNoError) {
198 return GetHandleError(my_handle);
199 }
200
201 capture_levels_[i] = capture_level_out;
202 if (saturation_warning == 1) {
203 stream_is_saturated_ = true;
204 }
205 }
206
207 if (mode_ == kAdaptiveAnalog) {
208 // Take the analog level to be the average across the handles.
209 analog_capture_level_ = 0;
210 for (int i = 0; i < num_handles(); i++) {
211 analog_capture_level_ += capture_levels_[i];
212 }
213
214 analog_capture_level_ /= num_handles();
215 }
216
217 was_analog_level_set_ = false;
218 return apm_->kNoError;
219}
220
221// TODO(ajm): ensure this is called under kAdaptiveAnalog.
222int GainControlImpl::set_stream_analog_level(int level) {
Brave Yao1a07a1e2015-05-21 12:42:40 +0800223 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 was_analog_level_set_ = true;
225 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
226 return apm_->kBadParameterError;
227 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000228 analog_capture_level_ = level;
229
230 return apm_->kNoError;
231}
232
233int GainControlImpl::stream_analog_level() {
234 // TODO(ajm): enable this assertion?
235 //assert(mode_ == kAdaptiveAnalog);
236
237 return analog_capture_level_;
238}
239
240int GainControlImpl::Enable(bool enable) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000241 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 return EnableComponent(enable);
243}
244
245bool GainControlImpl::is_enabled() const {
246 return is_component_enabled();
247}
248
249int GainControlImpl::set_mode(Mode mode) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000250 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 if (MapSetting(mode) == -1) {
252 return apm_->kBadParameterError;
253 }
254
255 mode_ = mode;
256 return Initialize();
257}
258
259GainControl::Mode GainControlImpl::mode() const {
260 return mode_;
261}
262
263int GainControlImpl::set_analog_level_limits(int minimum,
264 int maximum) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000265 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000266 if (minimum < 0) {
267 return apm_->kBadParameterError;
268 }
269
270 if (maximum > 65535) {
271 return apm_->kBadParameterError;
272 }
273
274 if (maximum < minimum) {
275 return apm_->kBadParameterError;
276 }
277
278 minimum_capture_level_ = minimum;
279 maximum_capture_level_ = maximum;
280
281 return Initialize();
282}
283
284int GainControlImpl::analog_level_minimum() const {
285 return minimum_capture_level_;
286}
287
288int GainControlImpl::analog_level_maximum() const {
289 return maximum_capture_level_;
290}
291
292bool GainControlImpl::stream_is_saturated() const {
293 return stream_is_saturated_;
294}
295
296int GainControlImpl::set_target_level_dbfs(int level) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000297 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000298 if (level > 31 || level < 0) {
299 return apm_->kBadParameterError;
300 }
301
302 target_level_dbfs_ = level;
303 return Configure();
304}
305
306int GainControlImpl::target_level_dbfs() const {
307 return target_level_dbfs_;
308}
309
310int GainControlImpl::set_compression_gain_db(int gain) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000311 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000312 if (gain < 0 || gain > 90) {
313 return apm_->kBadParameterError;
314 }
315
316 compression_gain_db_ = gain;
317 return Configure();
318}
319
320int GainControlImpl::compression_gain_db() const {
321 return compression_gain_db_;
322}
323
324int GainControlImpl::enable_limiter(bool enable) {
andrew@webrtc.org56e4a052014-02-27 22:23:17 +0000325 CriticalSectionScoped crit_scoped(crit_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 limiter_enabled_ = enable;
327 return Configure();
328}
329
330bool GainControlImpl::is_limiter_enabled() const {
331 return limiter_enabled_;
332}
333
334int GainControlImpl::Initialize() {
335 int err = ProcessingComponent::Initialize();
336 if (err != apm_->kNoError || !is_component_enabled()) {
337 return err;
338 }
339
peah4d291f72015-11-16 23:52:25 -0800340 AllocateRenderQueue();
341
kwibergcd19faf2015-11-05 05:11:19 -0800342 const int n = num_handles();
343 RTC_CHECK_GE(n, 0) << "Bad number of handles: " << n;
344 capture_levels_.assign(n, analog_capture_level_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 return apm_->kNoError;
346}
347
peah4d291f72015-11-16 23:52:25 -0800348void GainControlImpl::AllocateRenderQueue() {
peah2446e5a2015-11-18 06:11:13 -0800349 const size_t new_render_queue_element_max_size =
350 std::max<size_t>(static_cast<size_t>(1),
351 kMaxAllowedValuesOfSamplesPerFrame * num_handles());
peah4d291f72015-11-16 23:52:25 -0800352
peah2446e5a2015-11-18 06:11:13 -0800353 if (render_queue_element_max_size_ < new_render_queue_element_max_size) {
354 render_queue_element_max_size_ = new_render_queue_element_max_size;
peah4d291f72015-11-16 23:52:25 -0800355 std::vector<int16_t> template_queue_element(render_queue_element_max_size_);
356
357 render_signal_queue_.reset(
358 new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>(
359 kMaxNumFramesToBuffer, template_queue_element,
360 RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_)));
peah2446e5a2015-11-18 06:11:13 -0800361
362 render_queue_buffer_.resize(render_queue_element_max_size_);
363 capture_queue_buffer_.resize(render_queue_element_max_size_);
peah4d291f72015-11-16 23:52:25 -0800364 } else {
365 render_signal_queue_->Clear();
366 }
peah4d291f72015-11-16 23:52:25 -0800367}
368
niklase@google.com470e71d2011-07-07 08:21:25 +0000369void* GainControlImpl::CreateHandle() const {
Bjorn Volcker9345e862015-06-10 21:43:36 +0200370 return WebRtcAgc_Create();
niklase@google.com470e71d2011-07-07 08:21:25 +0000371}
372
bjornv@webrtc.org5964fe02014-04-22 06:52:28 +0000373void GainControlImpl::DestroyHandle(void* handle) const {
374 WebRtcAgc_Free(static_cast<Handle*>(handle));
niklase@google.com470e71d2011-07-07 08:21:25 +0000375}
376
377int GainControlImpl::InitializeHandle(void* handle) const {
378 return WebRtcAgc_Init(static_cast<Handle*>(handle),
379 minimum_capture_level_,
380 maximum_capture_level_,
381 MapSetting(mode_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000382 apm_->proc_sample_rate_hz());
niklase@google.com470e71d2011-07-07 08:21:25 +0000383}
384
385int GainControlImpl::ConfigureHandle(void* handle) const {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000386 WebRtcAgcConfig config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
388 // change the interface.
389 //assert(target_level_dbfs_ <= 0);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000390 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
391 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000392 config.compressionGaindB =
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000393 static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 config.limiterEnable = limiter_enabled_;
395
396 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
397}
398
399int GainControlImpl::num_handles_required() const {
400 return apm_->num_output_channels();
401}
402
403int GainControlImpl::GetHandleError(void* handle) const {
404 // The AGC has no get_error() function.
405 // (Despite listing errors in its interface...)
406 assert(handle != NULL);
407 return apm_->kUnspecifiedError;
408}
409} // namespace webrtc