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/echo_cancellation_impl.h"
     12 
     13 #include <assert.h>
     14 #include <string.h>
     15 
     16 extern "C" {
     17 #include "webrtc/modules/audio_processing/aec/aec_core.h"
     18 }
     19 #include "webrtc/modules/audio_processing/aec/include/echo_cancellation.h"
     20 #include "webrtc/modules/audio_processing/audio_buffer.h"
     21 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
     22 
     23 namespace webrtc {
     24 
     25 typedef void Handle;
     26 
     27 namespace {
     28 int16_t MapSetting(EchoCancellation::SuppressionLevel level) {
     29   switch (level) {
     30     case EchoCancellation::kLowSuppression:
     31       return kAecNlpConservative;
     32     case EchoCancellation::kModerateSuppression:
     33       return kAecNlpModerate;
     34     case EchoCancellation::kHighSuppression:
     35       return kAecNlpAggressive;
     36   }
     37   assert(false);
     38   return -1;
     39 }
     40 
     41 AudioProcessing::Error MapError(int err) {
     42   switch (err) {
     43     case AEC_UNSUPPORTED_FUNCTION_ERROR:
     44       return AudioProcessing::kUnsupportedFunctionError;
     45     case AEC_BAD_PARAMETER_ERROR:
     46       return AudioProcessing::kBadParameterError;
     47     case AEC_BAD_PARAMETER_WARNING:
     48       return AudioProcessing::kBadStreamParameterWarning;
     49     default:
     50       // AEC_UNSPECIFIED_ERROR
     51       // AEC_UNINITIALIZED_ERROR
     52       // AEC_NULL_POINTER_ERROR
     53       return AudioProcessing::kUnspecifiedError;
     54   }
     55 }
     56 }  // namespace
     57 
     58 EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm,
     59                                            CriticalSectionWrapper* crit)
     60   : ProcessingComponent(),
     61     apm_(apm),
     62     crit_(crit),
     63     drift_compensation_enabled_(false),
     64     metrics_enabled_(false),
     65     suppression_level_(kModerateSuppression),
     66     stream_drift_samples_(0),
     67     was_stream_drift_set_(false),
     68     stream_has_echo_(false),
     69     delay_logging_enabled_(false),
     70     delay_correction_enabled_(false),
     71     reported_delay_enabled_(true) {}
     72 
     73 EchoCancellationImpl::~EchoCancellationImpl() {}
     74 
     75 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
     76   if (!is_component_enabled()) {
     77     return apm_->kNoError;
     78   }
     79 
     80   assert(audio->samples_per_split_channel() <= 160);
     81   assert(audio->num_channels() == apm_->num_reverse_channels());
     82 
     83   int err = apm_->kNoError;
     84 
     85   // The ordering convention must be followed to pass to the correct AEC.
     86   size_t handle_index = 0;
     87   for (int i = 0; i < apm_->num_output_channels(); i++) {
     88     for (int j = 0; j < audio->num_channels(); j++) {
     89       Handle* my_handle = static_cast<Handle*>(handle(handle_index));
     90       err = WebRtcAec_BufferFarend(
     91           my_handle,
     92           audio->low_pass_split_data_f(j),
     93           static_cast<int16_t>(audio->samples_per_split_channel()));
     94 
     95       if (err != apm_->kNoError) {
     96         return GetHandleError(my_handle);  // TODO(ajm): warning possible?
     97       }
     98 
     99       handle_index++;
    100     }
    101   }
    102 
    103   return apm_->kNoError;
    104 }
    105 
    106 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) {
    107   if (!is_component_enabled()) {
    108     return apm_->kNoError;
    109   }
    110 
    111   if (!apm_->was_stream_delay_set()) {
    112     return apm_->kStreamParameterNotSetError;
    113   }
    114 
    115   if (drift_compensation_enabled_ && !was_stream_drift_set_) {
    116     return apm_->kStreamParameterNotSetError;
    117   }
    118 
    119   assert(audio->samples_per_split_channel() <= 160);
    120   assert(audio->num_channels() == apm_->num_output_channels());
    121 
    122   int err = apm_->kNoError;
    123 
    124   // The ordering convention must be followed to pass to the correct AEC.
    125   size_t handle_index = 0;
    126   stream_has_echo_ = false;
    127   for (int i = 0; i < audio->num_channels(); i++) {
    128     for (int j = 0; j < apm_->num_reverse_channels(); j++) {
    129       Handle* my_handle = handle(handle_index);
    130       err = WebRtcAec_Process(
    131           my_handle,
    132           audio->low_pass_split_data_f(i),
    133           audio->high_pass_split_data_f(i),
    134           audio->low_pass_split_data_f(i),
    135           audio->high_pass_split_data_f(i),
    136           static_cast<int16_t>(audio->samples_per_split_channel()),
    137           apm_->stream_delay_ms(),
    138           stream_drift_samples_);
    139 
    140       if (err != apm_->kNoError) {
    141         err = GetHandleError(my_handle);
    142         // TODO(ajm): Figure out how to return warnings properly.
    143         if (err != apm_->kBadStreamParameterWarning) {
    144           return err;
    145         }
    146       }
    147 
    148       int status = 0;
    149       err = WebRtcAec_get_echo_status(my_handle, &status);
    150       if (err != apm_->kNoError) {
    151         return GetHandleError(my_handle);
    152       }
    153 
    154       if (status == 1) {
    155         stream_has_echo_ = true;
    156       }
    157 
    158       handle_index++;
    159     }
    160   }
    161 
    162   was_stream_drift_set_ = false;
    163   return apm_->kNoError;
    164 }
    165 
    166 int EchoCancellationImpl::Enable(bool enable) {
    167   CriticalSectionScoped crit_scoped(crit_);
    168   // Ensure AEC and AECM are not both enabled.
    169   if (enable && apm_->echo_control_mobile()->is_enabled()) {
    170     return apm_->kBadParameterError;
    171   }
    172 
    173   return EnableComponent(enable);
    174 }
    175 
    176 bool EchoCancellationImpl::is_enabled() const {
    177   return is_component_enabled();
    178 }
    179 
    180 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) {
    181   CriticalSectionScoped crit_scoped(crit_);
    182   if (MapSetting(level) == -1) {
    183     return apm_->kBadParameterError;
    184   }
    185 
    186   suppression_level_ = level;
    187   return Configure();
    188 }
    189 
    190 EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level()
    191     const {
    192   return suppression_level_;
    193 }
    194 
    195 int EchoCancellationImpl::enable_drift_compensation(bool enable) {
    196   CriticalSectionScoped crit_scoped(crit_);
    197   drift_compensation_enabled_ = enable;
    198   return Configure();
    199 }
    200 
    201 bool EchoCancellationImpl::is_drift_compensation_enabled() const {
    202   return drift_compensation_enabled_;
    203 }
    204 
    205 void EchoCancellationImpl::set_stream_drift_samples(int drift) {
    206   was_stream_drift_set_ = true;
    207   stream_drift_samples_ = drift;
    208 }
    209 
    210 int EchoCancellationImpl::stream_drift_samples() const {
    211   return stream_drift_samples_;
    212 }
    213 
    214 int EchoCancellationImpl::enable_metrics(bool enable) {
    215   CriticalSectionScoped crit_scoped(crit_);
    216   metrics_enabled_ = enable;
    217   return Configure();
    218 }
    219 
    220 bool EchoCancellationImpl::are_metrics_enabled() const {
    221   return metrics_enabled_;
    222 }
    223 
    224 // TODO(ajm): we currently just use the metrics from the first AEC. Think more
    225 //            aboue the best way to extend this to multi-channel.
    226 int EchoCancellationImpl::GetMetrics(Metrics* metrics) {
    227   CriticalSectionScoped crit_scoped(crit_);
    228   if (metrics == NULL) {
    229     return apm_->kNullPointerError;
    230   }
    231 
    232   if (!is_component_enabled() || !metrics_enabled_) {
    233     return apm_->kNotEnabledError;
    234   }
    235 
    236   AecMetrics my_metrics;
    237   memset(&my_metrics, 0, sizeof(my_metrics));
    238   memset(metrics, 0, sizeof(Metrics));
    239 
    240   Handle* my_handle = static_cast<Handle*>(handle(0));
    241   int err = WebRtcAec_GetMetrics(my_handle, &my_metrics);
    242   if (err != apm_->kNoError) {
    243     return GetHandleError(my_handle);
    244   }
    245 
    246   metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant;
    247   metrics->residual_echo_return_loss.average = my_metrics.rerl.average;
    248   metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max;
    249   metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min;
    250 
    251   metrics->echo_return_loss.instant = my_metrics.erl.instant;
    252   metrics->echo_return_loss.average = my_metrics.erl.average;
    253   metrics->echo_return_loss.maximum = my_metrics.erl.max;
    254   metrics->echo_return_loss.minimum = my_metrics.erl.min;
    255 
    256   metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant;
    257   metrics->echo_return_loss_enhancement.average = my_metrics.erle.average;
    258   metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max;
    259   metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min;
    260 
    261   metrics->a_nlp.instant = my_metrics.aNlp.instant;
    262   metrics->a_nlp.average = my_metrics.aNlp.average;
    263   metrics->a_nlp.maximum = my_metrics.aNlp.max;
    264   metrics->a_nlp.minimum = my_metrics.aNlp.min;
    265 
    266   return apm_->kNoError;
    267 }
    268 
    269 bool EchoCancellationImpl::stream_has_echo() const {
    270   return stream_has_echo_;
    271 }
    272 
    273 int EchoCancellationImpl::enable_delay_logging(bool enable) {
    274   CriticalSectionScoped crit_scoped(crit_);
    275   delay_logging_enabled_ = enable;
    276   return Configure();
    277 }
    278 
    279 bool EchoCancellationImpl::is_delay_logging_enabled() const {
    280   return delay_logging_enabled_;
    281 }
    282 
    283 // TODO(bjornv): How should we handle the multi-channel case?
    284 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) {
    285   CriticalSectionScoped crit_scoped(crit_);
    286   if (median == NULL) {
    287     return apm_->kNullPointerError;
    288   }
    289   if (std == NULL) {
    290     return apm_->kNullPointerError;
    291   }
    292 
    293   if (!is_component_enabled() || !delay_logging_enabled_) {
    294     return apm_->kNotEnabledError;
    295   }
    296 
    297   Handle* my_handle = static_cast<Handle*>(handle(0));
    298   if (WebRtcAec_GetDelayMetrics(my_handle, median, std) !=
    299       apm_->kNoError) {
    300     return GetHandleError(my_handle);
    301   }
    302 
    303   return apm_->kNoError;
    304 }
    305 
    306 struct AecCore* EchoCancellationImpl::aec_core() const {
    307   CriticalSectionScoped crit_scoped(crit_);
    308   if (!is_component_enabled()) {
    309     return NULL;
    310   }
    311   Handle* my_handle = static_cast<Handle*>(handle(0));
    312   return WebRtcAec_aec_core(my_handle);
    313 }
    314 
    315 int EchoCancellationImpl::Initialize() {
    316   int err = ProcessingComponent::Initialize();
    317   if (err != apm_->kNoError || !is_component_enabled()) {
    318     return err;
    319   }
    320 
    321   return apm_->kNoError;
    322 }
    323 
    324 void EchoCancellationImpl::SetExtraOptions(const Config& config) {
    325   delay_correction_enabled_ = config.Get<DelayCorrection>().enabled;
    326   reported_delay_enabled_ = config.Get<ReportedDelay>().enabled;
    327   Configure();
    328 }
    329 
    330 void* EchoCancellationImpl::CreateHandle() const {
    331   Handle* handle = NULL;
    332   if (WebRtcAec_Create(&handle) != apm_->kNoError) {
    333     handle = NULL;
    334   } else {
    335     assert(handle != NULL);
    336   }
    337 
    338   return handle;
    339 }
    340 
    341 void EchoCancellationImpl::DestroyHandle(void* handle) const {
    342   assert(handle != NULL);
    343   WebRtcAec_Free(static_cast<Handle*>(handle));
    344 }
    345 
    346 int EchoCancellationImpl::InitializeHandle(void* handle) const {
    347   assert(handle != NULL);
    348   // TODO(ajm): Drift compensation is disabled in practice. If restored, it
    349   // should be managed internally and not depend on the hardware sample rate.
    350   // For now, just hardcode a 48 kHz value.
    351   return WebRtcAec_Init(static_cast<Handle*>(handle),
    352                        apm_->proc_sample_rate_hz(),
    353                        48000);
    354 }
    355 
    356 int EchoCancellationImpl::ConfigureHandle(void* handle) const {
    357   assert(handle != NULL);
    358   AecConfig config;
    359   config.metricsMode = metrics_enabled_;
    360   config.nlpMode = MapSetting(suppression_level_);
    361   config.skewMode = drift_compensation_enabled_;
    362   config.delay_logging = delay_logging_enabled_;
    363 
    364   WebRtcAec_enable_delay_correction(WebRtcAec_aec_core(
    365       static_cast<Handle*>(handle)), delay_correction_enabled_ ? 1 : 0);
    366   WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(
    367       static_cast<Handle*>(handle)), reported_delay_enabled_ ? 1 : 0);
    368   return WebRtcAec_set_config(static_cast<Handle*>(handle), config);
    369 }
    370 
    371 int EchoCancellationImpl::num_handles_required() const {
    372   return apm_->num_output_channels() *
    373          apm_->num_reverse_channels();
    374 }
    375 
    376 int EchoCancellationImpl::GetHandleError(void* handle) const {
    377   assert(handle != NULL);
    378   return MapError(WebRtcAec_get_error_code(static_cast<Handle*>(handle)));
    379 }
    380 }  // namespace webrtc
    381