Home | History | Annotate | Download | only in source
      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_control_mobile_impl.h"
     12 
     13 #include <cassert>
     14 
     15 #include "critical_section_wrapper.h"
     16 #include "echo_control_mobile.h"
     17 
     18 #include "audio_processing_impl.h"
     19 #include "audio_buffer.h"
     20 
     21 namespace webrtc {
     22 
     23 typedef void Handle;
     24 
     25 namespace {
     26 WebRtc_Word16 MapSetting(EchoControlMobile::RoutingMode mode) {
     27   switch (mode) {
     28     case EchoControlMobile::kQuietEarpieceOrHeadset:
     29       return 0;
     30     case EchoControlMobile::kEarpiece:
     31       return 1;
     32     case EchoControlMobile::kLoudEarpiece:
     33       return 2;
     34     case EchoControlMobile::kSpeakerphone:
     35       return 3;
     36     case EchoControlMobile::kLoudSpeakerphone:
     37       return 4;
     38     default:
     39       return -1;
     40   }
     41 }
     42 
     43 int MapError(int err) {
     44   switch (err) {
     45     case AECM_UNSUPPORTED_FUNCTION_ERROR:
     46       return AudioProcessing::kUnsupportedFunctionError;
     47     case AECM_BAD_PARAMETER_ERROR:
     48       return AudioProcessing::kBadParameterError;
     49     case AECM_BAD_PARAMETER_WARNING:
     50       return AudioProcessing::kBadStreamParameterWarning;
     51     default:
     52       // AECMOBFIX_UNSPECIFIED_ERROR
     53       // AECMOBFIX_UNINITIALIZED_ERROR
     54       // AECMOBFIX_NULL_POINTER_ERROR
     55       return AudioProcessing::kUnspecifiedError;
     56   }
     57 }
     58 }  // namespace
     59 
     60 EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessingImpl* apm)
     61   : ProcessingComponent(apm),
     62     apm_(apm),
     63     routing_mode_(kSpeakerphone),
     64     comfort_noise_enabled_(true) {}
     65 
     66 EchoControlMobileImpl::~EchoControlMobileImpl() {}
     67 
     68 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) {
     69   if (!is_component_enabled()) {
     70     return apm_->kNoError;
     71   }
     72 
     73   assert(audio->samples_per_split_channel() <= 160);
     74   assert(audio->num_channels() == apm_->num_reverse_channels());
     75 
     76   int err = apm_->kNoError;
     77 
     78   // The ordering convention must be followed to pass to the correct AECM.
     79   size_t handle_index = 0;
     80   for (int i = 0; i < apm_->num_output_channels(); i++) {
     81     for (int j = 0; j < audio->num_channels(); j++) {
     82       Handle* my_handle = static_cast<Handle*>(handle(handle_index));
     83       err = WebRtcAecm_BufferFarend(
     84           my_handle,
     85           audio->low_pass_split_data(j),
     86           static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
     87 
     88       if (err != apm_->kNoError) {
     89         return GetHandleError(my_handle);  // TODO(ajm): warning possible?
     90       }
     91 
     92       handle_index++;
     93     }
     94   }
     95 
     96   return apm_->kNoError;
     97 }
     98 
     99 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) {
    100   if (!is_component_enabled()) {
    101     return apm_->kNoError;
    102   }
    103 
    104   if (!apm_->was_stream_delay_set()) {
    105     return apm_->kStreamParameterNotSetError;
    106   }
    107 
    108   assert(audio->samples_per_split_channel() <= 160);
    109   assert(audio->num_channels() == apm_->num_output_channels());
    110 
    111   int err = apm_->kNoError;
    112 
    113   // The ordering convention must be followed to pass to the correct AECM.
    114   size_t handle_index = 0;
    115   for (int i = 0; i < audio->num_channels(); i++) {
    116     // TODO(ajm): improve how this works, possibly inside AECM.
    117     //            This is kind of hacked up.
    118     WebRtc_Word16* noisy = audio->low_pass_reference(i);
    119     WebRtc_Word16* clean = audio->low_pass_split_data(i);
    120     if (noisy == NULL) {
    121       noisy = clean;
    122       clean = NULL;
    123     }
    124     for (int j = 0; j < apm_->num_reverse_channels(); j++) {
    125       Handle* my_handle = static_cast<Handle*>(handle(handle_index));
    126       err = WebRtcAecm_Process(
    127           my_handle,
    128           noisy,
    129           clean,
    130           audio->low_pass_split_data(i),
    131           static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
    132           apm_->stream_delay_ms());
    133 
    134       if (err != apm_->kNoError) {
    135         return GetHandleError(my_handle);  // TODO(ajm): warning possible?
    136       }
    137 
    138       handle_index++;
    139     }
    140   }
    141 
    142   return apm_->kNoError;
    143 }
    144 
    145 int EchoControlMobileImpl::Enable(bool enable) {
    146   CriticalSectionScoped crit_scoped(*apm_->crit());
    147   // Ensure AEC and AECM are not both enabled.
    148   if (enable && apm_->echo_cancellation()->is_enabled()) {
    149     return apm_->kBadParameterError;
    150   }
    151 
    152   return EnableComponent(enable);
    153 }
    154 
    155 bool EchoControlMobileImpl::is_enabled() const {
    156   return is_component_enabled();
    157 }
    158 
    159 int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
    160   CriticalSectionScoped crit_scoped(*apm_->crit());
    161   if (MapSetting(mode) == -1) {
    162     return apm_->kBadParameterError;
    163   }
    164 
    165   routing_mode_ = mode;
    166   return Configure();
    167 }
    168 
    169 EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
    170     const {
    171   return routing_mode_;
    172 }
    173 
    174 int EchoControlMobileImpl::enable_comfort_noise(bool enable) {
    175   CriticalSectionScoped crit_scoped(*apm_->crit());
    176   comfort_noise_enabled_ = enable;
    177   return Configure();
    178 }
    179 
    180 bool EchoControlMobileImpl::is_comfort_noise_enabled() const {
    181   return comfort_noise_enabled_;
    182 }
    183 
    184 int EchoControlMobileImpl::Initialize() {
    185   if (!is_component_enabled()) {
    186     return apm_->kNoError;
    187   }
    188 
    189   if (apm_->sample_rate_hz() == apm_->kSampleRate32kHz) {
    190     // AECM doesn't support super-wideband.
    191     return apm_->kBadSampleRateError;
    192   }
    193 
    194   return ProcessingComponent::Initialize();
    195 }
    196 
    197 int EchoControlMobileImpl::get_version(char* version,
    198                                        int version_len_bytes) const {
    199   if (WebRtcAecm_get_version(version, version_len_bytes) != 0) {
    200       return apm_->kBadParameterError;
    201   }
    202 
    203   return apm_->kNoError;
    204 }
    205 
    206 void* EchoControlMobileImpl::CreateHandle() const {
    207   Handle* handle = NULL;
    208   if (WebRtcAecm_Create(&handle) != apm_->kNoError) {
    209     handle = NULL;
    210   } else {
    211     assert(handle != NULL);
    212   }
    213 
    214   return handle;
    215 }
    216 
    217 int EchoControlMobileImpl::DestroyHandle(void* handle) const {
    218   return WebRtcAecm_Free(static_cast<Handle*>(handle));
    219 }
    220 
    221 int EchoControlMobileImpl::InitializeHandle(void* handle) const {
    222   return WebRtcAecm_Init(static_cast<Handle*>(handle),
    223                          apm_->sample_rate_hz(),
    224                          48000); // Dummy value. This isn't actually
    225                                  // required by AECM.
    226 }
    227 
    228 int EchoControlMobileImpl::ConfigureHandle(void* handle) const {
    229   AecmConfig config;
    230   config.cngMode = comfort_noise_enabled_;
    231   config.echoMode = MapSetting(routing_mode_);
    232 
    233   return WebRtcAecm_set_config(static_cast<Handle*>(handle), config);
    234 }
    235 
    236 int EchoControlMobileImpl::num_handles_required() const {
    237   return apm_->num_output_channels() *
    238          apm_->num_reverse_channels();
    239 }
    240 
    241 int EchoControlMobileImpl::GetHandleError(void* handle) const {
    242   assert(handle != NULL);
    243   return MapError(WebRtcAecm_get_error_code(static_cast<Handle*>(handle)));
    244 }
    245 }  // namespace webrtc
    246