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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 } | 52 } |
53 | 53 |
54 // Maximum length that a frame of samples can have. | 54 // Maximum length that a frame of samples can have. |
55 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; | 55 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; |
56 // Maximum number of frames to buffer in the render queue. | 56 // Maximum number of frames to buffer in the render queue. |
57 // TODO(peah): Decrease this once we properly handle hugely unbalanced | 57 // TODO(peah): Decrease this once we properly handle hugely unbalanced |
58 // reverse and forward call numbers. | 58 // reverse and forward call numbers. |
59 static const size_t kMaxNumFramesToBuffer = 100; | 59 static const size_t kMaxNumFramesToBuffer = 100; |
60 } // namespace | 60 } // namespace |
61 | 61 |
62 class EchoCancellationImpl::Canceller { | |
63 public: | |
64 explicit Canceller(int sample_rate_hz) { | |
65 state_ = WebRtcAec_Create(); | |
66 RTC_DCHECK(state_); | |
67 } | |
68 | |
69 ~Canceller() { | |
70 RTC_CHECK(state_); | |
71 WebRtcAec_Free(state_); | |
72 } | |
73 | |
74 Handle* state() { return state_; } | |
75 | |
76 void Initialize(int sample_rate_hz) { | |
77 // TODO(ajm): Drift compensation is disabled in practice. If restored, it | |
78 // should be managed internally and not depend on the hardware sample rate. | |
79 // For now, just hardcode a 48 kHz value. | |
80 const int error = WebRtcAec_Init(state_, sample_rate_hz, 48000); | |
81 RTC_DCHECK_EQ(0, error); | |
82 } | |
83 | |
84 private: | |
85 Handle* state_; | |
86 | |
87 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Canceller); | |
88 }; | |
89 | |
90 EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm, | 62 EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm, |
91 rtc::CriticalSection* crit_render, | 63 rtc::CriticalSection* crit_render, |
92 rtc::CriticalSection* crit_capture) | 64 rtc::CriticalSection* crit_capture) |
93 : apm_(apm), | 65 : ProcessingComponent(), |
| 66 apm_(apm), |
94 crit_render_(crit_render), | 67 crit_render_(crit_render), |
95 crit_capture_(crit_capture), | 68 crit_capture_(crit_capture), |
96 drift_compensation_enabled_(false), | 69 drift_compensation_enabled_(false), |
97 metrics_enabled_(false), | 70 metrics_enabled_(false), |
98 suppression_level_(kModerateSuppression), | 71 suppression_level_(kModerateSuppression), |
99 stream_drift_samples_(0), | 72 stream_drift_samples_(0), |
100 was_stream_drift_set_(false), | 73 was_stream_drift_set_(false), |
101 stream_has_echo_(false), | 74 stream_has_echo_(false), |
102 delay_logging_enabled_(false), | 75 delay_logging_enabled_(false), |
103 extended_filter_enabled_(false), | 76 extended_filter_enabled_(false), |
104 delay_agnostic_enabled_(false), | 77 delay_agnostic_enabled_(false), |
105 next_generation_aec_enabled_(false), | 78 next_generation_aec_enabled_(false), |
106 render_queue_element_max_size_(0) { | 79 render_queue_element_max_size_(0) { |
107 RTC_DCHECK(apm); | 80 RTC_DCHECK(apm); |
108 RTC_DCHECK(crit_render); | 81 RTC_DCHECK(crit_render); |
109 RTC_DCHECK(crit_capture); | 82 RTC_DCHECK(crit_capture); |
110 } | 83 } |
111 | 84 |
112 EchoCancellationImpl::~EchoCancellationImpl() {} | 85 EchoCancellationImpl::~EchoCancellationImpl() {} |
113 | 86 |
114 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { | 87 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { |
115 rtc::CritScope cs_render(crit_render_); | 88 rtc::CritScope cs_render(crit_render_); |
116 if (!enabled_) { | 89 if (!is_component_enabled()) { |
117 return AudioProcessing::kNoError; | 90 return AudioProcessing::kNoError; |
118 } | 91 } |
119 | 92 |
120 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 93 assert(audio->num_frames_per_band() <= 160); |
121 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_reverse_channels()); | 94 assert(audio->num_channels() == apm_->num_reverse_channels()); |
122 RTC_DCHECK_GE(cancellers_.size(), | |
123 apm_->num_output_channels() * audio->num_channels()); | |
124 | 95 |
125 int err = AudioProcessing::kNoError; | 96 int err = AudioProcessing::kNoError; |
126 | 97 |
127 // The ordering convention must be followed to pass to the correct AEC. | 98 // The ordering convention must be followed to pass to the correct AEC. |
128 size_t handle_index = 0; | 99 size_t handle_index = 0; |
129 render_queue_buffer_.clear(); | 100 render_queue_buffer_.clear(); |
130 for (size_t i = 0; i < apm_->num_output_channels(); i++) { | 101 for (size_t i = 0; i < apm_->num_output_channels(); i++) { |
131 for (size_t j = 0; j < audio->num_channels(); j++) { | 102 for (size_t j = 0; j < audio->num_channels(); j++) { |
132 Handle* my_handle = cancellers_[handle_index++]->state(); | 103 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); |
133 // Retrieve any error code produced by the buffering of the farend | 104 // Retrieve any error code produced by the buffering of the farend |
134 // signal. | 105 // signal |
135 err = WebRtcAec_GetBufferFarendError( | 106 err = WebRtcAec_GetBufferFarendError( |
136 my_handle, audio->split_bands_const_f(j)[kBand0To8kHz], | 107 my_handle, audio->split_bands_const_f(j)[kBand0To8kHz], |
137 audio->num_frames_per_band()); | 108 audio->num_frames_per_band()); |
138 | 109 |
139 if (err != AudioProcessing::kNoError) { | 110 if (err != AudioProcessing::kNoError) { |
140 return MapError(err); // TODO(ajm): warning possible? | 111 return MapError(err); // TODO(ajm): warning possible? |
141 } | 112 } |
142 | 113 |
143 // Buffer the samples in the render queue. | 114 // Buffer the samples in the render queue. |
144 render_queue_buffer_.insert(render_queue_buffer_.end(), | 115 render_queue_buffer_.insert(render_queue_buffer_.end(), |
145 audio->split_bands_const_f(j)[kBand0To8kHz], | 116 audio->split_bands_const_f(j)[kBand0To8kHz], |
146 (audio->split_bands_const_f(j)[kBand0To8kHz] + | 117 (audio->split_bands_const_f(j)[kBand0To8kHz] + |
147 audio->num_frames_per_band())); | 118 audio->num_frames_per_band())); |
| 119 |
| 120 handle_index++; |
148 } | 121 } |
149 } | 122 } |
150 | 123 |
151 // Insert the samples into the queue. | 124 // Insert the samples into the queue. |
152 if (!render_signal_queue_->Insert(&render_queue_buffer_)) { | 125 if (!render_signal_queue_->Insert(&render_queue_buffer_)) { |
153 // The data queue is full and needs to be emptied. | 126 // The data queue is full and needs to be emptied. |
154 ReadQueuedRenderData(); | 127 ReadQueuedRenderData(); |
155 | 128 |
156 // Retry the insert (should always work). | 129 // Retry the insert (should always work). |
157 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); | 130 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); |
158 } | 131 } |
159 | 132 |
160 return AudioProcessing::kNoError; | 133 return AudioProcessing::kNoError; |
161 } | 134 } |
162 | 135 |
163 // Read chunks of data that were received and queued on the render side from | 136 // Read chunks of data that were received and queued on the render side from |
164 // a queue. All the data chunks are buffered into the farend signal of the AEC. | 137 // a queue. All the data chunks are buffered into the farend signal of the AEC. |
165 void EchoCancellationImpl::ReadQueuedRenderData() { | 138 void EchoCancellationImpl::ReadQueuedRenderData() { |
166 rtc::CritScope cs_capture(crit_capture_); | 139 rtc::CritScope cs_capture(crit_capture_); |
167 if (!enabled_) { | 140 if (!is_component_enabled()) { |
168 return; | 141 return; |
169 } | 142 } |
170 | 143 |
171 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { | 144 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { |
172 size_t handle_index = 0; | 145 size_t handle_index = 0; |
173 size_t buffer_index = 0; | 146 size_t buffer_index = 0; |
174 const size_t num_frames_per_band = | 147 const size_t num_frames_per_band = |
175 capture_queue_buffer_.size() / | 148 capture_queue_buffer_.size() / |
176 (apm_->num_output_channels() * apm_->num_reverse_channels()); | 149 (apm_->num_output_channels() * apm_->num_reverse_channels()); |
177 for (size_t i = 0; i < apm_->num_output_channels(); i++) { | 150 for (size_t i = 0; i < apm_->num_output_channels(); i++) { |
178 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { | 151 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { |
179 Handle* my_handle = cancellers_[handle_index++]->state(); | 152 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); |
180 WebRtcAec_BufferFarend(my_handle, &capture_queue_buffer_[buffer_index], | 153 WebRtcAec_BufferFarend(my_handle, &capture_queue_buffer_[buffer_index], |
181 num_frames_per_band); | 154 num_frames_per_band); |
182 | 155 |
183 buffer_index += num_frames_per_band; | 156 buffer_index += num_frames_per_band; |
| 157 handle_index++; |
184 } | 158 } |
185 } | 159 } |
186 } | 160 } |
187 } | 161 } |
188 | 162 |
189 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { | 163 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { |
190 rtc::CritScope cs_capture(crit_capture_); | 164 rtc::CritScope cs_capture(crit_capture_); |
191 if (!enabled_) { | 165 if (!is_component_enabled()) { |
192 return AudioProcessing::kNoError; | 166 return AudioProcessing::kNoError; |
193 } | 167 } |
194 | 168 |
195 if (!apm_->was_stream_delay_set()) { | 169 if (!apm_->was_stream_delay_set()) { |
196 return AudioProcessing::kStreamParameterNotSetError; | 170 return AudioProcessing::kStreamParameterNotSetError; |
197 } | 171 } |
198 | 172 |
199 if (drift_compensation_enabled_ && !was_stream_drift_set_) { | 173 if (drift_compensation_enabled_ && !was_stream_drift_set_) { |
200 return AudioProcessing::kStreamParameterNotSetError; | 174 return AudioProcessing::kStreamParameterNotSetError; |
201 } | 175 } |
202 | 176 |
203 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 177 assert(audio->num_frames_per_band() <= 160); |
204 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_proc_channels()); | 178 assert(audio->num_channels() == apm_->num_proc_channels()); |
205 | 179 |
206 int err = AudioProcessing::kNoError; | 180 int err = AudioProcessing::kNoError; |
207 | 181 |
208 // The ordering convention must be followed to pass to the correct AEC. | 182 // The ordering convention must be followed to pass to the correct AEC. |
209 size_t handle_index = 0; | 183 size_t handle_index = 0; |
210 stream_has_echo_ = false; | 184 stream_has_echo_ = false; |
211 for (size_t i = 0; i < audio->num_channels(); i++) { | 185 for (size_t i = 0; i < audio->num_channels(); i++) { |
212 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { | 186 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) { |
213 Handle* my_handle = cancellers_[handle_index++]->state(); | 187 Handle* my_handle = handle(handle_index); |
214 err = WebRtcAec_Process(my_handle, audio->split_bands_const_f(i), | 188 err = WebRtcAec_Process(my_handle, audio->split_bands_const_f(i), |
215 audio->num_bands(), audio->split_bands_f(i), | 189 audio->num_bands(), audio->split_bands_f(i), |
216 audio->num_frames_per_band(), | 190 audio->num_frames_per_band(), |
217 apm_->stream_delay_ms(), stream_drift_samples_); | 191 apm_->stream_delay_ms(), stream_drift_samples_); |
218 | 192 |
219 if (err != AudioProcessing::kNoError) { | 193 if (err != AudioProcessing::kNoError) { |
220 err = MapError(err); | 194 err = MapError(err); |
221 // TODO(ajm): Figure out how to return warnings properly. | 195 // TODO(ajm): Figure out how to return warnings properly. |
222 if (err != AudioProcessing::kBadStreamParameterWarning) { | 196 if (err != AudioProcessing::kBadStreamParameterWarning) { |
223 return err; | 197 return err; |
224 } | 198 } |
225 } | 199 } |
226 | 200 |
227 int status = 0; | 201 int status = 0; |
228 err = WebRtcAec_get_echo_status(my_handle, &status); | 202 err = WebRtcAec_get_echo_status(my_handle, &status); |
229 if (err != AudioProcessing::kNoError) { | 203 if (err != AudioProcessing::kNoError) { |
230 return MapError(err); | 204 return MapError(err); |
231 } | 205 } |
232 | 206 |
233 if (status == 1) { | 207 if (status == 1) { |
234 stream_has_echo_ = true; | 208 stream_has_echo_ = true; |
235 } | 209 } |
| 210 |
| 211 handle_index++; |
236 } | 212 } |
237 } | 213 } |
238 | 214 |
239 was_stream_drift_set_ = false; | 215 was_stream_drift_set_ = false; |
240 return AudioProcessing::kNoError; | 216 return AudioProcessing::kNoError; |
241 } | 217 } |
242 | 218 |
243 int EchoCancellationImpl::Enable(bool enable) { | 219 int EchoCancellationImpl::Enable(bool enable) { |
244 // Run in a single-threaded manner. | 220 // Run in a single-threaded manner. |
245 rtc::CritScope cs_render(crit_render_); | 221 rtc::CritScope cs_render(crit_render_); |
246 rtc::CritScope cs_capture(crit_capture_); | 222 rtc::CritScope cs_capture(crit_capture_); |
247 // Ensure AEC and AECM are not both enabled. | 223 // Ensure AEC and AECM are not both enabled. |
248 // The is_enabled call is safe from a deadlock perspective | 224 // The is_enabled call is safe from a deadlock perspective |
249 // as both locks are already held in the correct order. | 225 // as both locks are already held in the correct order. |
250 if (enable && apm_->echo_control_mobile()->is_enabled()) { | 226 if (enable && apm_->echo_control_mobile()->is_enabled()) { |
251 return AudioProcessing::kBadParameterError; | 227 return AudioProcessing::kBadParameterError; |
252 } | 228 } |
253 | 229 |
254 if (enable && !enabled_) { | 230 return EnableComponent(enable); |
255 enabled_ = enable; // Must be set before Initialize() is called. | |
256 Initialize(); | |
257 } else { | |
258 enabled_ = enable; | |
259 } | |
260 return AudioProcessing::kNoError; | |
261 } | 231 } |
262 | 232 |
263 bool EchoCancellationImpl::is_enabled() const { | 233 bool EchoCancellationImpl::is_enabled() const { |
264 rtc::CritScope cs(crit_capture_); | 234 rtc::CritScope cs(crit_capture_); |
265 return enabled_; | 235 return is_component_enabled(); |
266 } | 236 } |
267 | 237 |
268 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) { | 238 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) { |
269 { | 239 { |
270 if (MapSetting(level) == -1) { | 240 if (MapSetting(level) == -1) { |
271 return AudioProcessing::kBadParameterError; | 241 return AudioProcessing::kBadParameterError; |
272 } | 242 } |
273 rtc::CritScope cs(crit_capture_); | 243 rtc::CritScope cs(crit_capture_); |
274 suppression_level_ = level; | 244 suppression_level_ = level; |
275 } | 245 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 } | 290 } |
321 | 291 |
322 // TODO(ajm): we currently just use the metrics from the first AEC. Think more | 292 // TODO(ajm): we currently just use the metrics from the first AEC. Think more |
323 // aboue the best way to extend this to multi-channel. | 293 // aboue the best way to extend this to multi-channel. |
324 int EchoCancellationImpl::GetMetrics(Metrics* metrics) { | 294 int EchoCancellationImpl::GetMetrics(Metrics* metrics) { |
325 rtc::CritScope cs(crit_capture_); | 295 rtc::CritScope cs(crit_capture_); |
326 if (metrics == NULL) { | 296 if (metrics == NULL) { |
327 return AudioProcessing::kNullPointerError; | 297 return AudioProcessing::kNullPointerError; |
328 } | 298 } |
329 | 299 |
330 if (!enabled_ || !metrics_enabled_) { | 300 if (!is_component_enabled() || !metrics_enabled_) { |
331 return AudioProcessing::kNotEnabledError; | 301 return AudioProcessing::kNotEnabledError; |
332 } | 302 } |
333 | 303 |
334 AecMetrics my_metrics; | 304 AecMetrics my_metrics; |
335 memset(&my_metrics, 0, sizeof(my_metrics)); | 305 memset(&my_metrics, 0, sizeof(my_metrics)); |
336 memset(metrics, 0, sizeof(Metrics)); | 306 memset(metrics, 0, sizeof(Metrics)); |
337 | 307 |
338 Handle* my_handle = cancellers_[0]->state(); | 308 Handle* my_handle = static_cast<Handle*>(handle(0)); |
339 int err = WebRtcAec_GetMetrics(my_handle, &my_metrics); | 309 int err = WebRtcAec_GetMetrics(my_handle, &my_metrics); |
340 if (err != AudioProcessing::kNoError) { | 310 if (err != AudioProcessing::kNoError) { |
341 return MapError(err); | 311 return MapError(err); |
342 } | 312 } |
343 | 313 |
344 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant; | 314 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant; |
345 metrics->residual_echo_return_loss.average = my_metrics.rerl.average; | 315 metrics->residual_echo_return_loss.average = my_metrics.rerl.average; |
346 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max; | 316 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max; |
347 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min; | 317 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min; |
348 | 318 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std, | 377 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std, |
408 float* fraction_poor_delays) { | 378 float* fraction_poor_delays) { |
409 rtc::CritScope cs(crit_capture_); | 379 rtc::CritScope cs(crit_capture_); |
410 if (median == NULL) { | 380 if (median == NULL) { |
411 return AudioProcessing::kNullPointerError; | 381 return AudioProcessing::kNullPointerError; |
412 } | 382 } |
413 if (std == NULL) { | 383 if (std == NULL) { |
414 return AudioProcessing::kNullPointerError; | 384 return AudioProcessing::kNullPointerError; |
415 } | 385 } |
416 | 386 |
417 if (!enabled_ || !delay_logging_enabled_) { | 387 if (!is_component_enabled() || !delay_logging_enabled_) { |
418 return AudioProcessing::kNotEnabledError; | 388 return AudioProcessing::kNotEnabledError; |
419 } | 389 } |
420 | 390 |
421 Handle* my_handle = cancellers_[0]->state(); | 391 Handle* my_handle = static_cast<Handle*>(handle(0)); |
422 const int err = | 392 const int err = |
423 WebRtcAec_GetDelayMetrics(my_handle, median, std, fraction_poor_delays); | 393 WebRtcAec_GetDelayMetrics(my_handle, median, std, fraction_poor_delays); |
424 if (err != AudioProcessing::kNoError) { | 394 if (err != AudioProcessing::kNoError) { |
425 return MapError(err); | 395 return MapError(err); |
426 } | 396 } |
427 | 397 |
428 return AudioProcessing::kNoError; | 398 return AudioProcessing::kNoError; |
429 } | 399 } |
430 | 400 |
431 struct AecCore* EchoCancellationImpl::aec_core() const { | 401 struct AecCore* EchoCancellationImpl::aec_core() const { |
432 rtc::CritScope cs(crit_capture_); | 402 rtc::CritScope cs(crit_capture_); |
433 if (!enabled_) { | 403 if (!is_component_enabled()) { |
434 return NULL; | 404 return NULL; |
435 } | 405 } |
436 Handle* my_handle = cancellers_[0]->state(); | 406 Handle* my_handle = static_cast<Handle*>(handle(0)); |
437 return WebRtcAec_aec_core(my_handle); | 407 return WebRtcAec_aec_core(my_handle); |
438 } | 408 } |
439 | 409 |
440 void EchoCancellationImpl::Initialize() { | 410 int EchoCancellationImpl::Initialize() { |
441 rtc::CritScope cs_render(crit_render_); | 411 int err = ProcessingComponent::Initialize(); |
442 rtc::CritScope cs_capture(crit_capture_); | 412 { |
443 if (!enabled_) { | 413 rtc::CritScope cs(crit_capture_); |
444 return; | 414 if (err != AudioProcessing::kNoError || !is_component_enabled()) { |
445 } | 415 return err; |
446 const int sample_rate_hz = apm_->proc_sample_rate_hz(); | |
447 | |
448 if (num_handles_required() > cancellers_.size()) { | |
449 const size_t cancellers_old_size = cancellers_.size(); | |
450 cancellers_.resize(num_handles_required()); | |
451 | |
452 for (size_t i = cancellers_old_size; i < cancellers_.size(); ++i) { | |
453 cancellers_[i].reset(new Canceller(sample_rate_hz)); | |
454 } | 416 } |
455 } | 417 } |
456 | 418 |
457 for (size_t i = 0; i < cancellers_.size(); ++i) { | 419 AllocateRenderQueue(); |
458 cancellers_[i]->Initialize(sample_rate_hz); | |
459 } | |
460 | 420 |
461 Configure(); | 421 return AudioProcessing::kNoError; |
462 | |
463 AllocateRenderQueue(); | |
464 } | 422 } |
465 | 423 |
466 void EchoCancellationImpl::AllocateRenderQueue() { | 424 void EchoCancellationImpl::AllocateRenderQueue() { |
467 const size_t new_render_queue_element_max_size = std::max<size_t>( | 425 const size_t new_render_queue_element_max_size = std::max<size_t>( |
468 static_cast<size_t>(1), | 426 static_cast<size_t>(1), |
469 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); | 427 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); |
470 | 428 |
471 rtc::CritScope cs_render(crit_render_); | 429 rtc::CritScope cs_render(crit_render_); |
472 rtc::CritScope cs_capture(crit_capture_); | 430 rtc::CritScope cs_capture(crit_capture_); |
473 | 431 |
(...skipping 19 matching lines...) Expand all Loading... |
493 void EchoCancellationImpl::SetExtraOptions(const Config& config) { | 451 void EchoCancellationImpl::SetExtraOptions(const Config& config) { |
494 { | 452 { |
495 rtc::CritScope cs(crit_capture_); | 453 rtc::CritScope cs(crit_capture_); |
496 extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled; | 454 extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled; |
497 delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled; | 455 delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled; |
498 next_generation_aec_enabled_ = config.Get<NextGenerationAec>().enabled; | 456 next_generation_aec_enabled_ = config.Get<NextGenerationAec>().enabled; |
499 } | 457 } |
500 Configure(); | 458 Configure(); |
501 } | 459 } |
502 | 460 |
503 int EchoCancellationImpl::Configure() { | 461 void* EchoCancellationImpl::CreateHandle() const { |
| 462 return WebRtcAec_Create(); |
| 463 } |
| 464 |
| 465 void EchoCancellationImpl::DestroyHandle(void* handle) const { |
| 466 assert(handle != NULL); |
| 467 WebRtcAec_Free(static_cast<Handle*>(handle)); |
| 468 } |
| 469 |
| 470 int EchoCancellationImpl::InitializeHandle(void* handle) const { |
| 471 // Not locked as it only relies on APM public API which is threadsafe. |
| 472 |
| 473 assert(handle != NULL); |
| 474 // TODO(ajm): Drift compensation is disabled in practice. If restored, it |
| 475 // should be managed internally and not depend on the hardware sample rate. |
| 476 // For now, just hardcode a 48 kHz value. |
| 477 return WebRtcAec_Init(static_cast<Handle*>(handle), |
| 478 apm_->proc_sample_rate_hz(), 48000); |
| 479 } |
| 480 |
| 481 int EchoCancellationImpl::ConfigureHandle(void* handle) const { |
504 rtc::CritScope cs_render(crit_render_); | 482 rtc::CritScope cs_render(crit_render_); |
505 rtc::CritScope cs_capture(crit_capture_); | 483 rtc::CritScope cs_capture(crit_capture_); |
| 484 assert(handle != NULL); |
506 AecConfig config; | 485 AecConfig config; |
507 config.metricsMode = metrics_enabled_; | 486 config.metricsMode = metrics_enabled_; |
508 config.nlpMode = MapSetting(suppression_level_); | 487 config.nlpMode = MapSetting(suppression_level_); |
509 config.skewMode = drift_compensation_enabled_; | 488 config.skewMode = drift_compensation_enabled_; |
510 config.delay_logging = delay_logging_enabled_; | 489 config.delay_logging = delay_logging_enabled_; |
511 | 490 WebRtcAec_enable_extended_filter( |
512 int error = AudioProcessing::kNoError; | 491 WebRtcAec_aec_core(static_cast<Handle*>(handle)), |
513 for (size_t i = 0; i < cancellers_.size(); i++) { | 492 extended_filter_enabled_ ? 1 : 0); |
514 Handle* my_handle = cancellers_[i]->state(); | 493 WebRtcAec_enable_delay_agnostic( |
515 WebRtcAec_enable_extended_filter(WebRtcAec_aec_core(my_handle), | 494 WebRtcAec_aec_core(static_cast<Handle*>(handle)), |
516 extended_filter_enabled_ ? 1 : 0); | 495 delay_agnostic_enabled_ ? 1 : 0); |
517 WebRtcAec_enable_delay_agnostic(WebRtcAec_aec_core(my_handle), | 496 WebRtcAec_enable_next_generation_aec( |
518 delay_agnostic_enabled_ ? 1 : 0); | 497 WebRtcAec_aec_core(static_cast<Handle*>(handle)), |
519 WebRtcAec_enable_next_generation_aec(WebRtcAec_aec_core(my_handle), | 498 next_generation_aec_enabled_ ? 1 : 0); |
520 next_generation_aec_enabled_ ? 1 : 0); | 499 return WebRtcAec_set_config(static_cast<Handle*>(handle), config); |
521 const int handle_error = WebRtcAec_set_config(my_handle, config); | |
522 if (handle_error != AudioProcessing::kNoError) { | |
523 error = AudioProcessing::kNoError; | |
524 } | |
525 } | |
526 return error; | |
527 } | 500 } |
528 | 501 |
529 size_t EchoCancellationImpl::num_handles_required() const { | 502 size_t EchoCancellationImpl::num_handles_required() const { |
530 // Not locked as it only relies on APM public API which is threadsafe. | 503 // Not locked as it only relies on APM public API which is threadsafe. |
531 return apm_->num_output_channels() * apm_->num_reverse_channels(); | 504 return apm_->num_output_channels() * apm_->num_reverse_channels(); |
532 } | 505 } |
533 | 506 |
| 507 int EchoCancellationImpl::GetHandleError(void* handle) const { |
| 508 // Not locked as it does not rely on anything in the state. |
| 509 assert(handle != NULL); |
| 510 return AudioProcessing::kUnspecifiedError; |
| 511 } |
534 } // namespace webrtc | 512 } // namespace webrtc |
OLD | NEW |