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