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