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 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 } | 50 } |
51 | 51 |
52 // Maximum length that a frame of samples can have. | 52 // Maximum length that a frame of samples can have. |
53 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; | 53 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; |
54 // Maximum number of frames to buffer in the render queue. | 54 // Maximum number of frames to buffer in the render queue. |
55 // TODO(peah): Decrease this once we properly handle hugely unbalanced | 55 // TODO(peah): Decrease this once we properly handle hugely unbalanced |
56 // reverse and forward call numbers. | 56 // reverse and forward call numbers. |
57 static const size_t kMaxNumFramesToBuffer = 100; | 57 static const size_t kMaxNumFramesToBuffer = 100; |
58 } // namespace | 58 } // namespace |
59 | 59 |
| 60 struct EchoCancellationImpl::StreamProperties { |
| 61 StreamProperties() = delete; |
| 62 StreamProperties(int sample_rate_hz, |
| 63 size_t num_reverse_channels, |
| 64 size_t num_output_channels, |
| 65 size_t num_proc_channels) |
| 66 : sample_rate_hz(sample_rate_hz), |
| 67 num_reverse_channels(num_reverse_channels), |
| 68 num_output_channels(num_output_channels), |
| 69 num_proc_channels(num_proc_channels) {} |
| 70 |
| 71 const int sample_rate_hz; |
| 72 const size_t num_reverse_channels; |
| 73 const size_t num_output_channels; |
| 74 const size_t num_proc_channels; |
| 75 }; |
| 76 |
60 class EchoCancellationImpl::Canceller { | 77 class EchoCancellationImpl::Canceller { |
61 public: | 78 public: |
62 Canceller() { | 79 Canceller() { |
63 state_ = WebRtcAec_Create(); | 80 state_ = WebRtcAec_Create(); |
64 RTC_DCHECK(state_); | 81 RTC_DCHECK(state_); |
65 } | 82 } |
66 | 83 |
67 ~Canceller() { | 84 ~Canceller() { |
68 RTC_CHECK(state_); | 85 RTC_CHECK(state_); |
69 WebRtcAec_Free(state_); | 86 WebRtcAec_Free(state_); |
70 } | 87 } |
71 | 88 |
72 void* state() { return state_; } | 89 void* state() { return state_; } |
73 | 90 |
74 void Initialize(int sample_rate_hz) { | 91 void Initialize(int sample_rate_hz) { |
75 // TODO(ajm): Drift compensation is disabled in practice. If restored, it | 92 // TODO(ajm): Drift compensation is disabled in practice. If restored, it |
76 // should be managed internally and not depend on the hardware sample rate. | 93 // should be managed internally and not depend on the hardware sample rate. |
77 // For now, just hardcode a 48 kHz value. | 94 // For now, just hardcode a 48 kHz value. |
78 const int error = WebRtcAec_Init(state_, sample_rate_hz, 48000); | 95 const int error = WebRtcAec_Init(state_, sample_rate_hz, 48000); |
79 RTC_DCHECK_EQ(0, error); | 96 RTC_DCHECK_EQ(0, error); |
80 } | 97 } |
81 | 98 |
82 private: | 99 private: |
83 void* state_; | 100 void* state_; |
84 }; | 101 }; |
85 | 102 |
86 EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm, | 103 EchoCancellationImpl::EchoCancellationImpl(rtc::CriticalSection* crit_render, |
87 rtc::CriticalSection* crit_render, | |
88 rtc::CriticalSection* crit_capture) | 104 rtc::CriticalSection* crit_capture) |
89 : apm_(apm), | 105 : crit_render_(crit_render), |
90 crit_render_(crit_render), | |
91 crit_capture_(crit_capture), | 106 crit_capture_(crit_capture), |
92 drift_compensation_enabled_(false), | 107 drift_compensation_enabled_(false), |
93 metrics_enabled_(false), | 108 metrics_enabled_(false), |
94 suppression_level_(kModerateSuppression), | 109 suppression_level_(kModerateSuppression), |
95 stream_drift_samples_(0), | 110 stream_drift_samples_(0), |
96 was_stream_drift_set_(false), | 111 was_stream_drift_set_(false), |
97 stream_has_echo_(false), | 112 stream_has_echo_(false), |
98 delay_logging_enabled_(false), | 113 delay_logging_enabled_(false), |
99 extended_filter_enabled_(false), | 114 extended_filter_enabled_(false), |
100 delay_agnostic_enabled_(false), | 115 delay_agnostic_enabled_(false), |
101 aec3_enabled_(false), | 116 aec3_enabled_(false), |
102 render_queue_element_max_size_(0) { | 117 render_queue_element_max_size_(0) { |
103 RTC_DCHECK(apm); | |
104 RTC_DCHECK(crit_render); | 118 RTC_DCHECK(crit_render); |
105 RTC_DCHECK(crit_capture); | 119 RTC_DCHECK(crit_capture); |
106 } | 120 } |
107 | 121 |
108 EchoCancellationImpl::~EchoCancellationImpl() {} | 122 EchoCancellationImpl::~EchoCancellationImpl() {} |
109 | 123 |
110 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { | 124 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { |
111 rtc::CritScope cs_render(crit_render_); | 125 rtc::CritScope cs_render(crit_render_); |
112 if (!enabled_) { | 126 if (!enabled_) { |
113 return AudioProcessing::kNoError; | 127 return AudioProcessing::kNoError; |
114 } | 128 } |
115 | 129 |
| 130 RTC_DCHECK(stream_properties_); |
116 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 131 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
117 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_reverse_channels()); | 132 RTC_DCHECK_EQ(audio->num_channels(), |
118 RTC_DCHECK_GE(cancellers_.size(), | 133 stream_properties_->num_reverse_channels); |
119 apm_->num_output_channels() * audio->num_channels()); | 134 RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_output_channels * |
| 135 audio->num_channels()); |
120 | 136 |
121 int err = AudioProcessing::kNoError; | 137 int err = AudioProcessing::kNoError; |
122 | 138 |
123 // The ordering convention must be followed to pass to the correct AEC. | 139 // The ordering convention must be followed to pass to the correct AEC. |
124 size_t handle_index = 0; | 140 size_t handle_index = 0; |
125 render_queue_buffer_.clear(); | 141 render_queue_buffer_.clear(); |
126 for (size_t i = 0; i < apm_->num_output_channels(); i++) { | 142 for (size_t i = 0; i < stream_properties_->num_output_channels; i++) { |
127 for (size_t j = 0; j < audio->num_channels(); j++) { | 143 for (size_t j = 0; j < audio->num_channels(); j++) { |
128 // Retrieve any error code produced by the buffering of the farend | 144 // Retrieve any error code produced by the buffering of the farend |
129 // signal. | 145 // signal. |
130 err = WebRtcAec_GetBufferFarendError( | 146 err = WebRtcAec_GetBufferFarendError( |
131 cancellers_[handle_index++]->state(), | 147 cancellers_[handle_index++]->state(), |
132 audio->split_bands_const_f(j)[kBand0To8kHz], | 148 audio->split_bands_const_f(j)[kBand0To8kHz], |
133 audio->num_frames_per_band()); | 149 audio->num_frames_per_band()); |
134 | 150 |
135 if (err != AudioProcessing::kNoError) { | 151 if (err != AudioProcessing::kNoError) { |
136 return MapError(err); // TODO(ajm): warning possible? | 152 return MapError(err); // TODO(ajm): warning possible? |
(...skipping 20 matching lines...) Expand all Loading... |
157 } | 173 } |
158 | 174 |
159 // Read chunks of data that were received and queued on the render side from | 175 // Read chunks of data that were received and queued on the render side from |
160 // a queue. All the data chunks are buffered into the farend signal of the AEC. | 176 // a queue. All the data chunks are buffered into the farend signal of the AEC. |
161 void EchoCancellationImpl::ReadQueuedRenderData() { | 177 void EchoCancellationImpl::ReadQueuedRenderData() { |
162 rtc::CritScope cs_capture(crit_capture_); | 178 rtc::CritScope cs_capture(crit_capture_); |
163 if (!enabled_) { | 179 if (!enabled_) { |
164 return; | 180 return; |
165 } | 181 } |
166 | 182 |
| 183 RTC_DCHECK(stream_properties_); |
167 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { | 184 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { |
168 size_t handle_index = 0; | 185 size_t handle_index = 0; |
169 size_t buffer_index = 0; | 186 size_t buffer_index = 0; |
170 const size_t num_frames_per_band = | 187 const size_t num_frames_per_band = |
171 capture_queue_buffer_.size() / | 188 capture_queue_buffer_.size() / |
172 (apm_->num_output_channels() * apm_->num_reverse_channels()); | 189 (stream_properties_->num_output_channels * |
173 for (size_t i = 0; i < apm_->num_output_channels(); i++) { | 190 stream_properties_->num_reverse_channels); |
174 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { | 191 for (size_t i = 0; i < stream_properties_->num_output_channels; i++) { |
| 192 for (size_t j = 0; j < stream_properties_->num_reverse_channels; j++) { |
175 WebRtcAec_BufferFarend(cancellers_[handle_index++]->state(), | 193 WebRtcAec_BufferFarend(cancellers_[handle_index++]->state(), |
176 &capture_queue_buffer_[buffer_index], | 194 &capture_queue_buffer_[buffer_index], |
177 num_frames_per_band); | 195 num_frames_per_band); |
178 | 196 |
179 buffer_index += num_frames_per_band; | 197 buffer_index += num_frames_per_band; |
180 } | 198 } |
181 } | 199 } |
182 } | 200 } |
183 } | 201 } |
184 | 202 |
185 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { | 203 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio, |
| 204 int stream_delay_ms) { |
186 rtc::CritScope cs_capture(crit_capture_); | 205 rtc::CritScope cs_capture(crit_capture_); |
187 if (!enabled_) { | 206 if (!enabled_) { |
188 return AudioProcessing::kNoError; | 207 return AudioProcessing::kNoError; |
189 } | 208 } |
190 | 209 |
191 if (!apm_->was_stream_delay_set()) { | |
192 return AudioProcessing::kStreamParameterNotSetError; | |
193 } | |
194 | |
195 if (drift_compensation_enabled_ && !was_stream_drift_set_) { | 210 if (drift_compensation_enabled_ && !was_stream_drift_set_) { |
196 return AudioProcessing::kStreamParameterNotSetError; | 211 return AudioProcessing::kStreamParameterNotSetError; |
197 } | 212 } |
198 | 213 |
| 214 RTC_DCHECK(stream_properties_); |
199 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 215 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
200 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_proc_channels()); | 216 RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_proc_channels); |
201 | 217 |
202 int err = AudioProcessing::kNoError; | 218 int err = AudioProcessing::kNoError; |
203 | 219 |
204 // The ordering convention must be followed to pass to the correct AEC. | 220 // The ordering convention must be followed to pass to the correct AEC. |
205 size_t handle_index = 0; | 221 size_t handle_index = 0; |
206 stream_has_echo_ = false; | 222 stream_has_echo_ = false; |
207 for (size_t i = 0; i < audio->num_channels(); i++) { | 223 for (size_t i = 0; i < audio->num_channels(); i++) { |
208 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { | 224 for (size_t j = 0; j < stream_properties_->num_reverse_channels; j++) { |
209 err = WebRtcAec_Process(cancellers_[handle_index]->state(), | 225 err = WebRtcAec_Process( |
210 audio->split_bands_const_f(i), audio->num_bands(), | 226 cancellers_[handle_index]->state(), audio->split_bands_const_f(i), |
211 audio->split_bands_f(i), | 227 audio->num_bands(), audio->split_bands_f(i), |
212 audio->num_frames_per_band(), | 228 audio->num_frames_per_band(), stream_delay_ms, stream_drift_samples_); |
213 apm_->stream_delay_ms(), stream_drift_samples_); | |
214 | 229 |
215 if (err != AudioProcessing::kNoError) { | 230 if (err != AudioProcessing::kNoError) { |
216 err = MapError(err); | 231 err = MapError(err); |
217 // TODO(ajm): Figure out how to return warnings properly. | 232 // TODO(ajm): Figure out how to return warnings properly. |
218 if (err != AudioProcessing::kBadStreamParameterWarning) { | 233 if (err != AudioProcessing::kBadStreamParameterWarning) { |
219 return err; | 234 return err; |
220 } | 235 } |
221 } | 236 } |
222 | 237 |
223 int status = 0; | 238 int status = 0; |
(...skipping 12 matching lines...) Expand all Loading... |
236 } | 251 } |
237 | 252 |
238 was_stream_drift_set_ = false; | 253 was_stream_drift_set_ = false; |
239 return AudioProcessing::kNoError; | 254 return AudioProcessing::kNoError; |
240 } | 255 } |
241 | 256 |
242 int EchoCancellationImpl::Enable(bool enable) { | 257 int EchoCancellationImpl::Enable(bool enable) { |
243 // Run in a single-threaded manner. | 258 // Run in a single-threaded manner. |
244 rtc::CritScope cs_render(crit_render_); | 259 rtc::CritScope cs_render(crit_render_); |
245 rtc::CritScope cs_capture(crit_capture_); | 260 rtc::CritScope cs_capture(crit_capture_); |
246 // Ensure AEC and AECM are not both enabled. | |
247 // The is_enabled call is safe from a deadlock perspective | |
248 // as both locks are already held in the correct order. | |
249 if (enable && apm_->echo_control_mobile()->is_enabled()) { | |
250 return AudioProcessing::kBadParameterError; | |
251 } | |
252 | 261 |
253 if (enable && !enabled_) { | 262 if (enable && !enabled_) { |
254 enabled_ = enable; // Must be set before Initialize() is called. | 263 enabled_ = enable; // Must be set before Initialize() is called. |
255 Initialize(); | 264 |
| 265 // TODO(peah): Simplify once the Enable function has been removed from |
| 266 // the public APM API. |
| 267 RTC_DCHECK(stream_properties_); |
| 268 Initialize(stream_properties_->sample_rate_hz, |
| 269 stream_properties_->num_reverse_channels, |
| 270 stream_properties_->num_output_channels, |
| 271 stream_properties_->num_proc_channels); |
256 } else { | 272 } else { |
257 enabled_ = enable; | 273 enabled_ = enable; |
258 } | 274 } |
259 return AudioProcessing::kNoError; | 275 return AudioProcessing::kNoError; |
260 } | 276 } |
261 | 277 |
262 bool EchoCancellationImpl::is_enabled() const { | 278 bool EchoCancellationImpl::is_enabled() const { |
263 rtc::CritScope cs(crit_capture_); | 279 rtc::CritScope cs(crit_capture_); |
264 return enabled_; | 280 return enabled_; |
265 } | 281 } |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 } | 442 } |
427 | 443 |
428 struct AecCore* EchoCancellationImpl::aec_core() const { | 444 struct AecCore* EchoCancellationImpl::aec_core() const { |
429 rtc::CritScope cs(crit_capture_); | 445 rtc::CritScope cs(crit_capture_); |
430 if (!enabled_) { | 446 if (!enabled_) { |
431 return NULL; | 447 return NULL; |
432 } | 448 } |
433 return WebRtcAec_aec_core(cancellers_[0]->state()); | 449 return WebRtcAec_aec_core(cancellers_[0]->state()); |
434 } | 450 } |
435 | 451 |
436 void EchoCancellationImpl::Initialize() { | 452 void EchoCancellationImpl::Initialize(int sample_rate_hz, |
| 453 size_t num_reverse_channels, |
| 454 size_t num_output_channels, |
| 455 size_t num_proc_channels) { |
437 rtc::CritScope cs_render(crit_render_); | 456 rtc::CritScope cs_render(crit_render_); |
438 rtc::CritScope cs_capture(crit_capture_); | 457 rtc::CritScope cs_capture(crit_capture_); |
| 458 |
| 459 stream_properties_.reset( |
| 460 new StreamProperties(sample_rate_hz, num_reverse_channels, |
| 461 num_output_channels, num_proc_channels)); |
| 462 |
439 if (!enabled_) { | 463 if (!enabled_) { |
440 return; | 464 return; |
441 } | 465 } |
442 | 466 |
443 if (num_handles_required() > cancellers_.size()) { | 467 if (NumCancellersRequired() > cancellers_.size()) { |
444 const size_t cancellers_old_size = cancellers_.size(); | 468 const size_t cancellers_old_size = cancellers_.size(); |
445 cancellers_.resize(num_handles_required()); | 469 cancellers_.resize(NumCancellersRequired()); |
446 | 470 |
447 for (size_t i = cancellers_old_size; i < cancellers_.size(); ++i) { | 471 for (size_t i = cancellers_old_size; i < cancellers_.size(); ++i) { |
448 cancellers_[i].reset(new Canceller()); | 472 cancellers_[i].reset(new Canceller()); |
449 } | 473 } |
450 } | 474 } |
451 | 475 |
452 const int sample_rate_hz = apm_->proc_sample_rate_hz(); | |
453 for (auto& canceller : cancellers_) { | 476 for (auto& canceller : cancellers_) { |
454 canceller->Initialize(sample_rate_hz); | 477 canceller->Initialize(sample_rate_hz); |
455 } | 478 } |
456 | 479 |
457 Configure(); | 480 Configure(); |
458 | 481 |
459 AllocateRenderQueue(); | 482 AllocateRenderQueue(); |
460 } | 483 } |
461 | 484 |
462 int EchoCancellationImpl::GetSystemDelayInSamples() const { | 485 int EchoCancellationImpl::GetSystemDelayInSamples() const { |
463 rtc::CritScope cs(crit_capture_); | 486 rtc::CritScope cs(crit_capture_); |
464 RTC_DCHECK(enabled_); | 487 RTC_DCHECK(enabled_); |
465 // Report the delay for the first AEC component. | 488 // Report the delay for the first AEC component. |
466 return WebRtcAec_system_delay( | 489 return WebRtcAec_system_delay( |
467 WebRtcAec_aec_core(cancellers_[0]->state())); | 490 WebRtcAec_aec_core(cancellers_[0]->state())); |
468 } | 491 } |
469 | 492 |
470 void EchoCancellationImpl::AllocateRenderQueue() { | 493 void EchoCancellationImpl::AllocateRenderQueue() { |
471 const size_t new_render_queue_element_max_size = std::max<size_t>( | 494 const size_t new_render_queue_element_max_size = std::max<size_t>( |
472 static_cast<size_t>(1), | 495 static_cast<size_t>(1), |
473 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); | 496 kMaxAllowedValuesOfSamplesPerFrame * NumCancellersRequired()); |
474 | 497 |
475 rtc::CritScope cs_render(crit_render_); | 498 rtc::CritScope cs_render(crit_render_); |
476 rtc::CritScope cs_capture(crit_capture_); | 499 rtc::CritScope cs_capture(crit_capture_); |
477 | 500 |
478 // Reallocate the queue if the queue item size is too small to fit the | 501 // Reallocate the queue if the queue item size is too small to fit the |
479 // data to put in the queue. | 502 // data to put in the queue. |
480 if (render_queue_element_max_size_ < new_render_queue_element_max_size) { | 503 if (render_queue_element_max_size_ < new_render_queue_element_max_size) { |
481 render_queue_element_max_size_ = new_render_queue_element_max_size; | 504 render_queue_element_max_size_ = new_render_queue_element_max_size; |
482 | 505 |
483 std::vector<float> template_queue_element(render_queue_element_max_size_); | 506 std::vector<float> template_queue_element(render_queue_element_max_size_); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 WebRtcAec_enable_aec3(WebRtcAec_aec_core(canceller->state()), | 545 WebRtcAec_enable_aec3(WebRtcAec_aec_core(canceller->state()), |
523 aec3_enabled_ ? 1 : 0); | 546 aec3_enabled_ ? 1 : 0); |
524 const int handle_error = WebRtcAec_set_config(canceller->state(), config); | 547 const int handle_error = WebRtcAec_set_config(canceller->state(), config); |
525 if (handle_error != AudioProcessing::kNoError) { | 548 if (handle_error != AudioProcessing::kNoError) { |
526 error = AudioProcessing::kNoError; | 549 error = AudioProcessing::kNoError; |
527 } | 550 } |
528 } | 551 } |
529 return error; | 552 return error; |
530 } | 553 } |
531 | 554 |
532 size_t EchoCancellationImpl::num_handles_required() const { | 555 size_t EchoCancellationImpl::NumCancellersRequired() const { |
533 // Not locked as it only relies on APM public API which is threadsafe. | 556 RTC_DCHECK(stream_properties_); |
534 return apm_->num_output_channels() * apm_->num_reverse_channels(); | 557 return stream_properties_->num_output_channels * |
| 558 stream_properties_->num_reverse_channels; |
535 } | 559 } |
536 | 560 |
537 } // namespace webrtc | 561 } // namespace webrtc |
OLD | NEW |