Home | History | Annotate | Download | only in audio_processing
      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 {
     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 
     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 
     67 GainControlImpl::~GainControlImpl() {}
     68 
     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.
    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 
    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 
    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.
    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 
    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 
    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 
    263 bool GainControlImpl::is_enabled() const {
    264   rtc::CritScope cs(crit_capture_);
    265   return is_component_enabled();
    266 }
    267 
    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 
    279 GainControl::Mode GainControlImpl::mode() const {
    280   rtc::CritScope cs(crit_capture_);
    281   return mode_;
    282 }
    283 
    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 
    305 int GainControlImpl::analog_level_minimum() const {
    306   rtc::CritScope cs(crit_capture_);
    307   return minimum_capture_level_;
    308 }
    309 
    310 int GainControlImpl::analog_level_maximum() const {
    311   rtc::CritScope cs(crit_capture_);
    312   return maximum_capture_level_;
    313 }
    314 
    315 bool GainControlImpl::stream_is_saturated() const {
    316   rtc::CritScope cs(crit_capture_);
    317   return stream_is_saturated_;
    318 }
    319 
    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 
    330 int GainControlImpl::target_level_dbfs() const {
    331   rtc::CritScope cs(crit_capture_);
    332   return target_level_dbfs_;
    333 }
    334 
    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 
    345 int GainControlImpl::compression_gain_db() const {
    346   rtc::CritScope cs(crit_capture_);
    347   return compression_gain_db_;
    348 }
    349 
    350 int GainControlImpl::enable_limiter(bool enable) {
    351   rtc::CritScope cs(crit_capture_);
    352   limiter_enabled_ = enable;
    353   return Configure();
    354 }
    355 
    356 bool GainControlImpl::is_limiter_enabled() const {
    357   rtc::CritScope cs(crit_capture_);
    358   return limiter_enabled_;
    359 }
    360 
    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 
    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 
    401 void* GainControlImpl::CreateHandle() const {
    402   return WebRtcAgc_Create();
    403 }
    404 
    405 void GainControlImpl::DestroyHandle(void* handle) const {
    406   WebRtcAgc_Free(static_cast<Handle*>(handle));
    407 }
    408 
    409 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 
    420 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 
    436 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 
    441 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