• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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