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