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/include/gain_control.h"
     17 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
     18 
     19 namespace webrtc {
     20 
     21 typedef void Handle;
     22 
     23 namespace {
     24 int16_t MapSetting(GainControl::Mode mode) {
     25   switch (mode) {
     26     case GainControl::kAdaptiveAnalog:
     27       return kAgcModeAdaptiveAnalog;
     28     case GainControl::kAdaptiveDigital:
     29       return kAgcModeAdaptiveDigital;
     30     case GainControl::kFixedDigital:
     31       return kAgcModeFixedDigital;
     32   }
     33   assert(false);
     34   return -1;
     35 }
     36 }  // namespace
     37 
     38 GainControlImpl::GainControlImpl(const AudioProcessing* apm,
     39                                  CriticalSectionWrapper* crit)
     40   : ProcessingComponent(),
     41     apm_(apm),
     42     crit_(crit),
     43     mode_(kAdaptiveAnalog),
     44     minimum_capture_level_(0),
     45     maximum_capture_level_(255),
     46     limiter_enabled_(true),
     47     target_level_dbfs_(3),
     48     compression_gain_db_(9),
     49     analog_capture_level_(0),
     50     was_analog_level_set_(false),
     51     stream_is_saturated_(false) {}
     52 
     53 GainControlImpl::~GainControlImpl() {}
     54 
     55 int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
     56   if (!is_component_enabled()) {
     57     return apm_->kNoError;
     58   }
     59 
     60   assert(audio->samples_per_split_channel() <= 160);
     61 
     62   const int16_t* mixed_data = audio->low_pass_split_data(0);
     63   if (audio->num_channels() > 1) {
     64     audio->CopyAndMixLowPass(1);
     65     mixed_data = audio->mixed_low_pass_data(0);
     66   }
     67 
     68   for (int i = 0; i < num_handles(); i++) {
     69     Handle* my_handle = static_cast<Handle*>(handle(i));
     70     int err = WebRtcAgc_AddFarend(
     71         my_handle,
     72         mixed_data,
     73         static_cast<int16_t>(audio->samples_per_split_channel()));
     74 
     75     if (err != apm_->kNoError) {
     76       return GetHandleError(my_handle);
     77     }
     78   }
     79 
     80   return apm_->kNoError;
     81 }
     82 
     83 int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
     84   if (!is_component_enabled()) {
     85     return apm_->kNoError;
     86   }
     87 
     88   assert(audio->samples_per_split_channel() <= 160);
     89   assert(audio->num_channels() == num_handles());
     90 
     91   int err = apm_->kNoError;
     92 
     93   if (mode_ == kAdaptiveAnalog) {
     94     capture_levels_.assign(num_handles(), analog_capture_level_);
     95     for (int i = 0; i < num_handles(); i++) {
     96       Handle* my_handle = static_cast<Handle*>(handle(i));
     97       err = WebRtcAgc_AddMic(
     98           my_handle,
     99           audio->low_pass_split_data(i),
    100           audio->high_pass_split_data(i),
    101           static_cast<int16_t>(audio->samples_per_split_channel()));
    102 
    103       if (err != apm_->kNoError) {
    104         return GetHandleError(my_handle);
    105       }
    106     }
    107   } else if (mode_ == kAdaptiveDigital) {
    108 
    109     for (int i = 0; i < num_handles(); i++) {
    110       Handle* my_handle = static_cast<Handle*>(handle(i));
    111       int32_t capture_level_out = 0;
    112 
    113       err = WebRtcAgc_VirtualMic(
    114           my_handle,
    115           audio->low_pass_split_data(i),
    116           audio->high_pass_split_data(i),
    117           static_cast<int16_t>(audio->samples_per_split_channel()),
    118           analog_capture_level_,
    119           &capture_level_out);
    120 
    121       capture_levels_[i] = capture_level_out;
    122 
    123       if (err != apm_->kNoError) {
    124         return GetHandleError(my_handle);
    125       }
    126 
    127     }
    128   }
    129 
    130   return apm_->kNoError;
    131 }
    132 
    133 int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) {
    134   if (!is_component_enabled()) {
    135     return apm_->kNoError;
    136   }
    137 
    138   if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
    139     return apm_->kStreamParameterNotSetError;
    140   }
    141 
    142   assert(audio->samples_per_split_channel() <= 160);
    143   assert(audio->num_channels() == num_handles());
    144 
    145   stream_is_saturated_ = false;
    146   for (int i = 0; i < num_handles(); i++) {
    147     Handle* my_handle = static_cast<Handle*>(handle(i));
    148     int32_t capture_level_out = 0;
    149     uint8_t saturation_warning = 0;
    150 
    151     int err = WebRtcAgc_Process(
    152         my_handle,
    153         audio->low_pass_split_data(i),
    154         audio->high_pass_split_data(i),
    155         static_cast<int16_t>(audio->samples_per_split_channel()),
    156         audio->low_pass_split_data(i),
    157         audio->high_pass_split_data(i),
    158         capture_levels_[i],
    159         &capture_level_out,
    160         apm_->echo_cancellation()->stream_has_echo(),
    161         &saturation_warning);
    162 
    163     if (err != apm_->kNoError) {
    164       return GetHandleError(my_handle);
    165     }
    166 
    167     capture_levels_[i] = capture_level_out;
    168     if (saturation_warning == 1) {
    169       stream_is_saturated_ = true;
    170     }
    171   }
    172 
    173   if (mode_ == kAdaptiveAnalog) {
    174     // Take the analog level to be the average across the handles.
    175     analog_capture_level_ = 0;
    176     for (int i = 0; i < num_handles(); i++) {
    177       analog_capture_level_ += capture_levels_[i];
    178     }
    179 
    180     analog_capture_level_ /= num_handles();
    181   }
    182 
    183   was_analog_level_set_ = false;
    184   return apm_->kNoError;
    185 }
    186 
    187 // TODO(ajm): ensure this is called under kAdaptiveAnalog.
    188 int GainControlImpl::set_stream_analog_level(int level) {
    189   was_analog_level_set_ = true;
    190   if (level < minimum_capture_level_ || level > maximum_capture_level_) {
    191     return apm_->kBadParameterError;
    192   }
    193   analog_capture_level_ = level;
    194 
    195   return apm_->kNoError;
    196 }
    197 
    198 int GainControlImpl::stream_analog_level() {
    199   // TODO(ajm): enable this assertion?
    200   //assert(mode_ == kAdaptiveAnalog);
    201 
    202   return analog_capture_level_;
    203 }
    204 
    205 int GainControlImpl::Enable(bool enable) {
    206   CriticalSectionScoped crit_scoped(crit_);
    207   return EnableComponent(enable);
    208 }
    209 
    210 bool GainControlImpl::is_enabled() const {
    211   return is_component_enabled();
    212 }
    213 
    214 int GainControlImpl::set_mode(Mode mode) {
    215   CriticalSectionScoped crit_scoped(crit_);
    216   if (MapSetting(mode) == -1) {
    217     return apm_->kBadParameterError;
    218   }
    219 
    220   mode_ = mode;
    221   return Initialize();
    222 }
    223 
    224 GainControl::Mode GainControlImpl::mode() const {
    225   return mode_;
    226 }
    227 
    228 int GainControlImpl::set_analog_level_limits(int minimum,
    229                                              int maximum) {
    230   CriticalSectionScoped crit_scoped(crit_);
    231   if (minimum < 0) {
    232     return apm_->kBadParameterError;
    233   }
    234 
    235   if (maximum > 65535) {
    236     return apm_->kBadParameterError;
    237   }
    238 
    239   if (maximum < minimum) {
    240     return apm_->kBadParameterError;
    241   }
    242 
    243   minimum_capture_level_ = minimum;
    244   maximum_capture_level_ = maximum;
    245 
    246   return Initialize();
    247 }
    248 
    249 int GainControlImpl::analog_level_minimum() const {
    250   return minimum_capture_level_;
    251 }
    252 
    253 int GainControlImpl::analog_level_maximum() const {
    254   return maximum_capture_level_;
    255 }
    256 
    257 bool GainControlImpl::stream_is_saturated() const {
    258   return stream_is_saturated_;
    259 }
    260 
    261 int GainControlImpl::set_target_level_dbfs(int level) {
    262   CriticalSectionScoped crit_scoped(crit_);
    263   if (level > 31 || level < 0) {
    264     return apm_->kBadParameterError;
    265   }
    266 
    267   target_level_dbfs_ = level;
    268   return Configure();
    269 }
    270 
    271 int GainControlImpl::target_level_dbfs() const {
    272   return target_level_dbfs_;
    273 }
    274 
    275 int GainControlImpl::set_compression_gain_db(int gain) {
    276   CriticalSectionScoped crit_scoped(crit_);
    277   if (gain < 0 || gain > 90) {
    278     return apm_->kBadParameterError;
    279   }
    280 
    281   compression_gain_db_ = gain;
    282   return Configure();
    283 }
    284 
    285 int GainControlImpl::compression_gain_db() const {
    286   return compression_gain_db_;
    287 }
    288 
    289 int GainControlImpl::enable_limiter(bool enable) {
    290   CriticalSectionScoped crit_scoped(crit_);
    291   limiter_enabled_ = enable;
    292   return Configure();
    293 }
    294 
    295 bool GainControlImpl::is_limiter_enabled() const {
    296   return limiter_enabled_;
    297 }
    298 
    299 int GainControlImpl::Initialize() {
    300   int err = ProcessingComponent::Initialize();
    301   if (err != apm_->kNoError || !is_component_enabled()) {
    302     return err;
    303   }
    304 
    305   capture_levels_.assign(num_handles(), analog_capture_level_);
    306   return apm_->kNoError;
    307 }
    308 
    309 void* GainControlImpl::CreateHandle() const {
    310   Handle* handle = NULL;
    311   if (WebRtcAgc_Create(&handle) != apm_->kNoError) {
    312     handle = NULL;
    313   } else {
    314     assert(handle != NULL);
    315   }
    316 
    317   return handle;
    318 }
    319 
    320 void GainControlImpl::DestroyHandle(void* handle) const {
    321   WebRtcAgc_Free(static_cast<Handle*>(handle));
    322 }
    323 
    324 int GainControlImpl::InitializeHandle(void* handle) const {
    325   return WebRtcAgc_Init(static_cast<Handle*>(handle),
    326                           minimum_capture_level_,
    327                           maximum_capture_level_,
    328                           MapSetting(mode_),
    329                           apm_->proc_sample_rate_hz());
    330 }
    331 
    332 int GainControlImpl::ConfigureHandle(void* handle) const {
    333   WebRtcAgc_config_t config;
    334   // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
    335   //            change the interface.
    336   //assert(target_level_dbfs_ <= 0);
    337   //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
    338   config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
    339   config.compressionGaindB =
    340       static_cast<int16_t>(compression_gain_db_);
    341   config.limiterEnable = limiter_enabled_;
    342 
    343   return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
    344 }
    345 
    346 int GainControlImpl::num_handles_required() const {
    347   return apm_->num_output_channels();
    348 }
    349 
    350 int GainControlImpl::GetHandleError(void* handle) const {
    351   // The AGC has no get_error() function.
    352   // (Despite listing errors in its interface...)
    353   assert(handle != NULL);
    354   return apm_->kUnspecifiedError;
    355 }
    356 }  // namespace webrtc
    357