1 /*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
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
11 #include "echo_cancellation_impl.h"
12
13 #include <cassert>
14 #include <string.h>
15
16 #include "critical_section_wrapper.h"
17 #include "echo_cancellation.h"
18
19 #include "audio_processing_impl.h"
20 #include "audio_buffer.h"
21
22 namespace webrtc {
23
24 typedef void Handle;
25
26 namespace {
MapSetting(EchoCancellation::SuppressionLevel level)27 WebRtc_Word16 MapSetting(EchoCancellation::SuppressionLevel level) {
28 switch (level) {
29 case EchoCancellation::kLowSuppression:
30 return kAecNlpConservative;
31 case EchoCancellation::kModerateSuppression:
32 return kAecNlpModerate;
33 case EchoCancellation::kHighSuppression:
34 return kAecNlpAggressive;
35 default:
36 return -1;
37 }
38 }
39
MapError(int err)40 int MapError(int err) {
41 switch (err) {
42 case AEC_UNSUPPORTED_FUNCTION_ERROR:
43 return AudioProcessing::kUnsupportedFunctionError;
44 break;
45 case AEC_BAD_PARAMETER_ERROR:
46 return AudioProcessing::kBadParameterError;
47 break;
48 case AEC_BAD_PARAMETER_WARNING:
49 return AudioProcessing::kBadStreamParameterWarning;
50 break;
51 default:
52 // AEC_UNSPECIFIED_ERROR
53 // AEC_UNINITIALIZED_ERROR
54 // AEC_NULL_POINTER_ERROR
55 return AudioProcessing::kUnspecifiedError;
56 }
57 }
58 } // namespace
59
EchoCancellationImpl(const AudioProcessingImpl * apm)60 EchoCancellationImpl::EchoCancellationImpl(const AudioProcessingImpl* apm)
61 : ProcessingComponent(apm),
62 apm_(apm),
63 drift_compensation_enabled_(false),
64 metrics_enabled_(false),
65 suppression_level_(kModerateSuppression),
66 device_sample_rate_hz_(48000),
67 stream_drift_samples_(0),
68 was_stream_drift_set_(false),
69 stream_has_echo_(false),
70 delay_logging_enabled_(false) {}
71
~EchoCancellationImpl()72 EchoCancellationImpl::~EchoCancellationImpl() {}
73
ProcessRenderAudio(const AudioBuffer * audio)74 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
75 if (!is_component_enabled()) {
76 return apm_->kNoError;
77 }
78
79 assert(audio->samples_per_split_channel() <= 160);
80 assert(audio->num_channels() == apm_->num_reverse_channels());
81
82 int err = apm_->kNoError;
83
84 // The ordering convention must be followed to pass to the correct AEC.
85 size_t handle_index = 0;
86 for (int i = 0; i < apm_->num_output_channels(); i++) {
87 for (int j = 0; j < audio->num_channels(); j++) {
88 Handle* my_handle = static_cast<Handle*>(handle(handle_index));
89 err = WebRtcAec_BufferFarend(
90 my_handle,
91 audio->low_pass_split_data(j),
92 static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
93
94 if (err != apm_->kNoError) {
95 return GetHandleError(my_handle); // TODO(ajm): warning possible?
96 }
97
98 handle_index++;
99 }
100 }
101
102 return apm_->kNoError;
103 }
104
ProcessCaptureAudio(AudioBuffer * audio)105 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) {
106 if (!is_component_enabled()) {
107 return apm_->kNoError;
108 }
109
110 if (!apm_->was_stream_delay_set()) {
111 return apm_->kStreamParameterNotSetError;
112 }
113
114 if (drift_compensation_enabled_ && !was_stream_drift_set_) {
115 return apm_->kStreamParameterNotSetError;
116 }
117
118 assert(audio->samples_per_split_channel() <= 160);
119 assert(audio->num_channels() == apm_->num_output_channels());
120
121 int err = apm_->kNoError;
122
123 // The ordering convention must be followed to pass to the correct AEC.
124 size_t handle_index = 0;
125 stream_has_echo_ = false;
126 for (int i = 0; i < audio->num_channels(); i++) {
127 for (int j = 0; j < apm_->num_reverse_channels(); j++) {
128 Handle* my_handle = handle(handle_index);
129 err = WebRtcAec_Process(
130 my_handle,
131 audio->low_pass_split_data(i),
132 audio->high_pass_split_data(i),
133 audio->low_pass_split_data(i),
134 audio->high_pass_split_data(i),
135 static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
136 apm_->stream_delay_ms(),
137 stream_drift_samples_);
138
139 if (err != apm_->kNoError) {
140 err = GetHandleError(my_handle);
141 // TODO(ajm): Figure out how to return warnings properly.
142 if (err != apm_->kBadStreamParameterWarning) {
143 return err;
144 }
145 }
146
147 WebRtc_Word16 status = 0;
148 err = WebRtcAec_get_echo_status(my_handle, &status);
149 if (err != apm_->kNoError) {
150 return GetHandleError(my_handle);
151 }
152
153 if (status == 1) {
154 stream_has_echo_ = true;
155 }
156
157 handle_index++;
158 }
159 }
160
161 was_stream_drift_set_ = false;
162 return apm_->kNoError;
163 }
164
Enable(bool enable)165 int EchoCancellationImpl::Enable(bool enable) {
166 CriticalSectionScoped crit_scoped(*apm_->crit());
167 // Ensure AEC and AECM are not both enabled.
168 if (enable && apm_->echo_control_mobile()->is_enabled()) {
169 return apm_->kBadParameterError;
170 }
171
172 return EnableComponent(enable);
173 }
174
is_enabled() const175 bool EchoCancellationImpl::is_enabled() const {
176 return is_component_enabled();
177 }
178
set_suppression_level(SuppressionLevel level)179 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) {
180 CriticalSectionScoped crit_scoped(*apm_->crit());
181 if (MapSetting(level) == -1) {
182 return apm_->kBadParameterError;
183 }
184
185 suppression_level_ = level;
186 return Configure();
187 }
188
suppression_level() const189 EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level()
190 const {
191 return suppression_level_;
192 }
193
enable_drift_compensation(bool enable)194 int EchoCancellationImpl::enable_drift_compensation(bool enable) {
195 CriticalSectionScoped crit_scoped(*apm_->crit());
196 drift_compensation_enabled_ = enable;
197 return Configure();
198 }
199
is_drift_compensation_enabled() const200 bool EchoCancellationImpl::is_drift_compensation_enabled() const {
201 return drift_compensation_enabled_;
202 }
203
set_device_sample_rate_hz(int rate)204 int EchoCancellationImpl::set_device_sample_rate_hz(int rate) {
205 CriticalSectionScoped crit_scoped(*apm_->crit());
206 if (rate < 8000 || rate > 96000) {
207 return apm_->kBadParameterError;
208 }
209
210 device_sample_rate_hz_ = rate;
211 return Initialize();
212 }
213
device_sample_rate_hz() const214 int EchoCancellationImpl::device_sample_rate_hz() const {
215 return device_sample_rate_hz_;
216 }
217
set_stream_drift_samples(int drift)218 int EchoCancellationImpl::set_stream_drift_samples(int drift) {
219 was_stream_drift_set_ = true;
220 stream_drift_samples_ = drift;
221 return apm_->kNoError;
222 }
223
stream_drift_samples() const224 int EchoCancellationImpl::stream_drift_samples() const {
225 return stream_drift_samples_;
226 }
227
enable_metrics(bool enable)228 int EchoCancellationImpl::enable_metrics(bool enable) {
229 CriticalSectionScoped crit_scoped(*apm_->crit());
230 metrics_enabled_ = enable;
231 return Configure();
232 }
233
are_metrics_enabled() const234 bool EchoCancellationImpl::are_metrics_enabled() const {
235 return metrics_enabled_;
236 }
237
238 // TODO(ajm): we currently just use the metrics from the first AEC. Think more
239 // aboue the best way to extend this to multi-channel.
GetMetrics(Metrics * metrics)240 int EchoCancellationImpl::GetMetrics(Metrics* metrics) {
241 CriticalSectionScoped crit_scoped(*apm_->crit());
242 if (metrics == NULL) {
243 return apm_->kNullPointerError;
244 }
245
246 if (!is_component_enabled() || !metrics_enabled_) {
247 return apm_->kNotEnabledError;
248 }
249
250 AecMetrics my_metrics;
251 memset(&my_metrics, 0, sizeof(my_metrics));
252 memset(metrics, 0, sizeof(Metrics));
253
254 Handle* my_handle = static_cast<Handle*>(handle(0));
255 int err = WebRtcAec_GetMetrics(my_handle, &my_metrics);
256 if (err != apm_->kNoError) {
257 return GetHandleError(my_handle);
258 }
259
260 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant;
261 metrics->residual_echo_return_loss.average = my_metrics.rerl.average;
262 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max;
263 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min;
264
265 metrics->echo_return_loss.instant = my_metrics.erl.instant;
266 metrics->echo_return_loss.average = my_metrics.erl.average;
267 metrics->echo_return_loss.maximum = my_metrics.erl.max;
268 metrics->echo_return_loss.minimum = my_metrics.erl.min;
269
270 metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant;
271 metrics->echo_return_loss_enhancement.average = my_metrics.erle.average;
272 metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max;
273 metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min;
274
275 metrics->a_nlp.instant = my_metrics.aNlp.instant;
276 metrics->a_nlp.average = my_metrics.aNlp.average;
277 metrics->a_nlp.maximum = my_metrics.aNlp.max;
278 metrics->a_nlp.minimum = my_metrics.aNlp.min;
279
280 return apm_->kNoError;
281 }
282
stream_has_echo() const283 bool EchoCancellationImpl::stream_has_echo() const {
284 return stream_has_echo_;
285 }
286
enable_delay_logging(bool enable)287 int EchoCancellationImpl::enable_delay_logging(bool enable) {
288 CriticalSectionScoped crit_scoped(*apm_->crit());
289 delay_logging_enabled_ = enable;
290 return Configure();
291 }
292
is_delay_logging_enabled() const293 bool EchoCancellationImpl::is_delay_logging_enabled() const {
294 return delay_logging_enabled_;
295 }
296
297 // TODO(bjornv): How should we handle the multi-channel case?
GetDelayMetrics(int * median,int * std)298 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) {
299 CriticalSectionScoped crit_scoped(*apm_->crit());
300 if (median == NULL) {
301 return apm_->kNullPointerError;
302 }
303 if (std == NULL) {
304 return apm_->kNullPointerError;
305 }
306
307 if (!is_component_enabled() || !delay_logging_enabled_) {
308 return apm_->kNotEnabledError;
309 }
310
311 Handle* my_handle = static_cast<Handle*>(handle(0));
312 if (WebRtcAec_GetDelayMetrics(my_handle, median, std) !=
313 apm_->kNoError) {
314 return GetHandleError(my_handle);
315 }
316
317 return apm_->kNoError;
318 }
319
Initialize()320 int EchoCancellationImpl::Initialize() {
321 int err = ProcessingComponent::Initialize();
322 if (err != apm_->kNoError || !is_component_enabled()) {
323 return err;
324 }
325
326 was_stream_drift_set_ = false;
327
328 return apm_->kNoError;
329 }
330
get_version(char * version,int version_len_bytes) const331 int EchoCancellationImpl::get_version(char* version,
332 int version_len_bytes) const {
333 if (WebRtcAec_get_version(version, version_len_bytes) != 0) {
334 return apm_->kBadParameterError;
335 }
336
337 return apm_->kNoError;
338 }
339
CreateHandle() const340 void* EchoCancellationImpl::CreateHandle() const {
341 Handle* handle = NULL;
342 if (WebRtcAec_Create(&handle) != apm_->kNoError) {
343 handle = NULL;
344 } else {
345 assert(handle != NULL);
346 }
347
348 return handle;
349 }
350
DestroyHandle(void * handle) const351 int EchoCancellationImpl::DestroyHandle(void* handle) const {
352 assert(handle != NULL);
353 return WebRtcAec_Free(static_cast<Handle*>(handle));
354 }
355
InitializeHandle(void * handle) const356 int EchoCancellationImpl::InitializeHandle(void* handle) const {
357 assert(handle != NULL);
358 return WebRtcAec_Init(static_cast<Handle*>(handle),
359 apm_->sample_rate_hz(),
360 device_sample_rate_hz_);
361 }
362
ConfigureHandle(void * handle) const363 int EchoCancellationImpl::ConfigureHandle(void* handle) const {
364 assert(handle != NULL);
365 AecConfig config;
366 config.metricsMode = metrics_enabled_;
367 config.nlpMode = MapSetting(suppression_level_);
368 config.skewMode = drift_compensation_enabled_;
369 config.delay_logging = delay_logging_enabled_;
370
371 return WebRtcAec_set_config(static_cast<Handle*>(handle), config);
372 }
373
num_handles_required() const374 int EchoCancellationImpl::num_handles_required() const {
375 return apm_->num_output_channels() *
376 apm_->num_reverse_channels();
377 }
378
GetHandleError(void * handle) const379 int EchoCancellationImpl::GetHandleError(void* handle) const {
380 assert(handle != NULL);
381 return MapError(WebRtcAec_get_error_code(static_cast<Handle*>(handle)));
382 }
383 } // namespace webrtc
384