1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
11 #include "webrtc/modules/audio_processing/gain_control_impl.h"
12
13 #include <assert.h>
14
15 #include "webrtc/modules/audio_processing/audio_buffer.h"
16 #include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
17
18 namespace webrtc {
19
20 typedef void Handle;
21
22 namespace {
MapSetting(GainControl::Mode mode)23 int16_t MapSetting(GainControl::Mode mode) {
24 switch (mode) {
25 case GainControl::kAdaptiveAnalog:
26 return kAgcModeAdaptiveAnalog;
27 case GainControl::kAdaptiveDigital:
28 return kAgcModeAdaptiveDigital;
29 case GainControl::kFixedDigital:
30 return kAgcModeFixedDigital;
31 }
32 assert(false);
33 return -1;
34 }
35
36 // Maximum length that a frame of samples can have.
37 static 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.
41 static const size_t kMaxNumFramesToBuffer = 100;
42
43 } // namespace
44
GainControlImpl(const AudioProcessing * apm,rtc::CriticalSection * crit_render,rtc::CriticalSection * crit_capture)45 GainControlImpl::GainControlImpl(const AudioProcessing* apm,
46 rtc::CriticalSection* crit_render,
47 rtc::CriticalSection* crit_capture)
48 : ProcessingComponent(),
49 apm_(apm),
50 crit_render_(crit_render),
51 crit_capture_(crit_capture),
52 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),
61 render_queue_element_max_size_(0) {
62 RTC_DCHECK(apm);
63 RTC_DCHECK(crit_render);
64 RTC_DCHECK(crit_capture);
65 }
66
~GainControlImpl()67 GainControlImpl::~GainControlImpl() {}
68
ProcessRenderAudio(AudioBuffer * audio)69 int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
70 rtc::CritScope cs(crit_render_);
71 if (!is_component_enabled()) {
72 return AudioProcessing::kNoError;
73 }
74
75 assert(audio->num_frames_per_band() <= 160);
76
77 render_queue_buffer_.resize(0);
78 for (size_t i = 0; i < num_handles(); i++) {
79 Handle* my_handle = static_cast<Handle*>(handle(i));
80 int err =
81 WebRtcAgc_GetAddFarendError(my_handle, audio->num_frames_per_band());
82
83 if (err != AudioProcessing::kNoError)
84 return GetHandleError(my_handle);
85
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_)) {
94 // The data queue is full and needs to be emptied.
95 ReadQueuedRenderData();
96
97 // Retry the insert (should always work).
98 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true);
99 }
100
101 return AudioProcessing::kNoError;
102 }
103
104 // 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.
ReadQueuedRenderData()106 void GainControlImpl::ReadQueuedRenderData() {
107 rtc::CritScope cs(crit_capture_);
108
109 if (!is_component_enabled()) {
110 return;
111 }
112
113 while (render_signal_queue_->Remove(&capture_queue_buffer_)) {
114 size_t buffer_index = 0;
115 const size_t num_frames_per_band =
116 capture_queue_buffer_.size() / num_handles();
117 for (size_t 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
AnalyzeCaptureAudio(AudioBuffer * audio)127 int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
128 rtc::CritScope cs(crit_capture_);
129
130 if (!is_component_enabled()) {
131 return AudioProcessing::kNoError;
132 }
133
134 assert(audio->num_frames_per_band() <= 160);
135 assert(audio->num_channels() == num_handles());
136
137 int err = AudioProcessing::kNoError;
138
139 if (mode_ == kAdaptiveAnalog) {
140 capture_levels_.assign(num_handles(), analog_capture_level_);
141 for (size_t i = 0; i < num_handles(); i++) {
142 Handle* my_handle = static_cast<Handle*>(handle(i));
143 err = WebRtcAgc_AddMic(
144 my_handle,
145 audio->split_bands(i),
146 audio->num_bands(),
147 audio->num_frames_per_band());
148
149 if (err != AudioProcessing::kNoError) {
150 return GetHandleError(my_handle);
151 }
152 }
153 } else if (mode_ == kAdaptiveDigital) {
154
155 for (size_t i = 0; i < num_handles(); i++) {
156 Handle* my_handle = static_cast<Handle*>(handle(i));
157 int32_t capture_level_out = 0;
158
159 err = WebRtcAgc_VirtualMic(
160 my_handle,
161 audio->split_bands(i),
162 audio->num_bands(),
163 audio->num_frames_per_band(),
164 analog_capture_level_,
165 &capture_level_out);
166
167 capture_levels_[i] = capture_level_out;
168
169 if (err != AudioProcessing::kNoError) {
170 return GetHandleError(my_handle);
171 }
172
173 }
174 }
175
176 return AudioProcessing::kNoError;
177 }
178
ProcessCaptureAudio(AudioBuffer * audio)179 int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) {
180 rtc::CritScope cs(crit_capture_);
181
182 if (!is_component_enabled()) {
183 return AudioProcessing::kNoError;
184 }
185
186 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
187 return AudioProcessing::kStreamParameterNotSetError;
188 }
189
190 assert(audio->num_frames_per_band() <= 160);
191 assert(audio->num_channels() == num_handles());
192
193 stream_is_saturated_ = false;
194 for (size_t i = 0; i < num_handles(); i++) {
195 Handle* my_handle = static_cast<Handle*>(handle(i));
196 int32_t capture_level_out = 0;
197 uint8_t saturation_warning = 0;
198
199 // The call to stream_has_echo() is ok from a deadlock perspective
200 // as the capture lock is allready held.
201 int err = WebRtcAgc_Process(
202 my_handle,
203 audio->split_bands_const(i),
204 audio->num_bands(),
205 audio->num_frames_per_band(),
206 audio->split_bands(i),
207 capture_levels_[i],
208 &capture_level_out,
209 apm_->echo_cancellation()->stream_has_echo(),
210 &saturation_warning);
211
212 if (err != AudioProcessing::kNoError) {
213 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 (size_t 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;
233 return AudioProcessing::kNoError;
234 }
235
236 // TODO(ajm): ensure this is called under kAdaptiveAnalog.
set_stream_analog_level(int level)237 int GainControlImpl::set_stream_analog_level(int level) {
238 rtc::CritScope cs(crit_capture_);
239
240 was_analog_level_set_ = true;
241 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
242 return AudioProcessing::kBadParameterError;
243 }
244 analog_capture_level_ = level;
245
246 return AudioProcessing::kNoError;
247 }
248
stream_analog_level()249 int GainControlImpl::stream_analog_level() {
250 rtc::CritScope cs(crit_capture_);
251 // TODO(ajm): enable this assertion?
252 //assert(mode_ == kAdaptiveAnalog);
253
254 return analog_capture_level_;
255 }
256
Enable(bool enable)257 int GainControlImpl::Enable(bool enable) {
258 rtc::CritScope cs_render(crit_render_);
259 rtc::CritScope cs_capture(crit_capture_);
260 return EnableComponent(enable);
261 }
262
is_enabled() const263 bool GainControlImpl::is_enabled() const {
264 rtc::CritScope cs(crit_capture_);
265 return is_component_enabled();
266 }
267
set_mode(Mode mode)268 int GainControlImpl::set_mode(Mode mode) {
269 rtc::CritScope cs_render(crit_render_);
270 rtc::CritScope cs_capture(crit_capture_);
271 if (MapSetting(mode) == -1) {
272 return AudioProcessing::kBadParameterError;
273 }
274
275 mode_ = mode;
276 return Initialize();
277 }
278
mode() const279 GainControl::Mode GainControlImpl::mode() const {
280 rtc::CritScope cs(crit_capture_);
281 return mode_;
282 }
283
set_analog_level_limits(int minimum,int maximum)284 int GainControlImpl::set_analog_level_limits(int minimum,
285 int maximum) {
286 rtc::CritScope cs(crit_capture_);
287 if (minimum < 0) {
288 return AudioProcessing::kBadParameterError;
289 }
290
291 if (maximum > 65535) {
292 return AudioProcessing::kBadParameterError;
293 }
294
295 if (maximum < minimum) {
296 return AudioProcessing::kBadParameterError;
297 }
298
299 minimum_capture_level_ = minimum;
300 maximum_capture_level_ = maximum;
301
302 return Initialize();
303 }
304
analog_level_minimum() const305 int GainControlImpl::analog_level_minimum() const {
306 rtc::CritScope cs(crit_capture_);
307 return minimum_capture_level_;
308 }
309
analog_level_maximum() const310 int GainControlImpl::analog_level_maximum() const {
311 rtc::CritScope cs(crit_capture_);
312 return maximum_capture_level_;
313 }
314
stream_is_saturated() const315 bool GainControlImpl::stream_is_saturated() const {
316 rtc::CritScope cs(crit_capture_);
317 return stream_is_saturated_;
318 }
319
set_target_level_dbfs(int level)320 int GainControlImpl::set_target_level_dbfs(int level) {
321 rtc::CritScope cs(crit_capture_);
322 if (level > 31 || level < 0) {
323 return AudioProcessing::kBadParameterError;
324 }
325
326 target_level_dbfs_ = level;
327 return Configure();
328 }
329
target_level_dbfs() const330 int GainControlImpl::target_level_dbfs() const {
331 rtc::CritScope cs(crit_capture_);
332 return target_level_dbfs_;
333 }
334
set_compression_gain_db(int gain)335 int GainControlImpl::set_compression_gain_db(int gain) {
336 rtc::CritScope cs(crit_capture_);
337 if (gain < 0 || gain > 90) {
338 return AudioProcessing::kBadParameterError;
339 }
340
341 compression_gain_db_ = gain;
342 return Configure();
343 }
344
compression_gain_db() const345 int GainControlImpl::compression_gain_db() const {
346 rtc::CritScope cs(crit_capture_);
347 return compression_gain_db_;
348 }
349
enable_limiter(bool enable)350 int GainControlImpl::enable_limiter(bool enable) {
351 rtc::CritScope cs(crit_capture_);
352 limiter_enabled_ = enable;
353 return Configure();
354 }
355
is_limiter_enabled() const356 bool GainControlImpl::is_limiter_enabled() const {
357 rtc::CritScope cs(crit_capture_);
358 return limiter_enabled_;
359 }
360
Initialize()361 int GainControlImpl::Initialize() {
362 int err = ProcessingComponent::Initialize();
363 if (err != AudioProcessing::kNoError || !is_component_enabled()) {
364 return err;
365 }
366
367 AllocateRenderQueue();
368
369 rtc::CritScope cs_capture(crit_capture_);
370 const int n = num_handles();
371 RTC_CHECK_GE(n, 0) << "Bad number of handles: " << n;
372
373 capture_levels_.assign(n, analog_capture_level_);
374 return AudioProcessing::kNoError;
375 }
376
AllocateRenderQueue()377 void GainControlImpl::AllocateRenderQueue() {
378 const size_t new_render_queue_element_max_size =
379 std::max<size_t>(static_cast<size_t>(1),
380 kMaxAllowedValuesOfSamplesPerFrame * num_handles());
381
382 rtc::CritScope cs_render(crit_render_);
383 rtc::CritScope cs_capture(crit_capture_);
384
385 if (render_queue_element_max_size_ < new_render_queue_element_max_size) {
386 render_queue_element_max_size_ = new_render_queue_element_max_size;
387 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_)));
393
394 render_queue_buffer_.resize(render_queue_element_max_size_);
395 capture_queue_buffer_.resize(render_queue_element_max_size_);
396 } else {
397 render_signal_queue_->Clear();
398 }
399 }
400
CreateHandle() const401 void* GainControlImpl::CreateHandle() const {
402 return WebRtcAgc_Create();
403 }
404
DestroyHandle(void * handle) const405 void GainControlImpl::DestroyHandle(void* handle) const {
406 WebRtcAgc_Free(static_cast<Handle*>(handle));
407 }
408
InitializeHandle(void * handle) const409 int GainControlImpl::InitializeHandle(void* handle) const {
410 rtc::CritScope cs_render(crit_render_);
411 rtc::CritScope cs_capture(crit_capture_);
412
413 return WebRtcAgc_Init(static_cast<Handle*>(handle),
414 minimum_capture_level_,
415 maximum_capture_level_,
416 MapSetting(mode_),
417 apm_->proc_sample_rate_hz());
418 }
419
ConfigureHandle(void * handle) const420 int GainControlImpl::ConfigureHandle(void* handle) const {
421 rtc::CritScope cs_render(crit_render_);
422 rtc::CritScope cs_capture(crit_capture_);
423 WebRtcAgcConfig config;
424 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
425 // change the interface.
426 //assert(target_level_dbfs_ <= 0);
427 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
428 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
429 config.compressionGaindB =
430 static_cast<int16_t>(compression_gain_db_);
431 config.limiterEnable = limiter_enabled_;
432
433 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
434 }
435
num_handles_required() const436 size_t GainControlImpl::num_handles_required() const {
437 // Not locked as it only relies on APM public API which is threadsafe.
438 return apm_->num_proc_channels();
439 }
440
GetHandleError(void * handle) const441 int GainControlImpl::GetHandleError(void* handle) const {
442 // The AGC has no get_error() function.
443 // (Despite listing errors in its interface...)
444 assert(handle != NULL);
445 return AudioProcessing::kUnspecifiedError;
446 }
447 } // namespace webrtc
448