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
~EchoCancellationImpl()71 EchoCancellationImpl::~EchoCancellationImpl() {}
72
ProcessRenderAudio(const AudioBuffer * audio)73 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
74 if (!is_component_enabled()) {
75 return apm_->kNoError;
76 }
77
78 assert(audio->samples_per_split_channel() <= 160);
79 assert(audio->num_channels() == apm_->num_reverse_channels());
80
81 int err = apm_->kNoError;
82
83 // The ordering convention must be followed to pass to the correct AEC.
84 size_t handle_index = 0;
85 for (int i = 0; i < apm_->num_output_channels(); i++) {
86 for (int j = 0; j < audio->num_channels(); j++) {
87 Handle* my_handle = static_cast<Handle*>(handle(handle_index));
88 err = WebRtcAec_BufferFarend(
89 my_handle,
90 audio->low_pass_split_data(j),
91 static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
92
93 if (err != apm_->kNoError) {
94 return GetHandleError(my_handle); // TODO(ajm): warning possible?
95 }
96
97 handle_index++;
98 }
99 }
100
101 return apm_->kNoError;
102 }
103
ProcessCaptureAudio(AudioBuffer * audio)104 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) {
105 if (!is_component_enabled()) {
106 return apm_->kNoError;
107 }
108
109 if (!apm_->was_stream_delay_set()) {
110 return apm_->kStreamParameterNotSetError;
111 }
112
113 if (drift_compensation_enabled_ && !was_stream_drift_set_) {
114 return apm_->kStreamParameterNotSetError;
115 }
116
117 assert(audio->samples_per_split_channel() <= 160);
118 assert(audio->num_channels() == apm_->num_output_channels());
119
120 int err = apm_->kNoError;
121
122 // The ordering convention must be followed to pass to the correct AEC.
123 size_t handle_index = 0;
124 stream_has_echo_ = false;
125 for (int i = 0; i < audio->num_channels(); i++) {
126 for (int j = 0; j < apm_->num_reverse_channels(); j++) {
127 Handle* my_handle = handle(handle_index);
128 err = WebRtcAec_Process(
129 my_handle,
130 audio->low_pass_split_data(i),
131 audio->high_pass_split_data(i),
132 audio->low_pass_split_data(i),
133 audio->high_pass_split_data(i),
134 static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
135 apm_->stream_delay_ms(),
136 stream_drift_samples_);
137
138 if (err != apm_->kNoError) {
139 err = GetHandleError(my_handle);
140 // TODO(ajm): Figure out how to return warnings properly.
141 if (err != apm_->kBadStreamParameterWarning) {
142 return err;
143 }
144 }
145
146 WebRtc_Word16 status = 0;
147 err = WebRtcAec_get_echo_status(my_handle, &status);
148 if (err != apm_->kNoError) {
149 return GetHandleError(my_handle);
150 }
151
152 if (status == 1) {
153 stream_has_echo_ = true;
154 }
155
156 handle_index++;
157 }
158 }
159
160 was_stream_drift_set_ = false;
161 return apm_->kNoError;
162 }
163
Enable(bool enable)164 int EchoCancellationImpl::Enable(bool enable) {
165 CriticalSectionScoped crit_scoped(*apm_->crit());
166 // Ensure AEC and AECM are not both enabled.
167 if (enable && apm_->echo_control_mobile()->is_enabled()) {
168 return apm_->kBadParameterError;
169 }
170
171 return EnableComponent(enable);
172 }
173
is_enabled() const174 bool EchoCancellationImpl::is_enabled() const {
175 return is_component_enabled();
176 }
177
set_suppression_level(SuppressionLevel level)178 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) {
179 CriticalSectionScoped crit_scoped(*apm_->crit());
180 if (MapSetting(level) == -1) {
181 return apm_->kBadParameterError;
182 }
183
184 suppression_level_ = level;
185 return Configure();
186 }
187
suppression_level() const188 EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level()
189 const {
190 return suppression_level_;
191 }
192
enable_drift_compensation(bool enable)193 int EchoCancellationImpl::enable_drift_compensation(bool enable) {
194 CriticalSectionScoped crit_scoped(*apm_->crit());
195 drift_compensation_enabled_ = enable;
196 return Configure();
197 }
198
is_drift_compensation_enabled() const199 bool EchoCancellationImpl::is_drift_compensation_enabled() const {
200 return drift_compensation_enabled_;
201 }
202
set_device_sample_rate_hz(int rate)203 int EchoCancellationImpl::set_device_sample_rate_hz(int rate) {
204 CriticalSectionScoped crit_scoped(*apm_->crit());
205 if (rate < 8000 || rate > 96000) {
206 return apm_->kBadParameterError;
207 }
208
209 device_sample_rate_hz_ = rate;
210 return Initialize();
211 }
212
device_sample_rate_hz() const213 int EchoCancellationImpl::device_sample_rate_hz() const {
214 return device_sample_rate_hz_;
215 }
216
set_stream_drift_samples(int drift)217 int EchoCancellationImpl::set_stream_drift_samples(int drift) {
218 was_stream_drift_set_ = true;
219 stream_drift_samples_ = drift;
220 return apm_->kNoError;
221 }
222
stream_drift_samples() const223 int EchoCancellationImpl::stream_drift_samples() const {
224 return stream_drift_samples_;
225 }
226
enable_metrics(bool enable)227 int EchoCancellationImpl::enable_metrics(bool enable) {
228 CriticalSectionScoped crit_scoped(*apm_->crit());
229 metrics_enabled_ = enable;
230 return Configure();
231 }
232
are_metrics_enabled() const233 bool EchoCancellationImpl::are_metrics_enabled() const {
234 return metrics_enabled_;
235 }
236
237 // TODO(ajm): we currently just use the metrics from the first AEC. Think more
238 // aboue the best way to extend this to multi-channel.
GetMetrics(Metrics * metrics)239 int EchoCancellationImpl::GetMetrics(Metrics* metrics) {
240 CriticalSectionScoped crit_scoped(*apm_->crit());
241 if (metrics == NULL) {
242 return apm_->kNullPointerError;
243 }
244
245 if (!is_component_enabled() || !metrics_enabled_) {
246 return apm_->kNotEnabledError;
247 }
248
249 AecMetrics my_metrics;
250 memset(&my_metrics, 0, sizeof(my_metrics));
251 memset(metrics, 0, sizeof(Metrics));
252
253 Handle* my_handle = static_cast<Handle*>(handle(0));
254 int err = WebRtcAec_GetMetrics(my_handle, &my_metrics);
255 if (err != apm_->kNoError) {
256 return GetHandleError(my_handle);
257 }
258
259 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant;
260 metrics->residual_echo_return_loss.average = my_metrics.rerl.average;
261 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max;
262 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min;
263
264 metrics->echo_return_loss.instant = my_metrics.erl.instant;
265 metrics->echo_return_loss.average = my_metrics.erl.average;
266 metrics->echo_return_loss.maximum = my_metrics.erl.max;
267 metrics->echo_return_loss.minimum = my_metrics.erl.min;
268
269 metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant;
270 metrics->echo_return_loss_enhancement.average = my_metrics.erle.average;
271 metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max;
272 metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min;
273
274 metrics->a_nlp.instant = my_metrics.aNlp.instant;
275 metrics->a_nlp.average = my_metrics.aNlp.average;
276 metrics->a_nlp.maximum = my_metrics.aNlp.max;
277 metrics->a_nlp.minimum = my_metrics.aNlp.min;
278
279 return apm_->kNoError;
280 }
281
stream_has_echo() const282 bool EchoCancellationImpl::stream_has_echo() const {
283 return stream_has_echo_;
284 }
285
Initialize()286 int EchoCancellationImpl::Initialize() {
287 int err = ProcessingComponent::Initialize();
288 if (err != apm_->kNoError || !is_component_enabled()) {
289 return err;
290 }
291
292 was_stream_drift_set_ = false;
293
294 return apm_->kNoError;
295 }
296
get_version(char * version,int version_len_bytes) const297 int EchoCancellationImpl::get_version(char* version,
298 int version_len_bytes) const {
299 if (WebRtcAec_get_version(version, version_len_bytes) != 0) {
300 return apm_->kBadParameterError;
301 }
302
303 return apm_->kNoError;
304 }
305
CreateHandle() const306 void* EchoCancellationImpl::CreateHandle() const {
307 Handle* handle = NULL;
308 if (WebRtcAec_Create(&handle) != apm_->kNoError) {
309 handle = NULL;
310 } else {
311 assert(handle != NULL);
312 }
313
314 return handle;
315 }
316
DestroyHandle(void * handle) const317 int EchoCancellationImpl::DestroyHandle(void* handle) const {
318 assert(handle != NULL);
319 return WebRtcAec_Free(static_cast<Handle*>(handle));
320 }
321
InitializeHandle(void * handle) const322 int EchoCancellationImpl::InitializeHandle(void* handle) const {
323 assert(handle != NULL);
324 return WebRtcAec_Init(static_cast<Handle*>(handle),
325 apm_->sample_rate_hz(),
326 device_sample_rate_hz_);
327 }
328
ConfigureHandle(void * handle) const329 int EchoCancellationImpl::ConfigureHandle(void* handle) const {
330 assert(handle != NULL);
331 AecConfig config;
332 config.metricsMode = metrics_enabled_;
333 config.nlpMode = MapSetting(suppression_level_);
334 config.skewMode = drift_compensation_enabled_;
335
336 return WebRtcAec_set_config(static_cast<Handle*>(handle), config);
337 }
338
num_handles_required() const339 int EchoCancellationImpl::num_handles_required() const {
340 return apm_->num_output_channels() *
341 apm_->num_reverse_channels();
342 }
343
GetHandleError(void * handle) const344 int EchoCancellationImpl::GetHandleError(void* handle) const {
345 assert(handle != NULL);
346 return MapError(WebRtcAec_get_error_code(static_cast<Handle*>(handle)));
347 }
348 } // namespace webrtc
349