OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/audio_processing/echo_cancellation_impl.h" | 11 #include "webrtc/modules/audio_processing/echo_cancellation_impl.h" |
12 | 12 |
13 #include <assert.h> | 13 #include <assert.h> |
14 #include <string.h> | 14 #include <string.h> |
15 | 15 |
16 #include "webrtc/modules/audio_processing/aec/aec_core.h" | 16 #include "webrtc/modules/audio_processing/aec/aec_core.h" |
17 #include "webrtc/modules/audio_processing/aec/echo_cancellation.h" | 17 #include "webrtc/modules/audio_processing/aec/echo_cancellation.h" |
18 #include "webrtc/modules/audio_processing/audio_buffer.h" | 18 #include "webrtc/modules/audio_processing/audio_buffer.h" |
19 | 19 |
20 namespace webrtc { | 20 namespace webrtc { |
21 | 21 |
22 typedef void Handle; | |
23 | |
24 namespace { | 22 namespace { |
25 int16_t MapSetting(EchoCancellation::SuppressionLevel level) { | 23 int16_t MapSetting(EchoCancellation::SuppressionLevel level) { |
26 switch (level) { | 24 switch (level) { |
27 case EchoCancellation::kLowSuppression: | 25 case EchoCancellation::kLowSuppression: |
28 return kAecNlpConservative; | 26 return kAecNlpConservative; |
29 case EchoCancellation::kModerateSuppression: | 27 case EchoCancellation::kModerateSuppression: |
30 return kAecNlpModerate; | 28 return kAecNlpModerate; |
31 case EchoCancellation::kHighSuppression: | 29 case EchoCancellation::kHighSuppression: |
32 return kAecNlpAggressive; | 30 return kAecNlpAggressive; |
33 } | 31 } |
(...skipping 20 matching lines...) Expand all Loading... |
54 // Maximum length that a frame of samples can have. | 52 // Maximum length that a frame of samples can have. |
55 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; | 53 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; |
56 // Maximum number of frames to buffer in the render queue. | 54 // Maximum number of frames to buffer in the render queue. |
57 // TODO(peah): Decrease this once we properly handle hugely unbalanced | 55 // TODO(peah): Decrease this once we properly handle hugely unbalanced |
58 // reverse and forward call numbers. | 56 // reverse and forward call numbers. |
59 static const size_t kMaxNumFramesToBuffer = 100; | 57 static const size_t kMaxNumFramesToBuffer = 100; |
60 } // namespace | 58 } // namespace |
61 | 59 |
62 class EchoCancellationImpl::Canceller { | 60 class EchoCancellationImpl::Canceller { |
63 public: | 61 public: |
64 explicit Canceller(int sample_rate_hz) { | 62 Canceller() { |
65 state_ = WebRtcAec_Create(); | 63 state_ = WebRtcAec_Create(); |
66 RTC_DCHECK(state_); | 64 RTC_DCHECK(state_); |
67 } | 65 } |
68 | 66 |
69 ~Canceller() { | 67 ~Canceller() { |
70 RTC_CHECK(state_); | 68 RTC_CHECK(state_); |
71 WebRtcAec_Free(state_); | 69 WebRtcAec_Free(state_); |
72 } | 70 } |
73 | 71 |
74 Handle* state() { return state_; } | 72 void* state() { return state_; } |
75 | 73 |
76 void Initialize(int sample_rate_hz) { | 74 void Initialize(int sample_rate_hz) { |
77 // TODO(ajm): Drift compensation is disabled in practice. If restored, it | 75 // TODO(ajm): Drift compensation is disabled in practice. If restored, it |
78 // should be managed internally and not depend on the hardware sample rate. | 76 // should be managed internally and not depend on the hardware sample rate. |
79 // For now, just hardcode a 48 kHz value. | 77 // For now, just hardcode a 48 kHz value. |
80 const int error = WebRtcAec_Init(state_, sample_rate_hz, 48000); | 78 const int error = WebRtcAec_Init(state_, sample_rate_hz, 48000); |
81 RTC_DCHECK_EQ(0, error); | 79 RTC_DCHECK_EQ(0, error); |
82 } | 80 } |
83 | 81 |
84 private: | 82 private: |
85 Handle* state_; | 83 void* state_; |
86 | |
87 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Canceller); | |
88 }; | 84 }; |
89 | 85 |
90 EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm, | 86 EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm, |
91 rtc::CriticalSection* crit_render, | 87 rtc::CriticalSection* crit_render, |
92 rtc::CriticalSection* crit_capture) | 88 rtc::CriticalSection* crit_capture) |
93 : apm_(apm), | 89 : apm_(apm), |
94 crit_render_(crit_render), | 90 crit_render_(crit_render), |
95 crit_capture_(crit_capture), | 91 crit_capture_(crit_capture), |
96 drift_compensation_enabled_(false), | 92 drift_compensation_enabled_(false), |
97 metrics_enabled_(false), | 93 metrics_enabled_(false), |
(...skipping 24 matching lines...) Expand all Loading... |
122 RTC_DCHECK_GE(cancellers_.size(), | 118 RTC_DCHECK_GE(cancellers_.size(), |
123 apm_->num_output_channels() * audio->num_channels()); | 119 apm_->num_output_channels() * audio->num_channels()); |
124 | 120 |
125 int err = AudioProcessing::kNoError; | 121 int err = AudioProcessing::kNoError; |
126 | 122 |
127 // The ordering convention must be followed to pass to the correct AEC. | 123 // The ordering convention must be followed to pass to the correct AEC. |
128 size_t handle_index = 0; | 124 size_t handle_index = 0; |
129 render_queue_buffer_.clear(); | 125 render_queue_buffer_.clear(); |
130 for (size_t i = 0; i < apm_->num_output_channels(); i++) { | 126 for (size_t i = 0; i < apm_->num_output_channels(); i++) { |
131 for (size_t j = 0; j < audio->num_channels(); j++) { | 127 for (size_t j = 0; j < audio->num_channels(); j++) { |
132 Handle* my_handle = cancellers_[handle_index++]->state(); | |
133 // Retrieve any error code produced by the buffering of the farend | 128 // Retrieve any error code produced by the buffering of the farend |
134 // signal. | 129 // signal. |
135 err = WebRtcAec_GetBufferFarendError( | 130 err = WebRtcAec_GetBufferFarendError( |
136 my_handle, audio->split_bands_const_f(j)[kBand0To8kHz], | 131 cancellers_[handle_index++]->state(), |
| 132 audio->split_bands_const_f(j)[kBand0To8kHz], |
137 audio->num_frames_per_band()); | 133 audio->num_frames_per_band()); |
138 | 134 |
139 if (err != AudioProcessing::kNoError) { | 135 if (err != AudioProcessing::kNoError) { |
140 return MapError(err); // TODO(ajm): warning possible? | 136 return MapError(err); // TODO(ajm): warning possible? |
141 } | 137 } |
142 | 138 |
143 // Buffer the samples in the render queue. | 139 // Buffer the samples in the render queue. |
144 render_queue_buffer_.insert(render_queue_buffer_.end(), | 140 render_queue_buffer_.insert(render_queue_buffer_.end(), |
145 audio->split_bands_const_f(j)[kBand0To8kHz], | 141 audio->split_bands_const_f(j)[kBand0To8kHz], |
146 (audio->split_bands_const_f(j)[kBand0To8kHz] + | 142 (audio->split_bands_const_f(j)[kBand0To8kHz] + |
(...skipping 22 matching lines...) Expand all Loading... |
169 } | 165 } |
170 | 166 |
171 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { | 167 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { |
172 size_t handle_index = 0; | 168 size_t handle_index = 0; |
173 size_t buffer_index = 0; | 169 size_t buffer_index = 0; |
174 const size_t num_frames_per_band = | 170 const size_t num_frames_per_band = |
175 capture_queue_buffer_.size() / | 171 capture_queue_buffer_.size() / |
176 (apm_->num_output_channels() * apm_->num_reverse_channels()); | 172 (apm_->num_output_channels() * apm_->num_reverse_channels()); |
177 for (size_t i = 0; i < apm_->num_output_channels(); i++) { | 173 for (size_t i = 0; i < apm_->num_output_channels(); i++) { |
178 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { | 174 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { |
179 Handle* my_handle = cancellers_[handle_index++]->state(); | 175 WebRtcAec_BufferFarend(cancellers_[handle_index++]->state(), |
180 WebRtcAec_BufferFarend(my_handle, &capture_queue_buffer_[buffer_index], | 176 &capture_queue_buffer_[buffer_index], |
181 num_frames_per_band); | 177 num_frames_per_band); |
182 | 178 |
183 buffer_index += num_frames_per_band; | 179 buffer_index += num_frames_per_band; |
184 } | 180 } |
185 } | 181 } |
186 } | 182 } |
187 } | 183 } |
188 | 184 |
189 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { | 185 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { |
190 rtc::CritScope cs_capture(crit_capture_); | 186 rtc::CritScope cs_capture(crit_capture_); |
(...skipping 12 matching lines...) Expand all Loading... |
203 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 199 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
204 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_proc_channels()); | 200 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_proc_channels()); |
205 | 201 |
206 int err = AudioProcessing::kNoError; | 202 int err = AudioProcessing::kNoError; |
207 | 203 |
208 // The ordering convention must be followed to pass to the correct AEC. | 204 // The ordering convention must be followed to pass to the correct AEC. |
209 size_t handle_index = 0; | 205 size_t handle_index = 0; |
210 stream_has_echo_ = false; | 206 stream_has_echo_ = false; |
211 for (size_t i = 0; i < audio->num_channels(); i++) { | 207 for (size_t i = 0; i < audio->num_channels(); i++) { |
212 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { | 208 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { |
213 Handle* my_handle = cancellers_[handle_index++]->state(); | 209 err = WebRtcAec_Process(cancellers_[handle_index]->state(), |
214 err = WebRtcAec_Process(my_handle, audio->split_bands_const_f(i), | 210 audio->split_bands_const_f(i), audio->num_bands(), |
215 audio->num_bands(), audio->split_bands_f(i), | 211 audio->split_bands_f(i), |
216 audio->num_frames_per_band(), | 212 audio->num_frames_per_band(), |
217 apm_->stream_delay_ms(), stream_drift_samples_); | 213 apm_->stream_delay_ms(), stream_drift_samples_); |
218 | 214 |
219 if (err != AudioProcessing::kNoError) { | 215 if (err != AudioProcessing::kNoError) { |
220 err = MapError(err); | 216 err = MapError(err); |
221 // TODO(ajm): Figure out how to return warnings properly. | 217 // TODO(ajm): Figure out how to return warnings properly. |
222 if (err != AudioProcessing::kBadStreamParameterWarning) { | 218 if (err != AudioProcessing::kBadStreamParameterWarning) { |
223 return err; | 219 return err; |
224 } | 220 } |
225 } | 221 } |
226 | 222 |
227 int status = 0; | 223 int status = 0; |
228 err = WebRtcAec_get_echo_status(my_handle, &status); | 224 err = WebRtcAec_get_echo_status(cancellers_[handle_index]->state(), |
| 225 &status); |
229 if (err != AudioProcessing::kNoError) { | 226 if (err != AudioProcessing::kNoError) { |
230 return MapError(err); | 227 return MapError(err); |
231 } | 228 } |
232 | 229 |
233 if (status == 1) { | 230 if (status == 1) { |
234 stream_has_echo_ = true; | 231 stream_has_echo_ = true; |
235 } | 232 } |
| 233 |
| 234 handle_index++; |
236 } | 235 } |
237 } | 236 } |
238 | 237 |
239 was_stream_drift_set_ = false; | 238 was_stream_drift_set_ = false; |
240 return AudioProcessing::kNoError; | 239 return AudioProcessing::kNoError; |
241 } | 240 } |
242 | 241 |
243 int EchoCancellationImpl::Enable(bool enable) { | 242 int EchoCancellationImpl::Enable(bool enable) { |
244 // Run in a single-threaded manner. | 243 // Run in a single-threaded manner. |
245 rtc::CritScope cs_render(crit_render_); | 244 rtc::CritScope cs_render(crit_render_); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 } | 327 } |
329 | 328 |
330 if (!enabled_ || !metrics_enabled_) { | 329 if (!enabled_ || !metrics_enabled_) { |
331 return AudioProcessing::kNotEnabledError; | 330 return AudioProcessing::kNotEnabledError; |
332 } | 331 } |
333 | 332 |
334 AecMetrics my_metrics; | 333 AecMetrics my_metrics; |
335 memset(&my_metrics, 0, sizeof(my_metrics)); | 334 memset(&my_metrics, 0, sizeof(my_metrics)); |
336 memset(metrics, 0, sizeof(Metrics)); | 335 memset(metrics, 0, sizeof(Metrics)); |
337 | 336 |
338 Handle* my_handle = cancellers_[0]->state(); | 337 const int err = WebRtcAec_GetMetrics(cancellers_[0]->state(), &my_metrics); |
339 int err = WebRtcAec_GetMetrics(my_handle, &my_metrics); | |
340 if (err != AudioProcessing::kNoError) { | 338 if (err != AudioProcessing::kNoError) { |
341 return MapError(err); | 339 return MapError(err); |
342 } | 340 } |
343 | 341 |
344 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant; | 342 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant; |
345 metrics->residual_echo_return_loss.average = my_metrics.rerl.average; | 343 metrics->residual_echo_return_loss.average = my_metrics.rerl.average; |
346 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max; | 344 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max; |
347 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min; | 345 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min; |
348 | 346 |
349 metrics->echo_return_loss.instant = my_metrics.erl.instant; | 347 metrics->echo_return_loss.instant = my_metrics.erl.instant; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
411 return AudioProcessing::kNullPointerError; | 409 return AudioProcessing::kNullPointerError; |
412 } | 410 } |
413 if (std == NULL) { | 411 if (std == NULL) { |
414 return AudioProcessing::kNullPointerError; | 412 return AudioProcessing::kNullPointerError; |
415 } | 413 } |
416 | 414 |
417 if (!enabled_ || !delay_logging_enabled_) { | 415 if (!enabled_ || !delay_logging_enabled_) { |
418 return AudioProcessing::kNotEnabledError; | 416 return AudioProcessing::kNotEnabledError; |
419 } | 417 } |
420 | 418 |
421 Handle* my_handle = cancellers_[0]->state(); | 419 const int err = WebRtcAec_GetDelayMetrics(cancellers_[0]->state(), median, |
422 const int err = | 420 std, fraction_poor_delays); |
423 WebRtcAec_GetDelayMetrics(my_handle, median, std, fraction_poor_delays); | |
424 if (err != AudioProcessing::kNoError) { | 421 if (err != AudioProcessing::kNoError) { |
425 return MapError(err); | 422 return MapError(err); |
426 } | 423 } |
427 | 424 |
428 return AudioProcessing::kNoError; | 425 return AudioProcessing::kNoError; |
429 } | 426 } |
430 | 427 |
431 struct AecCore* EchoCancellationImpl::aec_core() const { | 428 struct AecCore* EchoCancellationImpl::aec_core() const { |
432 rtc::CritScope cs(crit_capture_); | 429 rtc::CritScope cs(crit_capture_); |
433 if (!enabled_) { | 430 if (!enabled_) { |
434 return NULL; | 431 return NULL; |
435 } | 432 } |
436 Handle* my_handle = cancellers_[0]->state(); | 433 return WebRtcAec_aec_core(cancellers_[0]->state()); |
437 return WebRtcAec_aec_core(my_handle); | |
438 } | 434 } |
439 | 435 |
440 void EchoCancellationImpl::Initialize() { | 436 void EchoCancellationImpl::Initialize() { |
441 rtc::CritScope cs_render(crit_render_); | 437 rtc::CritScope cs_render(crit_render_); |
442 rtc::CritScope cs_capture(crit_capture_); | 438 rtc::CritScope cs_capture(crit_capture_); |
443 if (!enabled_) { | 439 if (!enabled_) { |
444 return; | 440 return; |
445 } | 441 } |
446 const int sample_rate_hz = apm_->proc_sample_rate_hz(); | |
447 | 442 |
448 if (num_handles_required() > cancellers_.size()) { | 443 if (num_handles_required() > cancellers_.size()) { |
449 const size_t cancellers_old_size = cancellers_.size(); | 444 const size_t cancellers_old_size = cancellers_.size(); |
450 cancellers_.resize(num_handles_required()); | 445 cancellers_.resize(num_handles_required()); |
451 | 446 |
452 for (size_t i = cancellers_old_size; i < cancellers_.size(); ++i) { | 447 for (size_t i = cancellers_old_size; i < cancellers_.size(); ++i) { |
453 cancellers_[i].reset(new Canceller(sample_rate_hz)); | 448 cancellers_[i].reset(new Canceller()); |
454 } | 449 } |
455 } | 450 } |
456 | 451 |
457 for (size_t i = 0; i < cancellers_.size(); ++i) { | 452 const int sample_rate_hz = apm_->proc_sample_rate_hz(); |
458 cancellers_[i]->Initialize(sample_rate_hz); | 453 for (auto& canceller : cancellers_) { |
| 454 canceller->Initialize(sample_rate_hz); |
459 } | 455 } |
460 | 456 |
461 Configure(); | 457 Configure(); |
462 | 458 |
463 AllocateRenderQueue(); | 459 AllocateRenderQueue(); |
464 } | 460 } |
465 | 461 |
466 int EchoCancellationImpl::GetSystemDelayInSamples() const { | 462 int EchoCancellationImpl::GetSystemDelayInSamples() const { |
467 rtc::CritScope cs(crit_capture_); | 463 rtc::CritScope cs(crit_capture_); |
468 RTC_DCHECK(enabled_); | 464 RTC_DCHECK(enabled_); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 int EchoCancellationImpl::Configure() { | 507 int EchoCancellationImpl::Configure() { |
512 rtc::CritScope cs_render(crit_render_); | 508 rtc::CritScope cs_render(crit_render_); |
513 rtc::CritScope cs_capture(crit_capture_); | 509 rtc::CritScope cs_capture(crit_capture_); |
514 AecConfig config; | 510 AecConfig config; |
515 config.metricsMode = metrics_enabled_; | 511 config.metricsMode = metrics_enabled_; |
516 config.nlpMode = MapSetting(suppression_level_); | 512 config.nlpMode = MapSetting(suppression_level_); |
517 config.skewMode = drift_compensation_enabled_; | 513 config.skewMode = drift_compensation_enabled_; |
518 config.delay_logging = delay_logging_enabled_; | 514 config.delay_logging = delay_logging_enabled_; |
519 | 515 |
520 int error = AudioProcessing::kNoError; | 516 int error = AudioProcessing::kNoError; |
521 for (size_t i = 0; i < cancellers_.size(); i++) { | 517 for (auto& canceller : cancellers_) { |
522 Handle* my_handle = cancellers_[i]->state(); | 518 WebRtcAec_enable_extended_filter(WebRtcAec_aec_core(canceller->state()), |
523 WebRtcAec_enable_extended_filter(WebRtcAec_aec_core(my_handle), | |
524 extended_filter_enabled_ ? 1 : 0); | 519 extended_filter_enabled_ ? 1 : 0); |
525 WebRtcAec_enable_delay_agnostic(WebRtcAec_aec_core(my_handle), | 520 WebRtcAec_enable_delay_agnostic(WebRtcAec_aec_core(canceller->state()), |
526 delay_agnostic_enabled_ ? 1 : 0); | 521 delay_agnostic_enabled_ ? 1 : 0); |
527 WebRtcAec_enable_aec3(WebRtcAec_aec_core(my_handle), aec3_enabled_ ? 1 : 0); | 522 WebRtcAec_enable_aec3(WebRtcAec_aec_core(canceller->state()), |
528 const int handle_error = WebRtcAec_set_config(my_handle, config); | 523 aec3_enabled_ ? 1 : 0); |
| 524 const int handle_error = WebRtcAec_set_config(canceller->state(), config); |
529 if (handle_error != AudioProcessing::kNoError) { | 525 if (handle_error != AudioProcessing::kNoError) { |
530 error = AudioProcessing::kNoError; | 526 error = AudioProcessing::kNoError; |
531 } | 527 } |
532 } | 528 } |
533 return error; | 529 return error; |
534 } | 530 } |
535 | 531 |
536 size_t EchoCancellationImpl::num_handles_required() const { | 532 size_t EchoCancellationImpl::num_handles_required() const { |
537 // Not locked as it only relies on APM public API which is threadsafe. | 533 // Not locked as it only relies on APM public API which is threadsafe. |
538 return apm_->num_output_channels() * apm_->num_reverse_channels(); | 534 return apm_->num_output_channels() * apm_->num_reverse_channels(); |
539 } | 535 } |
540 | 536 |
541 } // namespace webrtc | 537 } // namespace webrtc |
OLD | NEW |