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_control_mobile_impl.h"
     12 
     13 #include <cassert>
     14 #include <cstring>
     15 
     16 #include "critical_section_wrapper.h"
     17 #include "echo_control_mobile.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(EchoControlMobile::RoutingMode mode) {
     28   switch (mode) {
     29     case EchoControlMobile::kQuietEarpieceOrHeadset:
     30       return 0;
     31     case EchoControlMobile::kEarpiece:
     32       return 1;
     33     case EchoControlMobile::kLoudEarpiece:
     34       return 2;
     35     case EchoControlMobile::kSpeakerphone:
     36       return 3;
     37     case EchoControlMobile::kLoudSpeakerphone:
     38       return 4;
     39     default:
     40       return -1;
     41   }
     42 }
     43 
     44 int MapError(int err) {
     45   switch (err) {
     46     case AECM_UNSUPPORTED_FUNCTION_ERROR:
     47       return AudioProcessing::kUnsupportedFunctionError;
     48     case AECM_NULL_POINTER_ERROR:
     49       return AudioProcessing::kNullPointerError;
     50     case AECM_BAD_PARAMETER_ERROR:
     51       return AudioProcessing::kBadParameterError;
     52     case AECM_BAD_PARAMETER_WARNING:
     53       return AudioProcessing::kBadStreamParameterWarning;
     54     default:
     55       // AECM_UNSPECIFIED_ERROR
     56       // AECM_UNINITIALIZED_ERROR
     57       return AudioProcessing::kUnspecifiedError;
     58   }
     59 }
     60 }  // namespace
     61 
     62 size_t EchoControlMobile::echo_path_size_bytes() {
     63     return WebRtcAecm_echo_path_size_bytes();
     64 }
     65 
     66 EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessingImpl* apm)
     67   : ProcessingComponent(apm),
     68     apm_(apm),
     69     routing_mode_(kSpeakerphone),
     70     comfort_noise_enabled_(true),
     71     external_echo_path_(NULL) {}
     72 
     73 EchoControlMobileImpl::~EchoControlMobileImpl() {
     74     if (external_echo_path_ != NULL) {
     75       delete [] external_echo_path_;
     76       external_echo_path_ = NULL;
     77     }
     78 }
     79 
     80 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) {
     81   if (!is_component_enabled()) {
     82     return apm_->kNoError;
     83   }
     84 
     85   assert(audio->samples_per_split_channel() <= 160);
     86   assert(audio->num_channels() == apm_->num_reverse_channels());
     87 
     88   int err = apm_->kNoError;
     89 
     90   // The ordering convention must be followed to pass to the correct AECM.
     91   size_t handle_index = 0;
     92   for (int i = 0; i < apm_->num_output_channels(); i++) {
     93     for (int j = 0; j < audio->num_channels(); j++) {
     94       Handle* my_handle = static_cast<Handle*>(handle(handle_index));
     95       err = WebRtcAecm_BufferFarend(
     96           my_handle,
     97           audio->low_pass_split_data(j),
     98           static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
     99 
    100       if (err != apm_->kNoError) {
    101         return GetHandleError(my_handle);  // TODO(ajm): warning possible?
    102       }
    103 
    104       handle_index++;
    105     }
    106   }
    107 
    108   return apm_->kNoError;
    109 }
    110 
    111 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) {
    112   if (!is_component_enabled()) {
    113     return apm_->kNoError;
    114   }
    115 
    116   if (!apm_->was_stream_delay_set()) {
    117     return apm_->kStreamParameterNotSetError;
    118   }
    119 
    120   assert(audio->samples_per_split_channel() <= 160);
    121   assert(audio->num_channels() == apm_->num_output_channels());
    122 
    123   int err = apm_->kNoError;
    124 
    125   // The ordering convention must be followed to pass to the correct AECM.
    126   size_t handle_index = 0;
    127   for (int i = 0; i < audio->num_channels(); i++) {
    128     // TODO(ajm): improve how this works, possibly inside AECM.
    129     //            This is kind of hacked up.
    130     WebRtc_Word16* noisy = audio->low_pass_reference(i);
    131     WebRtc_Word16* clean = audio->low_pass_split_data(i);
    132     if (noisy == NULL) {
    133       noisy = clean;
    134       clean = NULL;
    135     }
    136     for (int j = 0; j < apm_->num_reverse_channels(); j++) {
    137       Handle* my_handle = static_cast<Handle*>(handle(handle_index));
    138       err = WebRtcAecm_Process(
    139           my_handle,
    140           noisy,
    141           clean,
    142           audio->low_pass_split_data(i),
    143           static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
    144           apm_->stream_delay_ms());
    145 
    146       if (err != apm_->kNoError) {
    147         return GetHandleError(my_handle);  // TODO(ajm): warning possible?
    148       }
    149 
    150       handle_index++;
    151     }
    152   }
    153 
    154   return apm_->kNoError;
    155 }
    156 
    157 int EchoControlMobileImpl::Enable(bool enable) {
    158   CriticalSectionScoped crit_scoped(*apm_->crit());
    159   // Ensure AEC and AECM are not both enabled.
    160   if (enable && apm_->echo_cancellation()->is_enabled()) {
    161     return apm_->kBadParameterError;
    162   }
    163 
    164   return EnableComponent(enable);
    165 }
    166 
    167 bool EchoControlMobileImpl::is_enabled() const {
    168   return is_component_enabled();
    169 }
    170 
    171 int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
    172   CriticalSectionScoped crit_scoped(*apm_->crit());
    173   if (MapSetting(mode) == -1) {
    174     return apm_->kBadParameterError;
    175   }
    176 
    177   routing_mode_ = mode;
    178   return Configure();
    179 }
    180 
    181 EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
    182     const {
    183   return routing_mode_;
    184 }
    185 
    186 int EchoControlMobileImpl::enable_comfort_noise(bool enable) {
    187   CriticalSectionScoped crit_scoped(*apm_->crit());
    188   comfort_noise_enabled_ = enable;
    189   return Configure();
    190 }
    191 
    192 bool EchoControlMobileImpl::is_comfort_noise_enabled() const {
    193   return comfort_noise_enabled_;
    194 }
    195 
    196 int EchoControlMobileImpl::SetEchoPath(const void* echo_path,
    197                                        size_t size_bytes) {
    198   CriticalSectionScoped crit_scoped(*apm_->crit());
    199   if (echo_path == NULL) {
    200     return apm_->kNullPointerError;
    201   }
    202   if (size_bytes != echo_path_size_bytes()) {
    203     // Size mismatch
    204     return apm_->kBadParameterError;
    205   }
    206 
    207   if (external_echo_path_ == NULL) {
    208     external_echo_path_ = new unsigned char[size_bytes];
    209   }
    210   memcpy(external_echo_path_, echo_path, size_bytes);
    211 
    212   return Initialize();
    213 }
    214 
    215 int EchoControlMobileImpl::GetEchoPath(void* echo_path,
    216                                        size_t size_bytes) const {
    217   CriticalSectionScoped crit_scoped(*apm_->crit());
    218   if (echo_path == NULL) {
    219     return apm_->kNullPointerError;
    220   }
    221   if (size_bytes != echo_path_size_bytes()) {
    222     // Size mismatch
    223     return apm_->kBadParameterError;
    224   }
    225   if (!is_component_enabled()) {
    226     return apm_->kNotEnabledError;
    227   }
    228 
    229   // Get the echo path from the first channel
    230   Handle* my_handle = static_cast<Handle*>(handle(0));
    231   if (WebRtcAecm_GetEchoPath(my_handle, echo_path, size_bytes) != 0) {
    232       return GetHandleError(my_handle);
    233   }
    234 
    235   return apm_->kNoError;
    236 }
    237 
    238 int EchoControlMobileImpl::Initialize() {
    239   if (!is_component_enabled()) {
    240     return apm_->kNoError;
    241   }
    242 
    243   if (apm_->sample_rate_hz() == apm_->kSampleRate32kHz) {
    244     // AECM doesn't support super-wideband.
    245     return apm_->kBadSampleRateError;
    246   }
    247 
    248   return ProcessingComponent::Initialize();
    249 }
    250 
    251 int EchoControlMobileImpl::get_version(char* version,
    252                                        int version_len_bytes) const {
    253   if (WebRtcAecm_get_version(version, version_len_bytes) != 0) {
    254     return apm_->kBadParameterError;
    255   }
    256 
    257   return apm_->kNoError;
    258 }
    259 
    260 void* EchoControlMobileImpl::CreateHandle() const {
    261   Handle* handle = NULL;
    262   if (WebRtcAecm_Create(&handle) != apm_->kNoError) {
    263     handle = NULL;
    264   } else {
    265     assert(handle != NULL);
    266   }
    267 
    268   return handle;
    269 }
    270 
    271 int EchoControlMobileImpl::DestroyHandle(void* handle) const {
    272   return WebRtcAecm_Free(static_cast<Handle*>(handle));
    273 }
    274 
    275 int EchoControlMobileImpl::InitializeHandle(void* handle) const {
    276   assert(handle != NULL);
    277   Handle* my_handle = static_cast<Handle*>(handle);
    278   if (WebRtcAecm_Init(my_handle, apm_->sample_rate_hz()) != 0) {
    279     return GetHandleError(my_handle);
    280   }
    281   if (external_echo_path_ != NULL) {
    282     if (WebRtcAecm_InitEchoPath(my_handle,
    283                                 external_echo_path_,
    284                                 echo_path_size_bytes()) != 0) {
    285       return GetHandleError(my_handle);
    286     }
    287   }
    288 
    289   return apm_->kNoError;
    290 }
    291 
    292 int EchoControlMobileImpl::ConfigureHandle(void* handle) const {
    293   AecmConfig config;
    294   config.cngMode = comfort_noise_enabled_;
    295   config.echoMode = MapSetting(routing_mode_);
    296 
    297   return WebRtcAecm_set_config(static_cast<Handle*>(handle), config);
    298 }
    299 
    300 int EchoControlMobileImpl::num_handles_required() const {
    301   return apm_->num_output_channels() *
    302          apm_->num_reverse_channels();
    303 }
    304 
    305 int EchoControlMobileImpl::GetHandleError(void* handle) const {
    306   assert(handle != NULL);
    307   return MapError(WebRtcAecm_get_error_code(static_cast<Handle*>(handle)));
    308 }
    309 }  // namespace webrtc
    310