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 71 EchoCancellationImpl::~EchoCancellationImpl() {} 72 73 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { 74 if (!is_component_enabled()) { 75 return apm_->kNoError; 76 } 77 78 assert(audio->samples_per_split_channel() <= 160); 79 assert(audio->num_channels() == apm_->num_reverse_channels()); 80 81 int err = apm_->kNoError; 82 83 // The ordering convention must be followed to pass to the correct AEC. 84 size_t handle_index = 0; 85 for (int i = 0; i < apm_->num_output_channels(); i++) { 86 for (int j = 0; j < audio->num_channels(); j++) { 87 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); 88 err = WebRtcAec_BufferFarend( 89 my_handle, 90 audio->low_pass_split_data(j), 91 static_cast<WebRtc_Word16>(audio->samples_per_split_channel())); 92 93 if (err != apm_->kNoError) { 94 return GetHandleError(my_handle); // TODO(ajm): warning possible? 95 } 96 97 handle_index++; 98 } 99 } 100 101 return apm_->kNoError; 102 } 103 104 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { 105 if (!is_component_enabled()) { 106 return apm_->kNoError; 107 } 108 109 if (!apm_->was_stream_delay_set()) { 110 return apm_->kStreamParameterNotSetError; 111 } 112 113 if (drift_compensation_enabled_ && !was_stream_drift_set_) { 114 return apm_->kStreamParameterNotSetError; 115 } 116 117 assert(audio->samples_per_split_channel() <= 160); 118 assert(audio->num_channels() == apm_->num_output_channels()); 119 120 int err = apm_->kNoError; 121 122 // The ordering convention must be followed to pass to the correct AEC. 123 size_t handle_index = 0; 124 stream_has_echo_ = false; 125 for (int i = 0; i < audio->num_channels(); i++) { 126 for (int j = 0; j < apm_->num_reverse_channels(); j++) { 127 Handle* my_handle = handle(handle_index); 128 err = WebRtcAec_Process( 129 my_handle, 130 audio->low_pass_split_data(i), 131 audio->high_pass_split_data(i), 132 audio->low_pass_split_data(i), 133 audio->high_pass_split_data(i), 134 static_cast<WebRtc_Word16>(audio->samples_per_split_channel()), 135 apm_->stream_delay_ms(), 136 stream_drift_samples_); 137 138 if (err != apm_->kNoError) { 139 err = GetHandleError(my_handle); 140 // TODO(ajm): Figure out how to return warnings properly. 141 if (err != apm_->kBadStreamParameterWarning) { 142 return err; 143 } 144 } 145 146 WebRtc_Word16 status = 0; 147 err = WebRtcAec_get_echo_status(my_handle, &status); 148 if (err != apm_->kNoError) { 149 return GetHandleError(my_handle); 150 } 151 152 if (status == 1) { 153 stream_has_echo_ = true; 154 } 155 156 handle_index++; 157 } 158 } 159 160 was_stream_drift_set_ = false; 161 return apm_->kNoError; 162 } 163 164 int EchoCancellationImpl::Enable(bool enable) { 165 CriticalSectionScoped crit_scoped(*apm_->crit()); 166 // Ensure AEC and AECM are not both enabled. 167 if (enable && apm_->echo_control_mobile()->is_enabled()) { 168 return apm_->kBadParameterError; 169 } 170 171 return EnableComponent(enable); 172 } 173 174 bool EchoCancellationImpl::is_enabled() const { 175 return is_component_enabled(); 176 } 177 178 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) { 179 CriticalSectionScoped crit_scoped(*apm_->crit()); 180 if (MapSetting(level) == -1) { 181 return apm_->kBadParameterError; 182 } 183 184 suppression_level_ = level; 185 return Configure(); 186 } 187 188 EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level() 189 const { 190 return suppression_level_; 191 } 192 193 int EchoCancellationImpl::enable_drift_compensation(bool enable) { 194 CriticalSectionScoped crit_scoped(*apm_->crit()); 195 drift_compensation_enabled_ = enable; 196 return Configure(); 197 } 198 199 bool EchoCancellationImpl::is_drift_compensation_enabled() const { 200 return drift_compensation_enabled_; 201 } 202 203 int EchoCancellationImpl::set_device_sample_rate_hz(int rate) { 204 CriticalSectionScoped crit_scoped(*apm_->crit()); 205 if (rate < 8000 || rate > 96000) { 206 return apm_->kBadParameterError; 207 } 208 209 device_sample_rate_hz_ = rate; 210 return Initialize(); 211 } 212 213 int EchoCancellationImpl::device_sample_rate_hz() const { 214 return device_sample_rate_hz_; 215 } 216 217 int EchoCancellationImpl::set_stream_drift_samples(int drift) { 218 was_stream_drift_set_ = true; 219 stream_drift_samples_ = drift; 220 return apm_->kNoError; 221 } 222 223 int EchoCancellationImpl::stream_drift_samples() const { 224 return stream_drift_samples_; 225 } 226 227 int EchoCancellationImpl::enable_metrics(bool enable) { 228 CriticalSectionScoped crit_scoped(*apm_->crit()); 229 metrics_enabled_ = enable; 230 return Configure(); 231 } 232 233 bool EchoCancellationImpl::are_metrics_enabled() const { 234 return metrics_enabled_; 235 } 236 237 // TODO(ajm): we currently just use the metrics from the first AEC. Think more 238 // aboue the best way to extend this to multi-channel. 239 int EchoCancellationImpl::GetMetrics(Metrics* metrics) { 240 CriticalSectionScoped crit_scoped(*apm_->crit()); 241 if (metrics == NULL) { 242 return apm_->kNullPointerError; 243 } 244 245 if (!is_component_enabled() || !metrics_enabled_) { 246 return apm_->kNotEnabledError; 247 } 248 249 AecMetrics my_metrics; 250 memset(&my_metrics, 0, sizeof(my_metrics)); 251 memset(metrics, 0, sizeof(Metrics)); 252 253 Handle* my_handle = static_cast<Handle*>(handle(0)); 254 int err = WebRtcAec_GetMetrics(my_handle, &my_metrics); 255 if (err != apm_->kNoError) { 256 return GetHandleError(my_handle); 257 } 258 259 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant; 260 metrics->residual_echo_return_loss.average = my_metrics.rerl.average; 261 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max; 262 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min; 263 264 metrics->echo_return_loss.instant = my_metrics.erl.instant; 265 metrics->echo_return_loss.average = my_metrics.erl.average; 266 metrics->echo_return_loss.maximum = my_metrics.erl.max; 267 metrics->echo_return_loss.minimum = my_metrics.erl.min; 268 269 metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant; 270 metrics->echo_return_loss_enhancement.average = my_metrics.erle.average; 271 metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max; 272 metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min; 273 274 metrics->a_nlp.instant = my_metrics.aNlp.instant; 275 metrics->a_nlp.average = my_metrics.aNlp.average; 276 metrics->a_nlp.maximum = my_metrics.aNlp.max; 277 metrics->a_nlp.minimum = my_metrics.aNlp.min; 278 279 return apm_->kNoError; 280 } 281 282 bool EchoCancellationImpl::stream_has_echo() const { 283 return stream_has_echo_; 284 } 285 286 int EchoCancellationImpl::Initialize() { 287 int err = ProcessingComponent::Initialize(); 288 if (err != apm_->kNoError || !is_component_enabled()) { 289 return err; 290 } 291 292 was_stream_drift_set_ = false; 293 294 return apm_->kNoError; 295 } 296 297 int EchoCancellationImpl::get_version(char* version, 298 int version_len_bytes) const { 299 if (WebRtcAec_get_version(version, version_len_bytes) != 0) { 300 return apm_->kBadParameterError; 301 } 302 303 return apm_->kNoError; 304 } 305 306 void* EchoCancellationImpl::CreateHandle() const { 307 Handle* handle = NULL; 308 if (WebRtcAec_Create(&handle) != apm_->kNoError) { 309 handle = NULL; 310 } else { 311 assert(handle != NULL); 312 } 313 314 return handle; 315 } 316 317 int EchoCancellationImpl::DestroyHandle(void* handle) const { 318 assert(handle != NULL); 319 return WebRtcAec_Free(static_cast<Handle*>(handle)); 320 } 321 322 int EchoCancellationImpl::InitializeHandle(void* handle) const { 323 assert(handle != NULL); 324 return WebRtcAec_Init(static_cast<Handle*>(handle), 325 apm_->sample_rate_hz(), 326 device_sample_rate_hz_); 327 } 328 329 int EchoCancellationImpl::ConfigureHandle(void* handle) const { 330 assert(handle != NULL); 331 AecConfig config; 332 config.metricsMode = metrics_enabled_; 333 config.nlpMode = MapSetting(suppression_level_); 334 config.skewMode = drift_compensation_enabled_; 335 336 return WebRtcAec_set_config(static_cast<Handle*>(handle), config); 337 } 338 339 int EchoCancellationImpl::num_handles_required() const { 340 return apm_->num_output_channels() * 341 apm_->num_reverse_channels(); 342 } 343 344 int EchoCancellationImpl::GetHandleError(void* handle) const { 345 assert(handle != NULL); 346 return MapError(WebRtcAec_get_error_code(static_cast<Handle*>(handle))); 347 } 348 } // namespace webrtc 349