• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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