blob: 44a5a0c7730b80a3744a6ee64bbec3174829528f [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
niklase@google.com470e71d2011-07-07 08:21:25 +000022namespace {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000023int16_t MapSetting(EchoCancellation::SuppressionLevel level) {
niklase@google.com470e71d2011-07-07 08:21:25 +000024 switch (level) {
25 case EchoCancellation::kLowSuppression:
26 return kAecNlpConservative;
27 case EchoCancellation::kModerateSuppression:
28 return kAecNlpModerate;
29 case EchoCancellation::kHighSuppression:
30 return kAecNlpAggressive;
niklase@google.com470e71d2011-07-07 08:21:25 +000031 }
andrew@webrtc.org648af742012-02-08 01:57:29 +000032 assert(false);
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000033 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000034}
35
andrew@webrtc.org648af742012-02-08 01:57:29 +000036AudioProcessing::Error MapError(int err) {
niklase@google.com470e71d2011-07-07 08:21:25 +000037 switch (err) {
38 case AEC_UNSUPPORTED_FUNCTION_ERROR:
39 return AudioProcessing::kUnsupportedFunctionError;
niklase@google.com470e71d2011-07-07 08:21:25 +000040 case AEC_BAD_PARAMETER_ERROR:
41 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +000042 case AEC_BAD_PARAMETER_WARNING:
43 return AudioProcessing::kBadStreamParameterWarning;
niklase@google.com470e71d2011-07-07 08:21:25 +000044 default:
45 // AEC_UNSPECIFIED_ERROR
46 // AEC_UNINITIALIZED_ERROR
47 // AEC_NULL_POINTER_ERROR
48 return AudioProcessing::kUnspecifiedError;
49 }
50}
niklase@google.com470e71d2011-07-07 08:21:25 +000051
peah2446e5a2015-11-18 06:11:13 -080052// Maximum length that a frame of samples can have.
53static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160;
54// Maximum number of frames to buffer in the render queue.
55// TODO(peah): Decrease this once we properly handle hugely unbalanced
56// reverse and forward call numbers.
57static const size_t kMaxNumFramesToBuffer = 100;
58} // namespace
peahfa6228e2015-11-16 16:27:42 -080059
peahb624d8c2016-03-05 03:01:14 -080060class EchoCancellationImpl::Canceller {
61 public:
peah4510bbd2016-03-07 22:50:14 -080062 Canceller() {
peahb624d8c2016-03-05 03:01:14 -080063 state_ = WebRtcAec_Create();
64 RTC_DCHECK(state_);
65 }
66
67 ~Canceller() {
68 RTC_CHECK(state_);
69 WebRtcAec_Free(state_);
70 }
71
peah4510bbd2016-03-07 22:50:14 -080072 void* state() { return state_; }
peahb624d8c2016-03-05 03:01:14 -080073
74 void Initialize(int sample_rate_hz) {
75 // TODO(ajm): Drift compensation is disabled in practice. If restored, it
76 // should be managed internally and not depend on the hardware sample rate.
77 // For now, just hardcode a 48 kHz value.
78 const int error = WebRtcAec_Init(state_, sample_rate_hz, 48000);
79 RTC_DCHECK_EQ(0, error);
80 }
81
82 private:
peah4510bbd2016-03-07 22:50:14 -080083 void* state_;
peahb624d8c2016-03-05 03:01:14 -080084};
85
andrew@webrtc.org56e4a052014-02-27 22:23:17 +000086EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm,
peahdf3efa82015-11-28 12:35:15 -080087 rtc::CriticalSection* crit_render,
88 rtc::CriticalSection* crit_capture)
peahb624d8c2016-03-05 03:01:14 -080089 : apm_(apm),
peahdf3efa82015-11-28 12:35:15 -080090 crit_render_(crit_render),
91 crit_capture_(crit_capture),
Henrik Lundin441f6342015-06-09 16:03:13 +020092 drift_compensation_enabled_(false),
93 metrics_enabled_(false),
94 suppression_level_(kModerateSuppression),
95 stream_drift_samples_(0),
96 was_stream_drift_set_(false),
97 stream_has_echo_(false),
98 delay_logging_enabled_(false),
99 extended_filter_enabled_(false),
peahfa6228e2015-11-16 16:27:42 -0800100 delay_agnostic_enabled_(false),
peah6ebc4d32016-03-07 16:59:39 -0800101 aec3_enabled_(false),
peahdf3efa82015-11-28 12:35:15 -0800102 render_queue_element_max_size_(0) {
103 RTC_DCHECK(apm);
104 RTC_DCHECK(crit_render);
105 RTC_DCHECK(crit_capture);
106}
niklase@google.com470e71d2011-07-07 08:21:25 +0000107
108EchoCancellationImpl::~EchoCancellationImpl() {}
109
110int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800111 rtc::CritScope cs_render(crit_render_);
peahb624d8c2016-03-05 03:01:14 -0800112 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800113 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000114 }
115
peahb624d8c2016-03-05 03:01:14 -0800116 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
117 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_reverse_channels());
118 RTC_DCHECK_GE(cancellers_.size(),
119 apm_->num_output_channels() * audio->num_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000120
peahdf3efa82015-11-28 12:35:15 -0800121 int err = AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000122
123 // The ordering convention must be followed to pass to the correct AEC.
124 size_t handle_index = 0;
peahfa6228e2015-11-16 16:27:42 -0800125 render_queue_buffer_.clear();
Peter Kasting69558702016-01-12 16:26:35 -0800126 for (size_t i = 0; i < apm_->num_output_channels(); i++) {
127 for (size_t j = 0; j < audio->num_channels(); j++) {
peahfa6228e2015-11-16 16:27:42 -0800128 // Retrieve any error code produced by the buffering of the farend
peahb624d8c2016-03-05 03:01:14 -0800129 // signal.
peahfa6228e2015-11-16 16:27:42 -0800130 err = WebRtcAec_GetBufferFarendError(
peah4510bbd2016-03-07 22:50:14 -0800131 cancellers_[handle_index++]->state(),
132 audio->split_bands_const_f(j)[kBand0To8kHz],
Peter Kastingdce40cf2015-08-24 14:52:23 -0700133 audio->num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000134
peahdf3efa82015-11-28 12:35:15 -0800135 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800136 return MapError(err); // TODO(ajm): warning possible?
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 }
138
peahfa6228e2015-11-16 16:27:42 -0800139 // Buffer the samples in the render queue.
140 render_queue_buffer_.insert(render_queue_buffer_.end(),
141 audio->split_bands_const_f(j)[kBand0To8kHz],
142 (audio->split_bands_const_f(j)[kBand0To8kHz] +
143 audio->num_frames_per_band()));
niklase@google.com470e71d2011-07-07 08:21:25 +0000144 }
145 }
146
peahfa6228e2015-11-16 16:27:42 -0800147 // Insert the samples into the queue.
148 if (!render_signal_queue_->Insert(&render_queue_buffer_)) {
peahdf3efa82015-11-28 12:35:15 -0800149 // The data queue is full and needs to be emptied.
peahfa6228e2015-11-16 16:27:42 -0800150 ReadQueuedRenderData();
151
152 // Retry the insert (should always work).
153 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true);
154 }
155
peahdf3efa82015-11-28 12:35:15 -0800156 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000157}
158
peahfa6228e2015-11-16 16:27:42 -0800159// 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.
161void EchoCancellationImpl::ReadQueuedRenderData() {
peahdf3efa82015-11-28 12:35:15 -0800162 rtc::CritScope cs_capture(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800163 if (!enabled_) {
peahfa6228e2015-11-16 16:27:42 -0800164 return;
165 }
166
167 while (render_signal_queue_->Remove(&capture_queue_buffer_)) {
168 size_t handle_index = 0;
pkasting25702cb2016-01-08 13:50:27 -0800169 size_t buffer_index = 0;
170 const size_t num_frames_per_band =
peahfa6228e2015-11-16 16:27:42 -0800171 capture_queue_buffer_.size() /
172 (apm_->num_output_channels() * apm_->num_reverse_channels());
Peter Kasting69558702016-01-12 16:26:35 -0800173 for (size_t i = 0; i < apm_->num_output_channels(); i++) {
174 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) {
peah4510bbd2016-03-07 22:50:14 -0800175 WebRtcAec_BufferFarend(cancellers_[handle_index++]->state(),
176 &capture_queue_buffer_[buffer_index],
peahfa6228e2015-11-16 16:27:42 -0800177 num_frames_per_band);
178
179 buffer_index += num_frames_per_band;
peahfa6228e2015-11-16 16:27:42 -0800180 }
181 }
182 }
183}
184
niklase@google.com470e71d2011-07-07 08:21:25 +0000185int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) {
peahdf3efa82015-11-28 12:35:15 -0800186 rtc::CritScope cs_capture(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800187 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800188 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000189 }
190
191 if (!apm_->was_stream_delay_set()) {
peahdf3efa82015-11-28 12:35:15 -0800192 return AudioProcessing::kStreamParameterNotSetError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 }
194
195 if (drift_compensation_enabled_ && !was_stream_drift_set_) {
peahdf3efa82015-11-28 12:35:15 -0800196 return AudioProcessing::kStreamParameterNotSetError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 }
198
peahb624d8c2016-03-05 03:01:14 -0800199 RTC_DCHECK_GE(160u, audio->num_frames_per_band());
200 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_proc_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000201
peahdf3efa82015-11-28 12:35:15 -0800202 int err = AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000203
204 // The ordering convention must be followed to pass to the correct AEC.
205 size_t handle_index = 0;
206 stream_has_echo_ = false;
Peter Kasting69558702016-01-12 16:26:35 -0800207 for (size_t i = 0; i < audio->num_channels(); i++) {
208 for (size_t j = 0; j < apm_->num_reverse_channels(); j++) {
peah4510bbd2016-03-07 22:50:14 -0800209 err = WebRtcAec_Process(cancellers_[handle_index]->state(),
210 audio->split_bands_const_f(i), audio->num_bands(),
211 audio->split_bands_f(i),
peahdf3efa82015-11-28 12:35:15 -0800212 audio->num_frames_per_band(),
213 apm_->stream_delay_ms(), stream_drift_samples_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000214
peahdf3efa82015-11-28 12:35:15 -0800215 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800216 err = MapError(err);
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 // TODO(ajm): Figure out how to return warnings properly.
peahdf3efa82015-11-28 12:35:15 -0800218 if (err != AudioProcessing::kBadStreamParameterWarning) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000219 return err;
220 }
221 }
222
bjornv@webrtc.org21a2fc92013-02-15 17:01:03 +0000223 int status = 0;
peah4510bbd2016-03-07 22:50:14 -0800224 err = WebRtcAec_get_echo_status(cancellers_[handle_index]->state(),
225 &status);
peahdf3efa82015-11-28 12:35:15 -0800226 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800227 return MapError(err);
niklase@google.com470e71d2011-07-07 08:21:25 +0000228 }
229
230 if (status == 1) {
231 stream_has_echo_ = true;
232 }
peah4510bbd2016-03-07 22:50:14 -0800233
234 handle_index++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000235 }
236 }
237
238 was_stream_drift_set_ = false;
peahdf3efa82015-11-28 12:35:15 -0800239 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000240}
241
242int EchoCancellationImpl::Enable(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800243 // Run in a single-threaded manner.
244 rtc::CritScope cs_render(crit_render_);
245 rtc::CritScope cs_capture(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000246 // Ensure AEC and AECM are not both enabled.
peahdf3efa82015-11-28 12:35:15 -0800247 // The is_enabled call is safe from a deadlock perspective
248 // as both locks are already held in the correct order.
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 if (enable && apm_->echo_control_mobile()->is_enabled()) {
peahdf3efa82015-11-28 12:35:15 -0800250 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 }
252
peahb624d8c2016-03-05 03:01:14 -0800253 if (enable && !enabled_) {
254 enabled_ = enable; // Must be set before Initialize() is called.
255 Initialize();
256 } else {
257 enabled_ = enable;
258 }
259 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000260}
261
262bool EchoCancellationImpl::is_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800263 rtc::CritScope cs(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800264 return enabled_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000265}
266
267int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) {
peahdf3efa82015-11-28 12:35:15 -0800268 {
269 if (MapSetting(level) == -1) {
270 return AudioProcessing::kBadParameterError;
271 }
272 rtc::CritScope cs(crit_capture_);
273 suppression_level_ = level;
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000275 return Configure();
276}
277
278EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level()
279 const {
peahdf3efa82015-11-28 12:35:15 -0800280 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 return suppression_level_;
282}
283
284int EchoCancellationImpl::enable_drift_compensation(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800285 {
286 rtc::CritScope cs(crit_capture_);
287 drift_compensation_enabled_ = enable;
288 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000289 return Configure();
290}
291
292bool EchoCancellationImpl::is_drift_compensation_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800293 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000294 return drift_compensation_enabled_;
295}
296
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000297void EchoCancellationImpl::set_stream_drift_samples(int drift) {
peahdf3efa82015-11-28 12:35:15 -0800298 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000299 was_stream_drift_set_ = true;
300 stream_drift_samples_ = drift;
niklase@google.com470e71d2011-07-07 08:21:25 +0000301}
302
303int EchoCancellationImpl::stream_drift_samples() const {
peahdf3efa82015-11-28 12:35:15 -0800304 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000305 return stream_drift_samples_;
306}
307
308int EchoCancellationImpl::enable_metrics(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800309 {
310 rtc::CritScope cs(crit_capture_);
311 metrics_enabled_ = enable;
312 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000313 return Configure();
314}
315
316bool EchoCancellationImpl::are_metrics_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800317 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000318 return metrics_enabled_;
319}
320
321// TODO(ajm): we currently just use the metrics from the first AEC. Think more
322// aboue the best way to extend this to multi-channel.
323int EchoCancellationImpl::GetMetrics(Metrics* metrics) {
peahdf3efa82015-11-28 12:35:15 -0800324 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000325 if (metrics == NULL) {
peahdf3efa82015-11-28 12:35:15 -0800326 return AudioProcessing::kNullPointerError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000327 }
328
peahb624d8c2016-03-05 03:01:14 -0800329 if (!enabled_ || !metrics_enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800330 return AudioProcessing::kNotEnabledError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000331 }
332
333 AecMetrics my_metrics;
334 memset(&my_metrics, 0, sizeof(my_metrics));
335 memset(metrics, 0, sizeof(Metrics));
336
peah4510bbd2016-03-07 22:50:14 -0800337 const int err = WebRtcAec_GetMetrics(cancellers_[0]->state(), &my_metrics);
peahdf3efa82015-11-28 12:35:15 -0800338 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800339 return MapError(err);
niklase@google.com470e71d2011-07-07 08:21:25 +0000340 }
341
342 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant;
343 metrics->residual_echo_return_loss.average = my_metrics.rerl.average;
344 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max;
345 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min;
346
347 metrics->echo_return_loss.instant = my_metrics.erl.instant;
348 metrics->echo_return_loss.average = my_metrics.erl.average;
349 metrics->echo_return_loss.maximum = my_metrics.erl.max;
350 metrics->echo_return_loss.minimum = my_metrics.erl.min;
351
352 metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant;
353 metrics->echo_return_loss_enhancement.average = my_metrics.erle.average;
354 metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max;
355 metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min;
356
357 metrics->a_nlp.instant = my_metrics.aNlp.instant;
358 metrics->a_nlp.average = my_metrics.aNlp.average;
359 metrics->a_nlp.maximum = my_metrics.aNlp.max;
360 metrics->a_nlp.minimum = my_metrics.aNlp.min;
361
peahdf3efa82015-11-28 12:35:15 -0800362 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000363}
364
365bool EchoCancellationImpl::stream_has_echo() const {
peahdf3efa82015-11-28 12:35:15 -0800366 rtc::CritScope cs(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 return stream_has_echo_;
368}
369
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000370int EchoCancellationImpl::enable_delay_logging(bool enable) {
peahdf3efa82015-11-28 12:35:15 -0800371 {
372 rtc::CritScope cs(crit_capture_);
373 delay_logging_enabled_ = enable;
374 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000375 return Configure();
376}
377
378bool EchoCancellationImpl::is_delay_logging_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800379 rtc::CritScope cs(crit_capture_);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000380 return delay_logging_enabled_;
381}
382
Minyue13b96ba2015-10-03 00:39:14 +0200383bool EchoCancellationImpl::is_delay_agnostic_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800384 rtc::CritScope cs(crit_capture_);
Minyue13b96ba2015-10-03 00:39:14 +0200385 return delay_agnostic_enabled_;
386}
387
peah6ebc4d32016-03-07 16:59:39 -0800388bool EchoCancellationImpl::is_aec3_enabled() const {
peaha332e2d2016-02-17 01:11:16 -0800389 rtc::CritScope cs(crit_capture_);
peah6ebc4d32016-03-07 16:59:39 -0800390 return aec3_enabled_;
peaha332e2d2016-02-17 01:11:16 -0800391}
392
Minyue13b96ba2015-10-03 00:39:14 +0200393bool EchoCancellationImpl::is_extended_filter_enabled() const {
peahdf3efa82015-11-28 12:35:15 -0800394 rtc::CritScope cs(crit_capture_);
Minyue13b96ba2015-10-03 00:39:14 +0200395 return extended_filter_enabled_;
396}
397
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000398// TODO(bjornv): How should we handle the multi-channel case?
399int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) {
peahdf3efa82015-11-28 12:35:15 -0800400 rtc::CritScope cs(crit_capture_);
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +0000401 float fraction_poor_delays = 0;
402 return GetDelayMetrics(median, std, &fraction_poor_delays);
403}
404
405int EchoCancellationImpl::GetDelayMetrics(int* median, int* std,
406 float* fraction_poor_delays) {
peahdf3efa82015-11-28 12:35:15 -0800407 rtc::CritScope cs(crit_capture_);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000408 if (median == NULL) {
peahdf3efa82015-11-28 12:35:15 -0800409 return AudioProcessing::kNullPointerError;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000410 }
411 if (std == NULL) {
peahdf3efa82015-11-28 12:35:15 -0800412 return AudioProcessing::kNullPointerError;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000413 }
414
peahb624d8c2016-03-05 03:01:14 -0800415 if (!enabled_ || !delay_logging_enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800416 return AudioProcessing::kNotEnabledError;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000417 }
418
peah4510bbd2016-03-07 22:50:14 -0800419 const int err = WebRtcAec_GetDelayMetrics(cancellers_[0]->state(), median,
420 std, fraction_poor_delays);
peahdf3efa82015-11-28 12:35:15 -0800421 if (err != AudioProcessing::kNoError) {
peahc12be392015-11-09 23:53:50 -0800422 return MapError(err);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000423 }
424
peahdf3efa82015-11-28 12:35:15 -0800425 return AudioProcessing::kNoError;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000426}
427
bjornv@webrtc.org91d11b32013-03-05 16:53:09 +0000428struct AecCore* EchoCancellationImpl::aec_core() const {
peahdf3efa82015-11-28 12:35:15 -0800429 rtc::CritScope cs(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800430 if (!enabled_) {
bjornv@webrtc.org91d11b32013-03-05 16:53:09 +0000431 return NULL;
432 }
peah4510bbd2016-03-07 22:50:14 -0800433 return WebRtcAec_aec_core(cancellers_[0]->state());
bjornv@webrtc.org91d11b32013-03-05 16:53:09 +0000434}
435
peahb624d8c2016-03-05 03:01:14 -0800436void EchoCancellationImpl::Initialize() {
437 rtc::CritScope cs_render(crit_render_);
438 rtc::CritScope cs_capture(crit_capture_);
439 if (!enabled_) {
440 return;
441 }
peahb624d8c2016-03-05 03:01:14 -0800442
443 if (num_handles_required() > cancellers_.size()) {
444 const size_t cancellers_old_size = cancellers_.size();
445 cancellers_.resize(num_handles_required());
446
447 for (size_t i = cancellers_old_size; i < cancellers_.size(); ++i) {
peah4510bbd2016-03-07 22:50:14 -0800448 cancellers_[i].reset(new Canceller());
peahdf3efa82015-11-28 12:35:15 -0800449 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000450 }
451
peah4510bbd2016-03-07 22:50:14 -0800452 const int sample_rate_hz = apm_->proc_sample_rate_hz();
453 for (auto& canceller : cancellers_) {
454 canceller->Initialize(sample_rate_hz);
peahb624d8c2016-03-05 03:01:14 -0800455 }
solenberg92586f02016-03-04 12:29:03 -0800456
peahb624d8c2016-03-05 03:01:14 -0800457 Configure();
458
459 AllocateRenderQueue();
niklase@google.com470e71d2011-07-07 08:21:25 +0000460}
461
peah20028c42016-03-04 11:50:54 -0800462int EchoCancellationImpl::GetSystemDelayInSamples() const {
463 rtc::CritScope cs(crit_capture_);
peahb624d8c2016-03-05 03:01:14 -0800464 RTC_DCHECK(enabled_);
peah20028c42016-03-04 11:50:54 -0800465 // Report the delay for the first AEC component.
466 return WebRtcAec_system_delay(
peahb624d8c2016-03-05 03:01:14 -0800467 WebRtcAec_aec_core(cancellers_[0]->state()));
peah20028c42016-03-04 11:50:54 -0800468}
469
peahfa6228e2015-11-16 16:27:42 -0800470void EchoCancellationImpl::AllocateRenderQueue() {
peahfa6228e2015-11-16 16:27:42 -0800471 const size_t new_render_queue_element_max_size = std::max<size_t>(
peah2446e5a2015-11-18 06:11:13 -0800472 static_cast<size_t>(1),
473 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required());
peahfa6228e2015-11-16 16:27:42 -0800474
peahdf3efa82015-11-28 12:35:15 -0800475 rtc::CritScope cs_render(crit_render_);
476 rtc::CritScope cs_capture(crit_capture_);
477
peahfa6228e2015-11-16 16:27:42 -0800478 // Reallocate the queue if the queue item size is too small to fit the
479 // data to put in the queue.
peah2446e5a2015-11-18 06:11:13 -0800480 if (render_queue_element_max_size_ < new_render_queue_element_max_size) {
peahfa6228e2015-11-16 16:27:42 -0800481 render_queue_element_max_size_ = new_render_queue_element_max_size;
482
483 std::vector<float> template_queue_element(render_queue_element_max_size_);
484
485 render_signal_queue_.reset(
486 new SwapQueue<std::vector<float>, RenderQueueItemVerifier<float>>(
487 kMaxNumFramesToBuffer, template_queue_element,
488 RenderQueueItemVerifier<float>(render_queue_element_max_size_)));
peah2446e5a2015-11-18 06:11:13 -0800489
490 render_queue_buffer_.resize(render_queue_element_max_size_);
491 capture_queue_buffer_.resize(render_queue_element_max_size_);
peahfa6228e2015-11-16 16:27:42 -0800492 } else {
493 render_signal_queue_->Clear();
494 }
peahfa6228e2015-11-16 16:27:42 -0800495}
496
andrew@webrtc.org1760a172013-09-25 23:17:38 +0000497void EchoCancellationImpl::SetExtraOptions(const Config& config) {
peahdf3efa82015-11-28 12:35:15 -0800498 {
499 rtc::CritScope cs(crit_capture_);
500 extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled;
501 delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled;
peah6ebc4d32016-03-07 16:59:39 -0800502 aec3_enabled_ = config.Get<EchoCanceller3>().enabled;
peahdf3efa82015-11-28 12:35:15 -0800503 }
andrew@webrtc.org1760a172013-09-25 23:17:38 +0000504 Configure();
505}
506
peahb624d8c2016-03-05 03:01:14 -0800507int EchoCancellationImpl::Configure() {
peahdf3efa82015-11-28 12:35:15 -0800508 rtc::CritScope cs_render(crit_render_);
509 rtc::CritScope cs_capture(crit_capture_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000510 AecConfig config;
511 config.metricsMode = metrics_enabled_;
512 config.nlpMode = MapSetting(suppression_level_);
513 config.skewMode = drift_compensation_enabled_;
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000514 config.delay_logging = delay_logging_enabled_;
peahb624d8c2016-03-05 03:01:14 -0800515
516 int error = AudioProcessing::kNoError;
peah4510bbd2016-03-07 22:50:14 -0800517 for (auto& canceller : cancellers_) {
518 WebRtcAec_enable_extended_filter(WebRtcAec_aec_core(canceller->state()),
peahb624d8c2016-03-05 03:01:14 -0800519 extended_filter_enabled_ ? 1 : 0);
peah4510bbd2016-03-07 22:50:14 -0800520 WebRtcAec_enable_delay_agnostic(WebRtcAec_aec_core(canceller->state()),
peahb624d8c2016-03-05 03:01:14 -0800521 delay_agnostic_enabled_ ? 1 : 0);
peah4510bbd2016-03-07 22:50:14 -0800522 WebRtcAec_enable_aec3(WebRtcAec_aec_core(canceller->state()),
523 aec3_enabled_ ? 1 : 0);
524 const int handle_error = WebRtcAec_set_config(canceller->state(), config);
peahb624d8c2016-03-05 03:01:14 -0800525 if (handle_error != AudioProcessing::kNoError) {
526 error = AudioProcessing::kNoError;
527 }
528 }
529 return error;
niklase@google.com470e71d2011-07-07 08:21:25 +0000530}
531
Peter Kasting69558702016-01-12 16:26:35 -0800532size_t EchoCancellationImpl::num_handles_required() const {
peahdf3efa82015-11-28 12:35:15 -0800533 // Not locked as it only relies on APM public API which is threadsafe.
pkasting25702cb2016-01-08 13:50:27 -0800534 return apm_->num_output_channels() * apm_->num_reverse_channels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000535}
536
niklase@google.com470e71d2011-07-07 08:21:25 +0000537} // namespace webrtc