• 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 
~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