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