blob: cea905515a731c4da94c30385773991bd2c28517 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
bjornv@webrtc.org0c6f9312012-01-30 09:39:08 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
bjornv@webrtc.org21a2fc92013-02-15 17:01:03 +000011#include "webrtc/modules/audio_processing/echo_cancellation_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
bjornv@webrtc.org21a2fc92013-02-15 17:01:03 +000013#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include <string.h>
15
andrew@webrtc.org1760a172013-09-25 23:17:38 +000016#include "webrtc/modules/audio_processing/aec/aec_core.h"
Henrik Kjellander9b72af92015-11-11 20:16:11 +010017#include "webrtc/modules/audio_processing/aec/echo_cancellation.h"
bjornv@webrtc.org21a2fc92013-02-15 17:01:03 +000018#include "webrtc/modules/audio_processing/audio_buffer.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019
niklase@google.com470e71d2011-07-07 08:21:25 +000020namespace webrtc {
21
22typedef void Handle;
23
24namespace {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000025int16_t MapSetting(EchoCancellation::SuppressionLevel level) {
niklase@google.com470e71d2011-07-07 08:21:25 +000026 switch (level) {
27 case EchoCancellation::kLowSuppression:
28 return kAecNlpConservative;
29 case EchoCancellation::kModerateSuppression:
30 return kAecNlpModerate;
31 case EchoCancellation::kHighSuppression:
32 return kAecNlpAggressive;
niklase@google.com470e71d2011-07-07 08:21:25 +000033 }
andrew@webrtc.org648af742012-02-08 01:57:29 +000034 assert(false);
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000035 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000036}
37
andrew@webrtc.org648af742012-02-08 01:57:29 +000038AudioProcessing::Error MapError(int err) {
niklase@google.com470e71d2011-07-07 08:21:25 +000039 switch (err) {
40 case AEC_UNSUPPORTED_FUNCTION_ERROR:
41 return AudioProcessing::kUnsupportedFunctionError;
niklase@google.com470e71d2011-07-07 08:21:25 +000042 case AEC_BAD_PARAMETER_ERROR:
43 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +000044 case AEC_BAD_PARAMETER_WARNING:
45 return AudioProcessing::kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +000046 default:
47 // AEC_UNSPECIFIED_ERROR
48 // AEC_UNINITIALIZED_ERROR
49 // AEC_NULL_POINTER_ERROR
50 return AudioProcessing::kUnspecifiedError;
51 }
52}
niklase@google.com470e71d2011-07-07 08:21:25 +000053
peah2446e5a2015-11-18 06:11:13 -080054// Maximum length that a frame of samples can have.
55static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160;
56// Maximum number of frames to buffer in the render queue.
57// TODO(peah): Decrease this once we properly handle hugely unbalanced
58// reverse and forward call numbers.
59static const size_t kMaxNumFramesToBuffer = 100;
60} // namespace
peahfa6228e2015-11-16 16:27:42 -080061
peahb624d8c2016-03-05 03:01:14 -080062class 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
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000090EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm,
peahdf3efa82015-11-28 12:35:15 -080091 rtc::CriticalSection* crit_render,
92 rtc::CriticalSection* crit_capture)
peahb624d8c2016-03-05 03:01:14 -080093 : apm_(apm),
peahdf3efa82015-11-28 12:35:15 -080094 crit_render_(crit_render),
95 crit_capture_(crit_capture),
Henrik Lundin441f6342015-06-09 16:03:13 +020096 drift_compensation_enabled_(false),
97 metrics_enabled_(false),
98 suppression_level_(kModerateSuppression),
99 stream_drift_samples_(0),
100 was_stream_drift_set_(false),
101 stream_has_echo_(false),
102 delay_logging_enabled_(false),
103 extended_filter_enabled_(false),
peahfa6228e2015-11-16 16:27:42 -0800104 delay_agnostic_enabled_(false),
peaha332e2d2016-02-17 01:11:16 -0800105 next_generation_aec_enabled_(false),
peahdf3efa82015-11-28 12:35:15 -0800106 render_queue_element_max_size_(0) {
107 RTC_DCHECK(apm);
108 RTC_DCHECK(crit_render);
109 RTC_DCHECK(crit_capture);
110}
niklase@google.com470e71d2011-07-07 08:21:25 +0000111
112EchoCancellationImpl::~EchoCancellationImpl() {}
113
114int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800115 rtc::CritScope cs_render(crit_render_);
peahb624d8c2016-03-05 03:01:14 -0800116 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800117 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 }
119
peahb624d8c2016-03-05 03:01:14 -0800120 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
121 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_reverse_channels());
122 RTC_DCHECK_GE(cancellers_.size(),
123 apm_->num_output_channels() * audio->num_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000124
peahdf3efa82015-11-28 12:35:15 -0800125 int err = AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000126
127 // The ordering convention must be followed to pass to the correct AEC.
128 size_t handle_index = 0;
peahfa6228e2015-11-16 16:27:42 -0800129 render_queue_buffer_.clear();
Peter Kasting69558702016-01-12 16:26:35 -0800130 for (size_t i = 0; i < apm_->num_output_channels(); i++) {
131 for (size_t j = 0; j < audio->num_channels(); j++) {
peahb624d8c2016-03-05 03:01:14 -0800132 Handle* my_handle = cancellers_[handle_index++]->state();
peahfa6228e2015-11-16 16:27:42 -0800133 // Retrieve any error code produced by the buffering of the farend
peahb624d8c2016-03-05 03:01:14 -0800134 // signal.
peahfa6228e2015-11-16 16:27:42 -0800135 err = WebRtcAec_GetBufferFarendError(
136 my_handle, audio->split_bands_const_f(j)[kBand0To8kHz],
Peter Kastingdce40cf2015-08-24 14:52:23 -0700137 audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000138
peahdf3efa82015-11-28 12:35:15 -0800139 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800140 return MapError(err); // TODO(ajm): warning possible?
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 }
142
peahfa6228e2015-11-16 16:27:42 -0800143 // Buffer the samples in the render queue.
144 render_queue_buffer_.insert(render_queue_buffer_.end(),
145 audio->split_bands_const_f(j)[kBand0To8kHz],
146 (audio->split_bands_const_f(j)[kBand0To8kHz] +
147 audio->num_frames_per_band()));
niklase@google.com470e71d2011-07-07 08:21:25 +0000148 }
149 }
150
peahfa6228e2015-11-16 16:27:42 -0800151 // Insert the samples into the queue.
152 if (!render_signal_queue_->Insert(&render_queue_buffer_)) {
peahdf3efa82015-11-28 12:35:15 -0800153 // The data queue is full and needs to be emptied.
peahfa6228e2015-11-16 16:27:42 -0800154 ReadQueuedRenderData();
155
156 // Retry the insert (should always work).
157 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true);
158 }
159
peahdf3efa82015-11-28 12:35:15 -0800160 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000161}
162
peahfa6228e2015-11-16 16:27:42 -0800163// 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.
165void EchoCancellationImpl::ReadQueuedRenderData() {
peahdf3efa82015-11-28 12:35:15 -0800166 rtc::CritScope cs_capture(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800167 if (!enabled_) {
peahfa6228e2015-11-16 16:27:42 -0800168 return;
169 }
170
171 while (render_signal_queue_->Remove(&capture_queue_buffer_)) {
172 size_t handle_index = 0;
pkasting25702cb2016-01-08 13:50:27 -0800173 size_t buffer_index = 0;
174 const size_t num_frames_per_band =
peahfa6228e2015-11-16 16:27:42 -0800175 capture_queue_buffer_.size() /
176 (apm_->num_output_channels() * apm_->num_reverse_channels());
Peter Kasting69558702016-01-12 16:26:35 -0800177 for (size_t i = 0; i < apm_->num_output_channels(); i++) {
178 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) {
peahb624d8c2016-03-05 03:01:14 -0800179 Handle* my_handle = cancellers_[handle_index++]->state();
peahfa6228e2015-11-16 16:27:42 -0800180 WebRtcAec_BufferFarend(my_handle, &capture_queue_buffer_[buffer_index],
181 num_frames_per_band);
182
183 buffer_index += num_frames_per_band;
peahfa6228e2015-11-16 16:27:42 -0800184 }
185 }
186 }
187}
188
niklase@google.com470e71d2011-07-07 08:21:25 +0000189int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800190 rtc::CritScope cs_capture(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800191 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800192 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 }
194
195 if (!apm_->was_stream_delay_set()) {
peahdf3efa82015-11-28 12:35:15 -0800196 return AudioProcessing::kStreamParameterNotSetError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 }
198
199 if (drift_compensation_enabled_ && !was_stream_drift_set_) {
peahdf3efa82015-11-28 12:35:15 -0800200 return AudioProcessing::kStreamParameterNotSetError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 }
202
peahb624d8c2016-03-05 03:01:14 -0800203 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
204 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_proc_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000205
peahdf3efa82015-11-28 12:35:15 -0800206 int err = AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000207
208 // The ordering convention must be followed to pass to the correct AEC.
209 size_t handle_index = 0;
210 stream_has_echo_ = false;
Peter Kasting69558702016-01-12 16:26:35 -0800211 for (size_t i = 0; i < audio->num_channels(); i++) {
212 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) {
peahb624d8c2016-03-05 03:01:14 -0800213 Handle* my_handle = cancellers_[handle_index++]->state();
peahdf3efa82015-11-28 12:35:15 -0800214 err = WebRtcAec_Process(my_handle, audio->split_bands_const_f(i),
215 audio->num_bands(), audio->split_bands_f(i),
216 audio->num_frames_per_band(),
217 apm_->stream_delay_ms(), stream_drift_samples_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000218
peahdf3efa82015-11-28 12:35:15 -0800219 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800220 err = MapError(err);
niklase@google.com470e71d2011-07-07 08:21:25 +0000221 // TODO(ajm): Figure out how to return warnings properly.
peahdf3efa82015-11-28 12:35:15 -0800222 if (err != AudioProcessing::kBadStreamParameterWarning) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000223 return err;
224 }
225 }
226
bjornv@webrtc.org21a2fc92013-02-15 17:01:03 +0000227 int status = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000228 err = WebRtcAec_get_echo_status(my_handle, &status);
peahdf3efa82015-11-28 12:35:15 -0800229 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800230 return MapError(err);
niklase@google.com470e71d2011-07-07 08:21:25 +0000231 }
232
233 if (status == 1) {
234 stream_has_echo_ = true;
235 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 }
237 }
238
239 was_stream_drift_set_ = false;
peahdf3efa82015-11-28 12:35:15 -0800240 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000241}
242
243int EchoCancellationImpl::Enable(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800244 // Run in a single-threaded manner.
245 rtc::CritScope cs_render(crit_render_);
246 rtc::CritScope cs_capture(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 // Ensure AEC and AECM are not both enabled.
peahdf3efa82015-11-28 12:35:15 -0800248 // The is_enabled call is safe from a deadlock perspective
249 // as both locks are already held in the correct order.
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 if (enable && apm_->echo_control_mobile()->is_enabled()) {
peahdf3efa82015-11-28 12:35:15 -0800251 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 }
253
peahb624d8c2016-03-05 03:01:14 -0800254 if (enable && !enabled_) {
255 enabled_ = enable; // Must be set before Initialize() is called.
256 Initialize();
257 } else {
258 enabled_ = enable;
259 }
260 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000261}
262
263bool EchoCancellationImpl::is_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800264 rtc::CritScope cs(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800265 return enabled_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
268int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) {
peahdf3efa82015-11-28 12:35:15 -0800269 {
270 if (MapSetting(level) == -1) {
271 return AudioProcessing::kBadParameterError;
272 }
273 rtc::CritScope cs(crit_capture_);
274 suppression_level_ = level;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000276 return Configure();
277}
278
279EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level()
280 const {
peahdf3efa82015-11-28 12:35:15 -0800281 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000282 return suppression_level_;
283}
284
285int EchoCancellationImpl::enable_drift_compensation(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800286 {
287 rtc::CritScope cs(crit_capture_);
288 drift_compensation_enabled_ = enable;
289 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 return Configure();
291}
292
293bool EchoCancellationImpl::is_drift_compensation_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800294 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000295 return drift_compensation_enabled_;
296}
297
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000298void EchoCancellationImpl::set_stream_drift_samples(int drift) {
peahdf3efa82015-11-28 12:35:15 -0800299 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000300 was_stream_drift_set_ = true;
301 stream_drift_samples_ = drift;
niklase@google.com470e71d2011-07-07 08:21:25 +0000302}
303
304int EchoCancellationImpl::stream_drift_samples() const {
peahdf3efa82015-11-28 12:35:15 -0800305 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000306 return stream_drift_samples_;
307}
308
309int EchoCancellationImpl::enable_metrics(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800310 {
311 rtc::CritScope cs(crit_capture_);
312 metrics_enabled_ = enable;
313 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000314 return Configure();
315}
316
317bool EchoCancellationImpl::are_metrics_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800318 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000319 return metrics_enabled_;
320}
321
322// 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.
324int EchoCancellationImpl::GetMetrics(Metrics* metrics) {
peahdf3efa82015-11-28 12:35:15 -0800325 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 if (metrics == NULL) {
peahdf3efa82015-11-28 12:35:15 -0800327 return AudioProcessing::kNullPointerError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 }
329
peahb624d8c2016-03-05 03:01:14 -0800330 if (!enabled_ || !metrics_enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800331 return AudioProcessing::kNotEnabledError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000332 }
333
334 AecMetrics my_metrics;
335 memset(&my_metrics, 0, sizeof(my_metrics));
336 memset(metrics, 0, sizeof(Metrics));
337
peahb624d8c2016-03-05 03:01:14 -0800338 Handle* my_handle = cancellers_[0]->state();
niklase@google.com470e71d2011-07-07 08:21:25 +0000339 int err = WebRtcAec_GetMetrics(my_handle, &my_metrics);
peahdf3efa82015-11-28 12:35:15 -0800340 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800341 return MapError(err);
niklase@google.com470e71d2011-07-07 08:21:25 +0000342 }
343
344 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant;
345 metrics->residual_echo_return_loss.average = my_metrics.rerl.average;
346 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max;
347 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min;
348
349 metrics->echo_return_loss.instant = my_metrics.erl.instant;
350 metrics->echo_return_loss.average = my_metrics.erl.average;
351 metrics->echo_return_loss.maximum = my_metrics.erl.max;
352 metrics->echo_return_loss.minimum = my_metrics.erl.min;
353
354 metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant;
355 metrics->echo_return_loss_enhancement.average = my_metrics.erle.average;
356 metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max;
357 metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min;
358
359 metrics->a_nlp.instant = my_metrics.aNlp.instant;
360 metrics->a_nlp.average = my_metrics.aNlp.average;
361 metrics->a_nlp.maximum = my_metrics.aNlp.max;
362 metrics->a_nlp.minimum = my_metrics.aNlp.min;
363
peahdf3efa82015-11-28 12:35:15 -0800364 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000365}
366
367bool EchoCancellationImpl::stream_has_echo() const {
peahdf3efa82015-11-28 12:35:15 -0800368 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000369 return stream_has_echo_;
370}
371
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000372int EchoCancellationImpl::enable_delay_logging(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800373 {
374 rtc::CritScope cs(crit_capture_);
375 delay_logging_enabled_ = enable;
376 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000377 return Configure();
378}
379
380bool EchoCancellationImpl::is_delay_logging_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800381 rtc::CritScope cs(crit_capture_);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000382 return delay_logging_enabled_;
383}
384
Minyue13b96ba2015-10-03 00:39:14 +0200385bool EchoCancellationImpl::is_delay_agnostic_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800386 rtc::CritScope cs(crit_capture_);
Minyue13b96ba2015-10-03 00:39:14 +0200387 return delay_agnostic_enabled_;
388}
389
peaha332e2d2016-02-17 01:11:16 -0800390bool EchoCancellationImpl::is_next_generation_aec_enabled() const {
391 rtc::CritScope cs(crit_capture_);
392 return next_generation_aec_enabled_;
393}
394
Minyue13b96ba2015-10-03 00:39:14 +0200395bool EchoCancellationImpl::is_extended_filter_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800396 rtc::CritScope cs(crit_capture_);
Minyue13b96ba2015-10-03 00:39:14 +0200397 return extended_filter_enabled_;
398}
399
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000400// TODO(bjornv): How should we handle the multi-channel case?
401int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) {
peahdf3efa82015-11-28 12:35:15 -0800402 rtc::CritScope cs(crit_capture_);
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +0000403 float fraction_poor_delays = 0;
404 return GetDelayMetrics(median, std, &fraction_poor_delays);
405}
406
407int EchoCancellationImpl::GetDelayMetrics(int* median, int* std,
408 float* fraction_poor_delays) {
peahdf3efa82015-11-28 12:35:15 -0800409 rtc::CritScope cs(crit_capture_);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000410 if (median == NULL) {
peahdf3efa82015-11-28 12:35:15 -0800411 return AudioProcessing::kNullPointerError;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000412 }
413 if (std == NULL) {
peahdf3efa82015-11-28 12:35:15 -0800414 return AudioProcessing::kNullPointerError;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000415 }
416
peahb624d8c2016-03-05 03:01:14 -0800417 if (!enabled_ || !delay_logging_enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800418 return AudioProcessing::kNotEnabledError;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000419 }
420
peahb624d8c2016-03-05 03:01:14 -0800421 Handle* my_handle = cancellers_[0]->state();
peahc12be392015-11-09 23:53:50 -0800422 const int err =
423 WebRtcAec_GetDelayMetrics(my_handle, median, std, fraction_poor_delays);
peahdf3efa82015-11-28 12:35:15 -0800424 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800425 return MapError(err);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000426 }
427
peahdf3efa82015-11-28 12:35:15 -0800428 return AudioProcessing::kNoError;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000429}
430
bjornv@webrtc.org91d11b32013-03-05 16:53:09 +0000431struct AecCore* EchoCancellationImpl::aec_core() const {
peahdf3efa82015-11-28 12:35:15 -0800432 rtc::CritScope cs(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800433 if (!enabled_) {
bjornv@webrtc.org91d11b32013-03-05 16:53:09 +0000434 return NULL;
435 }
peahb624d8c2016-03-05 03:01:14 -0800436 Handle* my_handle = cancellers_[0]->state();
bjornv@webrtc.org91d11b32013-03-05 16:53:09 +0000437 return WebRtcAec_aec_core(my_handle);
438}
439
peahb624d8c2016-03-05 03:01:14 -0800440void EchoCancellationImpl::Initialize() {
441 rtc::CritScope cs_render(crit_render_);
442 rtc::CritScope cs_capture(crit_capture_);
443 if (!enabled_) {
444 return;
445 }
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));
peahdf3efa82015-11-28 12:35:15 -0800454 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000455 }
456
peahb624d8c2016-03-05 03:01:14 -0800457 for (size_t i = 0; i < cancellers_.size(); ++i) {
458 cancellers_[i]->Initialize(sample_rate_hz);
459 }
solenberg92586f02016-03-04 12:29:03 -0800460
peahb624d8c2016-03-05 03:01:14 -0800461 Configure();
462
463 AllocateRenderQueue();
niklase@google.com470e71d2011-07-07 08:21:25 +0000464}
465
peah20028c42016-03-04 11:50:54 -0800466int EchoCancellationImpl::GetSystemDelayInSamples() const {
467 rtc::CritScope cs(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800468 RTC_DCHECK(enabled_);
peah20028c42016-03-04 11:50:54 -0800469 // Report the delay for the first AEC component.
470 return WebRtcAec_system_delay(
peahb624d8c2016-03-05 03:01:14 -0800471 WebRtcAec_aec_core(cancellers_[0]->state()));
peah20028c42016-03-04 11:50:54 -0800472}
473
peahfa6228e2015-11-16 16:27:42 -0800474void EchoCancellationImpl::AllocateRenderQueue() {
peahfa6228e2015-11-16 16:27:42 -0800475 const size_t new_render_queue_element_max_size = std::max<size_t>(
peah2446e5a2015-11-18 06:11:13 -0800476 static_cast<size_t>(1),
477 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required());
peahfa6228e2015-11-16 16:27:42 -0800478
peahdf3efa82015-11-28 12:35:15 -0800479 rtc::CritScope cs_render(crit_render_);
480 rtc::CritScope cs_capture(crit_capture_);
481
peahfa6228e2015-11-16 16:27:42 -0800482 // Reallocate the queue if the queue item size is too small to fit the
483 // data to put in the queue.
peah2446e5a2015-11-18 06:11:13 -0800484 if (render_queue_element_max_size_ < new_render_queue_element_max_size) {
peahfa6228e2015-11-16 16:27:42 -0800485 render_queue_element_max_size_ = new_render_queue_element_max_size;
486
487 std::vector<float> template_queue_element(render_queue_element_max_size_);
488
489 render_signal_queue_.reset(
490 new SwapQueue<std::vector<float>, RenderQueueItemVerifier<float>>(
491 kMaxNumFramesToBuffer, template_queue_element,
492 RenderQueueItemVerifier<float>(render_queue_element_max_size_)));
peah2446e5a2015-11-18 06:11:13 -0800493
494 render_queue_buffer_.resize(render_queue_element_max_size_);
495 capture_queue_buffer_.resize(render_queue_element_max_size_);
peahfa6228e2015-11-16 16:27:42 -0800496 } else {
497 render_signal_queue_->Clear();
498 }
peahfa6228e2015-11-16 16:27:42 -0800499}
500
andrew@webrtc.org1760a172013-09-25 23:17:38 +0000501void EchoCancellationImpl::SetExtraOptions(const Config& config) {
peahdf3efa82015-11-28 12:35:15 -0800502 {
503 rtc::CritScope cs(crit_capture_);
504 extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled;
505 delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled;
peaha332e2d2016-02-17 01:11:16 -0800506 next_generation_aec_enabled_ = config.Get<NextGenerationAec>().enabled;
peahdf3efa82015-11-28 12:35:15 -0800507 }
andrew@webrtc.org1760a172013-09-25 23:17:38 +0000508 Configure();
509}
510
peahb624d8c2016-03-05 03:01:14 -0800511int EchoCancellationImpl::Configure() {
peahdf3efa82015-11-28 12:35:15 -0800512 rtc::CritScope cs_render(crit_render_);
513 rtc::CritScope cs_capture(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000514 AecConfig config;
515 config.metricsMode = metrics_enabled_;
516 config.nlpMode = MapSetting(suppression_level_);
517 config.skewMode = drift_compensation_enabled_;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000518 config.delay_logging = delay_logging_enabled_;
peahb624d8c2016-03-05 03:01:14 -0800519
520 int error = AudioProcessing::kNoError;
521 for (size_t i = 0; i < cancellers_.size(); i++) {
522 Handle* my_handle = cancellers_[i]->state();
523 WebRtcAec_enable_extended_filter(WebRtcAec_aec_core(my_handle),
524 extended_filter_enabled_ ? 1 : 0);
525 WebRtcAec_enable_delay_agnostic(WebRtcAec_aec_core(my_handle),
526 delay_agnostic_enabled_ ? 1 : 0);
527 WebRtcAec_enable_next_generation_aec(WebRtcAec_aec_core(my_handle),
528 next_generation_aec_enabled_ ? 1 : 0);
529 const int handle_error = WebRtcAec_set_config(my_handle, config);
530 if (handle_error != AudioProcessing::kNoError) {
531 error = AudioProcessing::kNoError;
532 }
533 }
534 return error;
niklase@google.com470e71d2011-07-07 08:21:25 +0000535}
536
Peter Kasting69558702016-01-12 16:26:35 -0800537size_t EchoCancellationImpl::num_handles_required() const {
peahdf3efa82015-11-28 12:35:15 -0800538 // Not locked as it only relies on APM public API which is threadsafe.
pkasting25702cb2016-01-08 13:50:27 -0800539 return apm_->num_output_channels() * apm_->num_reverse_channels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000540}
541
niklase@google.com470e71d2011-07-07 08:21:25 +0000542} // namespace webrtc