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 extern "C" { | 16 extern "C" { |
17 #include "webrtc/modules/audio_processing/aec/aec_core.h" | 17 #include "webrtc/modules/audio_processing/aec/aec_core.h" |
18 } | 18 } |
19 #include "webrtc/modules/audio_processing/aec/echo_cancellation.h" | 19 #include "webrtc/modules/audio_processing/aec/echo_cancellation.h" |
20 #include "webrtc/modules/audio_processing/audio_buffer.h" | 20 #include "webrtc/modules/audio_processing/audio_buffer.h" |
21 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
22 | 21 |
23 namespace webrtc { | 22 namespace webrtc { |
24 | 23 |
25 typedef void Handle; | 24 typedef void Handle; |
26 | 25 |
27 namespace { | 26 namespace { |
28 int16_t MapSetting(EchoCancellation::SuppressionLevel level) { | 27 int16_t MapSetting(EchoCancellation::SuppressionLevel level) { |
29 switch (level) { | 28 switch (level) { |
30 case EchoCancellation::kLowSuppression: | 29 case EchoCancellation::kLowSuppression: |
31 return kAecNlpConservative; | 30 return kAecNlpConservative; |
(...skipping 25 matching lines...) Expand all Loading... | |
57 // Maximum length that a frame of samples can have. | 56 // Maximum length that a frame of samples can have. |
58 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; | 57 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; |
59 // Maximum number of frames to buffer in the render queue. | 58 // Maximum number of frames to buffer in the render queue. |
60 // TODO(peah): Decrease this once we properly handle hugely unbalanced | 59 // TODO(peah): Decrease this once we properly handle hugely unbalanced |
61 // reverse and forward call numbers. | 60 // reverse and forward call numbers. |
62 static const size_t kMaxNumFramesToBuffer = 100; | 61 static const size_t kMaxNumFramesToBuffer = 100; |
63 } // namespace | 62 } // namespace |
64 | 63 |
65 EchoCancellationImpl::EchoCancellationImpl( | 64 EchoCancellationImpl::EchoCancellationImpl( |
66 const AudioProcessing* apm, | 65 const AudioProcessing* apm, |
67 CriticalSectionWrapper* crit, | 66 rtc::CriticalSection* crit_render, |
67 rtc::CriticalSection* crit_capture, | |
68 const rtc::ThreadChecker* render_thread_checker) | 68 const rtc::ThreadChecker* render_thread_checker) |
69 : ProcessingComponent(), | 69 : ProcessingComponent(), |
70 apm_(apm), | 70 apm_(apm), |
71 crit_(crit), | 71 crit_render_(crit_render), |
72 crit_capture_(crit_capture), | |
72 render_thread_checker_(render_thread_checker), | 73 render_thread_checker_(render_thread_checker), |
73 drift_compensation_enabled_(false), | 74 drift_compensation_enabled_(false), |
74 metrics_enabled_(false), | 75 metrics_enabled_(false), |
75 suppression_level_(kModerateSuppression), | 76 suppression_level_(kModerateSuppression), |
76 stream_drift_samples_(0), | 77 stream_drift_samples_(0), |
77 was_stream_drift_set_(false), | 78 was_stream_drift_set_(false), |
78 stream_has_echo_(false), | 79 stream_has_echo_(false), |
79 delay_logging_enabled_(false), | 80 delay_logging_enabled_(false), |
80 extended_filter_enabled_(false), | 81 extended_filter_enabled_(false), |
81 delay_agnostic_enabled_(false), | 82 delay_agnostic_enabled_(false), |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
113 // Buffer the samples in the render queue. | 114 // Buffer the samples in the render queue. |
114 render_queue_buffer_.insert(render_queue_buffer_.end(), | 115 render_queue_buffer_.insert(render_queue_buffer_.end(), |
115 audio->split_bands_const_f(j)[kBand0To8kHz], | 116 audio->split_bands_const_f(j)[kBand0To8kHz], |
116 (audio->split_bands_const_f(j)[kBand0To8kHz] + | 117 (audio->split_bands_const_f(j)[kBand0To8kHz] + |
117 audio->num_frames_per_band())); | 118 audio->num_frames_per_band())); |
118 } | 119 } |
119 } | 120 } |
120 | 121 |
121 // Insert the samples into the queue. | 122 // Insert the samples into the queue. |
122 if (!render_signal_queue_->Insert(&render_queue_buffer_)) { | 123 if (!render_signal_queue_->Insert(&render_queue_buffer_)) { |
123 ReadQueuedRenderData(); | 124 // The data queue is full and needs to be emptied. |
125 { | |
126 rtc::CritScope cs_capture(crit_capture_); | |
127 ReadQueuedRenderData(); | |
128 } | |
124 | 129 |
125 // Retry the insert (should always work). | 130 // Retry the insert (should always work). |
126 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); | 131 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); |
127 } | 132 } |
128 | 133 |
129 return apm_->kNoError; | 134 return apm_->kNoError; |
130 } | 135 } |
131 | 136 |
132 // Read chunks of data that were received and queued on the render side from | 137 // Read chunks of data that were received and queued on the render side from |
133 // a queue. All the data chunks are buffered into the farend signal of the AEC. | 138 // a queue. All the data chunks are buffered into the farend signal of the AEC. |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
208 | 213 |
209 handle_index++; | 214 handle_index++; |
210 } | 215 } |
211 } | 216 } |
212 | 217 |
213 was_stream_drift_set_ = false; | 218 was_stream_drift_set_ = false; |
214 return apm_->kNoError; | 219 return apm_->kNoError; |
215 } | 220 } |
216 | 221 |
217 int EchoCancellationImpl::Enable(bool enable) { | 222 int EchoCancellationImpl::Enable(bool enable) { |
218 CriticalSectionScoped crit_scoped(crit_); | 223 // Run in a single-threaded manner. |
224 rtc::CritScope cs_render(crit_render_); | |
225 rtc::CritScope cs_capture(crit_capture_); | |
219 // Ensure AEC and AECM are not both enabled. | 226 // Ensure AEC and AECM are not both enabled. |
220 if (enable && apm_->echo_control_mobile()->is_enabled()) { | 227 if (enable && apm_->echo_control_mobile()->is_enabled()) { |
221 return apm_->kBadParameterError; | 228 return apm_->kBadParameterError; |
222 } | 229 } |
223 | 230 |
224 return EnableComponent(enable); | 231 return EnableComponent(enable); |
225 } | 232 } |
226 | 233 |
227 bool EchoCancellationImpl::is_enabled() const { | 234 bool EchoCancellationImpl::is_enabled() const { |
235 rtc::CritScope cs(crit_capture_); | |
228 return is_component_enabled(); | 236 return is_component_enabled(); |
229 } | 237 } |
230 | 238 |
231 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) { | 239 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) { |
232 CriticalSectionScoped crit_scoped(crit_); | 240 rtc::CritScope cs(crit_capture_); |
233 if (MapSetting(level) == -1) { | 241 if (MapSetting(level) == -1) { |
234 return apm_->kBadParameterError; | 242 return apm_->kBadParameterError; |
235 } | 243 } |
236 | 244 |
237 suppression_level_ = level; | 245 suppression_level_ = level; |
238 return Configure(); | 246 return Configure(); |
239 } | 247 } |
240 | 248 |
241 EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level() | 249 EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level() |
242 const { | 250 const { |
251 rtc::CritScope cs(crit_capture_); | |
243 return suppression_level_; | 252 return suppression_level_; |
244 } | 253 } |
245 | 254 |
246 int EchoCancellationImpl::enable_drift_compensation(bool enable) { | 255 int EchoCancellationImpl::enable_drift_compensation(bool enable) { |
247 CriticalSectionScoped crit_scoped(crit_); | 256 rtc::CritScope cs(crit_capture_); |
248 drift_compensation_enabled_ = enable; | 257 drift_compensation_enabled_ = enable; |
249 return Configure(); | 258 return Configure(); |
250 } | 259 } |
251 | 260 |
252 bool EchoCancellationImpl::is_drift_compensation_enabled() const { | 261 bool EchoCancellationImpl::is_drift_compensation_enabled() const { |
262 rtc::CritScope cs(crit_capture_); | |
253 return drift_compensation_enabled_; | 263 return drift_compensation_enabled_; |
254 } | 264 } |
255 | 265 |
256 void EchoCancellationImpl::set_stream_drift_samples(int drift) { | 266 void EchoCancellationImpl::set_stream_drift_samples(int drift) { |
267 rtc::CritScope cs(crit_capture_); | |
257 was_stream_drift_set_ = true; | 268 was_stream_drift_set_ = true; |
258 stream_drift_samples_ = drift; | 269 stream_drift_samples_ = drift; |
259 } | 270 } |
260 | 271 |
261 int EchoCancellationImpl::stream_drift_samples() const { | 272 int EchoCancellationImpl::stream_drift_samples() const { |
273 rtc::CritScope cs(crit_capture_); | |
262 return stream_drift_samples_; | 274 return stream_drift_samples_; |
263 } | 275 } |
264 | 276 |
265 int EchoCancellationImpl::enable_metrics(bool enable) { | 277 int EchoCancellationImpl::enable_metrics(bool enable) { |
266 CriticalSectionScoped crit_scoped(crit_); | 278 rtc::CritScope cs(crit_capture_); |
267 metrics_enabled_ = enable; | 279 metrics_enabled_ = enable; |
268 return Configure(); | 280 return Configure(); |
269 } | 281 } |
270 | 282 |
271 bool EchoCancellationImpl::are_metrics_enabled() const { | 283 bool EchoCancellationImpl::are_metrics_enabled() const { |
284 rtc::CritScope cs(crit_capture_); | |
272 return metrics_enabled_; | 285 return metrics_enabled_; |
273 } | 286 } |
274 | 287 |
275 // TODO(ajm): we currently just use the metrics from the first AEC. Think more | 288 // TODO(ajm): we currently just use the metrics from the first AEC. Think more |
276 // aboue the best way to extend this to multi-channel. | 289 // aboue the best way to extend this to multi-channel. |
277 int EchoCancellationImpl::GetMetrics(Metrics* metrics) { | 290 int EchoCancellationImpl::GetMetrics(Metrics* metrics) { |
278 CriticalSectionScoped crit_scoped(crit_); | 291 rtc::CritScope cs(crit_capture_); |
279 if (metrics == NULL) { | 292 if (metrics == NULL) { |
280 return apm_->kNullPointerError; | 293 return apm_->kNullPointerError; |
281 } | 294 } |
282 | 295 |
283 if (!is_component_enabled() || !metrics_enabled_) { | 296 if (!is_component_enabled() || !metrics_enabled_) { |
284 return apm_->kNotEnabledError; | 297 return apm_->kNotEnabledError; |
285 } | 298 } |
286 | 299 |
287 AecMetrics my_metrics; | 300 AecMetrics my_metrics; |
288 memset(&my_metrics, 0, sizeof(my_metrics)); | 301 memset(&my_metrics, 0, sizeof(my_metrics)); |
(...skipping 22 matching lines...) Expand all Loading... | |
311 | 324 |
312 metrics->a_nlp.instant = my_metrics.aNlp.instant; | 325 metrics->a_nlp.instant = my_metrics.aNlp.instant; |
313 metrics->a_nlp.average = my_metrics.aNlp.average; | 326 metrics->a_nlp.average = my_metrics.aNlp.average; |
314 metrics->a_nlp.maximum = my_metrics.aNlp.max; | 327 metrics->a_nlp.maximum = my_metrics.aNlp.max; |
315 metrics->a_nlp.minimum = my_metrics.aNlp.min; | 328 metrics->a_nlp.minimum = my_metrics.aNlp.min; |
316 | 329 |
317 return apm_->kNoError; | 330 return apm_->kNoError; |
318 } | 331 } |
319 | 332 |
320 bool EchoCancellationImpl::stream_has_echo() const { | 333 bool EchoCancellationImpl::stream_has_echo() const { |
334 // This is called both from within and from outside of APM, with and | |
335 // without locks set. The lock acquisition below is hence possible | |
336 // reentrant. | |
kwiberg-webrtc
2015/11/25 10:17:14
possibly
peah-webrtc
2015/11/25 12:33:53
Done.
| |
337 rtc::CritScope cs(crit_capture_); | |
338 | |
321 return stream_has_echo_; | 339 return stream_has_echo_; |
322 } | 340 } |
323 | 341 |
324 int EchoCancellationImpl::enable_delay_logging(bool enable) { | 342 int EchoCancellationImpl::enable_delay_logging(bool enable) { |
325 CriticalSectionScoped crit_scoped(crit_); | 343 // This is called both from within and from outside of APM, with and |
344 // without locks set. The lock acquisition below is hence possible | |
345 // reentrant. | |
kwiberg-webrtc
2015/11/25 10:17:14
possibly
peah-webrtc
2015/11/25 12:33:53
Done.
| |
346 rtc::CritScope cs(crit_capture_); | |
347 | |
326 delay_logging_enabled_ = enable; | 348 delay_logging_enabled_ = enable; |
327 return Configure(); | 349 return Configure(); |
328 } | 350 } |
329 | 351 |
330 bool EchoCancellationImpl::is_delay_logging_enabled() const { | 352 bool EchoCancellationImpl::is_delay_logging_enabled() const { |
353 rtc::CritScope cs(crit_capture_); | |
331 return delay_logging_enabled_; | 354 return delay_logging_enabled_; |
332 } | 355 } |
333 | 356 |
334 bool EchoCancellationImpl::is_delay_agnostic_enabled() const { | 357 bool EchoCancellationImpl::is_delay_agnostic_enabled() const { |
358 // Only called from within APM, hence no locking is needed. | |
335 return delay_agnostic_enabled_; | 359 return delay_agnostic_enabled_; |
336 } | 360 } |
337 | 361 |
338 bool EchoCancellationImpl::is_extended_filter_enabled() const { | 362 bool EchoCancellationImpl::is_extended_filter_enabled() const { |
363 // Only called from within APM, hence no locking is needed. | |
339 return extended_filter_enabled_; | 364 return extended_filter_enabled_; |
340 } | 365 } |
341 | 366 |
342 // TODO(bjornv): How should we handle the multi-channel case? | 367 // TODO(bjornv): How should we handle the multi-channel case? |
343 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) { | 368 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) { |
369 rtc::CritScope cs(crit_capture_); | |
344 float fraction_poor_delays = 0; | 370 float fraction_poor_delays = 0; |
345 return GetDelayMetrics(median, std, &fraction_poor_delays); | 371 return GetDelayMetrics(median, std, &fraction_poor_delays); |
346 } | 372 } |
347 | 373 |
348 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std, | 374 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std, |
349 float* fraction_poor_delays) { | 375 float* fraction_poor_delays) { |
350 CriticalSectionScoped crit_scoped(crit_); | 376 rtc::CritScope cs(crit_capture_); |
351 if (median == NULL) { | 377 if (median == NULL) { |
352 return apm_->kNullPointerError; | 378 return apm_->kNullPointerError; |
353 } | 379 } |
354 if (std == NULL) { | 380 if (std == NULL) { |
355 return apm_->kNullPointerError; | 381 return apm_->kNullPointerError; |
356 } | 382 } |
357 | 383 |
358 if (!is_component_enabled() || !delay_logging_enabled_) { | 384 if (!is_component_enabled() || !delay_logging_enabled_) { |
359 return apm_->kNotEnabledError; | 385 return apm_->kNotEnabledError; |
360 } | 386 } |
361 | 387 |
362 Handle* my_handle = static_cast<Handle*>(handle(0)); | 388 Handle* my_handle = static_cast<Handle*>(handle(0)); |
363 const int err = | 389 const int err = |
364 WebRtcAec_GetDelayMetrics(my_handle, median, std, fraction_poor_delays); | 390 WebRtcAec_GetDelayMetrics(my_handle, median, std, fraction_poor_delays); |
365 if (err != apm_->kNoError) { | 391 if (err != apm_->kNoError) { |
366 return MapError(err); | 392 return MapError(err); |
367 } | 393 } |
368 | 394 |
369 return apm_->kNoError; | 395 return apm_->kNoError; |
370 } | 396 } |
371 | 397 |
372 struct AecCore* EchoCancellationImpl::aec_core() const { | 398 struct AecCore* EchoCancellationImpl::aec_core() const { |
373 CriticalSectionScoped crit_scoped(crit_); | 399 // Only called from within APM, hence no locking is needed. |
374 if (!is_component_enabled()) { | 400 if (!is_component_enabled()) { |
375 return NULL; | 401 return NULL; |
376 } | 402 } |
377 Handle* my_handle = static_cast<Handle*>(handle(0)); | 403 Handle* my_handle = static_cast<Handle*>(handle(0)); |
378 return WebRtcAec_aec_core(my_handle); | 404 return WebRtcAec_aec_core(my_handle); |
379 } | 405 } |
380 | 406 |
381 int EchoCancellationImpl::Initialize() { | 407 int EchoCancellationImpl::Initialize() { |
408 // Only called from within APM, hence no locking is needed. | |
382 int err = ProcessingComponent::Initialize(); | 409 int err = ProcessingComponent::Initialize(); |
383 if (err != apm_->kNoError || !is_component_enabled()) { | 410 if (err != apm_->kNoError || !is_component_enabled()) { |
384 return err; | 411 return err; |
385 } | 412 } |
386 | 413 |
387 AllocateRenderQueue(); | 414 AllocateRenderQueue(); |
388 | 415 |
389 return apm_->kNoError; | 416 return apm_->kNoError; |
390 } | 417 } |
391 | 418 |
(...skipping 15 matching lines...) Expand all Loading... | |
407 RenderQueueItemVerifier<float>(render_queue_element_max_size_))); | 434 RenderQueueItemVerifier<float>(render_queue_element_max_size_))); |
408 | 435 |
409 render_queue_buffer_.resize(render_queue_element_max_size_); | 436 render_queue_buffer_.resize(render_queue_element_max_size_); |
410 capture_queue_buffer_.resize(render_queue_element_max_size_); | 437 capture_queue_buffer_.resize(render_queue_element_max_size_); |
411 } else { | 438 } else { |
412 render_signal_queue_->Clear(); | 439 render_signal_queue_->Clear(); |
413 } | 440 } |
414 } | 441 } |
415 | 442 |
416 void EchoCancellationImpl::SetExtraOptions(const Config& config) { | 443 void EchoCancellationImpl::SetExtraOptions(const Config& config) { |
444 // This is called both from within and from outside of APM, with and | |
445 // without locks set. The lock acquisition below is hence possible | |
446 // reentrant. | |
kwiberg-webrtc
2015/11/25 10:17:14
possibly
peah-webrtc
2015/11/25 12:33:53
Done.
| |
447 rtc::CritScope cs(crit_capture_); | |
417 extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled; | 448 extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled; |
418 delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled; | 449 delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled; |
419 Configure(); | 450 Configure(); |
420 } | 451 } |
421 | 452 |
422 void* EchoCancellationImpl::CreateHandle() const { | 453 void* EchoCancellationImpl::CreateHandle() const { |
454 // Only called from within APM, hence no locking is needed. | |
423 return WebRtcAec_Create(); | 455 return WebRtcAec_Create(); |
424 } | 456 } |
425 | 457 |
426 void EchoCancellationImpl::DestroyHandle(void* handle) const { | 458 void EchoCancellationImpl::DestroyHandle(void* handle) const { |
459 // Only called from within APM, hence no locking is needed. | |
427 assert(handle != NULL); | 460 assert(handle != NULL); |
428 WebRtcAec_Free(static_cast<Handle*>(handle)); | 461 WebRtcAec_Free(static_cast<Handle*>(handle)); |
429 } | 462 } |
430 | 463 |
431 int EchoCancellationImpl::InitializeHandle(void* handle) const { | 464 int EchoCancellationImpl::InitializeHandle(void* handle) const { |
465 // Only called from within APM, hence no locking is needed. | |
432 assert(handle != NULL); | 466 assert(handle != NULL); |
433 // TODO(ajm): Drift compensation is disabled in practice. If restored, it | 467 // TODO(ajm): Drift compensation is disabled in practice. If restored, it |
434 // should be managed internally and not depend on the hardware sample rate. | 468 // should be managed internally and not depend on the hardware sample rate. |
435 // For now, just hardcode a 48 kHz value. | 469 // For now, just hardcode a 48 kHz value. |
436 return WebRtcAec_Init(static_cast<Handle*>(handle), | 470 return WebRtcAec_Init(static_cast<Handle*>(handle), |
437 apm_->proc_sample_rate_hz(), | 471 apm_->proc_sample_rate_hz(), |
438 48000); | 472 48000); |
439 } | 473 } |
440 | 474 |
441 int EchoCancellationImpl::ConfigureHandle(void* handle) const { | 475 int EchoCancellationImpl::ConfigureHandle(void* handle) const { |
476 // Only called from within APM, hence no locking is needed. | |
442 assert(handle != NULL); | 477 assert(handle != NULL); |
443 AecConfig config; | 478 AecConfig config; |
444 config.metricsMode = metrics_enabled_; | 479 config.metricsMode = metrics_enabled_; |
445 config.nlpMode = MapSetting(suppression_level_); | 480 config.nlpMode = MapSetting(suppression_level_); |
446 config.skewMode = drift_compensation_enabled_; | 481 config.skewMode = drift_compensation_enabled_; |
447 config.delay_logging = delay_logging_enabled_; | 482 config.delay_logging = delay_logging_enabled_; |
448 WebRtcAec_enable_extended_filter( | 483 WebRtcAec_enable_extended_filter( |
449 WebRtcAec_aec_core(static_cast<Handle*>(handle)), | 484 WebRtcAec_aec_core(static_cast<Handle*>(handle)), |
450 extended_filter_enabled_ ? 1 : 0); | 485 extended_filter_enabled_ ? 1 : 0); |
451 WebRtcAec_enable_delay_agnostic( | 486 WebRtcAec_enable_delay_agnostic( |
452 WebRtcAec_aec_core(static_cast<Handle*>(handle)), | 487 WebRtcAec_aec_core(static_cast<Handle*>(handle)), |
453 delay_agnostic_enabled_ ? 1 : 0); | 488 delay_agnostic_enabled_ ? 1 : 0); |
454 return WebRtcAec_set_config(static_cast<Handle*>(handle), config); | 489 return WebRtcAec_set_config(static_cast<Handle*>(handle), config); |
455 } | 490 } |
456 | 491 |
457 int EchoCancellationImpl::num_handles_required() const { | 492 int EchoCancellationImpl::num_handles_required() const { |
493 // Only called from within APM, hence no locking is needed. | |
458 return apm_->num_output_channels() * | 494 return apm_->num_output_channels() * |
459 apm_->num_reverse_channels(); | 495 apm_->num_reverse_channels(); |
460 } | 496 } |
461 | 497 |
462 int EchoCancellationImpl::GetHandleError(void* handle) const { | 498 int EchoCancellationImpl::GetHandleError(void* handle) const { |
499 // Only called from within APM, hence no locking is needed. | |
463 assert(handle != NULL); | 500 assert(handle != NULL); |
464 return AudioProcessing::kUnspecifiedError; | 501 return AudioProcessing::kUnspecifiedError; |
465 } | 502 } |
466 } // namespace webrtc | 503 } // namespace webrtc |
OLD | NEW |