1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11dba34dd1d41e811769e6ebd085e7101e257a64d8bjornv@webrtc.org#include "webrtc/modules/audio_processing/echo_cancellation_impl.h"
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
13dba34dd1d41e811769e6ebd085e7101e257a64d8bjornv@webrtc.org#include <assert.h>
14b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <string.h>
15b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
168ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.orgextern "C" {
178ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org#include "webrtc/modules/audio_processing/aec/aec_core.h"
188ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org}
198ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org#include "webrtc/modules/audio_processing/aec/include/echo_cancellation.h"
20dba34dd1d41e811769e6ebd085e7101e257a64d8bjornv@webrtc.org#include "webrtc/modules/audio_processing/audio_buffer.h"
21dba34dd1d41e811769e6ebd085e7101e257a64d8bjornv@webrtc.org#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc {
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgtypedef void Handle;
26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace {
283f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.orgint16_t MapSetting(EchoCancellation::SuppressionLevel level) {
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  switch (level) {
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case EchoCancellation::kLowSuppression:
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return kAecNlpConservative;
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case EchoCancellation::kModerateSuppression:
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return kAecNlpModerate;
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case EchoCancellation::kHighSuppression:
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return kAecNlpAggressive;
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(false);
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return -1;
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioProcessing::Error MapError(int err) {
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  switch (err) {
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case AEC_UNSUPPORTED_FUNCTION_ERROR:
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return AudioProcessing::kUnsupportedFunctionError;
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case AEC_BAD_PARAMETER_ERROR:
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return AudioProcessing::kBadParameterError;
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case AEC_BAD_PARAMETER_WARNING:
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return AudioProcessing::kBadStreamParameterWarning;
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    default:
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      // AEC_UNSPECIFIED_ERROR
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      // AEC_UNINITIALIZED_ERROR
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      // AEC_NULL_POINTER_ERROR
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      return AudioProcessing::kUnspecifiedError;
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
58a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.orgEchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm,
59a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org                                           CriticalSectionWrapper* crit)
60a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  : ProcessingComponent(),
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    apm_(apm),
62a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org    crit_(crit),
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    drift_compensation_enabled_(false),
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    metrics_enabled_(false),
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    suppression_level_(kModerateSuppression),
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    stream_drift_samples_(0),
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    was_stream_drift_set_(false),
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    stream_has_echo_(false),
698ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org    delay_logging_enabled_(false),
70376df2cf3dd5f653dd551f79021815ab3c4a02c4bjornv@webrtc.org    delay_correction_enabled_(false),
71376df2cf3dd5f653dd551f79021815ab3c4a02c4bjornv@webrtc.org    reported_delay_enabled_(true) {}
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgEchoCancellationImpl::~EchoCancellationImpl() {}
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!is_component_enabled()) {
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNoError;
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(audio->samples_per_split_channel() <= 160);
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(audio->num_channels() == apm_->num_reverse_channels());
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int err = apm_->kNoError;
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // The ordering convention must be followed to pass to the correct AEC.
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  size_t handle_index = 0;
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  for (int i = 0; i < apm_->num_output_channels(); i++) {
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (int j = 0; j < audio->num_channels(); j++) {
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      Handle* my_handle = static_cast<Handle*>(handle(handle_index));
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      err = WebRtcAec_BufferFarend(
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          my_handle,
9238a0cee9789409eebadb54bcf055a29b61767118kwiberg@webrtc.org          audio->low_pass_split_data_f(j),
933f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org          static_cast<int16_t>(audio->samples_per_split_channel()));
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (err != apm_->kNoError) {
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return GetHandleError(my_handle);  // TODO(ajm): warning possible?
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      handle_index++;
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->kNoError;
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) {
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!is_component_enabled()) {
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNoError;
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!apm_->was_stream_delay_set()) {
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kStreamParameterNotSetError;
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (drift_compensation_enabled_ && !was_stream_drift_set_) {
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kStreamParameterNotSetError;
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(audio->samples_per_split_channel() <= 160);
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(audio->num_channels() == apm_->num_output_channels());
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int err = apm_->kNoError;
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // The ordering convention must be followed to pass to the correct AEC.
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  size_t handle_index = 0;
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  stream_has_echo_ = false;
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  for (int i = 0; i < audio->num_channels(); i++) {
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (int j = 0; j < apm_->num_reverse_channels(); j++) {
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      Handle* my_handle = handle(handle_index);
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      err = WebRtcAec_Process(
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          my_handle,
132e9b43402e00fc048cf93d7bb9a2cdbf97c1fed2cmflodman@webrtc.org          audio->low_pass_split_data_f(i),
133e9b43402e00fc048cf93d7bb9a2cdbf97c1fed2cmflodman@webrtc.org          audio->high_pass_split_data_f(i),
134e9b43402e00fc048cf93d7bb9a2cdbf97c1fed2cmflodman@webrtc.org          audio->low_pass_split_data_f(i),
135e9b43402e00fc048cf93d7bb9a2cdbf97c1fed2cmflodman@webrtc.org          audio->high_pass_split_data_f(i),
1363f6d5e0bded85b8b0d055da8fa49e8d7137fe8edpbos@webrtc.org          static_cast<int16_t>(audio->samples_per_split_channel()),
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          apm_->stream_delay_ms(),
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          stream_drift_samples_);
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (err != apm_->kNoError) {
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = GetHandleError(my_handle);
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // TODO(ajm): Figure out how to return warnings properly.
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != apm_->kBadStreamParameterWarning) {
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          return err;
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
148dba34dd1d41e811769e6ebd085e7101e257a64d8bjornv@webrtc.org      int status = 0;
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      err = WebRtcAec_get_echo_status(my_handle, &status);
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (err != apm_->kNoError) {
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return GetHandleError(my_handle);
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (status == 1) {
155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        stream_has_echo_ = true;
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      handle_index++;
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  was_stream_drift_set_ = false;
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->kNoError;
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::Enable(bool enable) {
167a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Ensure AEC and AECM are not both enabled.
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (enable && apm_->echo_control_mobile()->is_enabled()) {
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kBadParameterError;
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return EnableComponent(enable);
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool EchoCancellationImpl::is_enabled() const {
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return is_component_enabled();
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::set_suppression_level(SuppressionLevel level) {
181a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (MapSetting(level) == -1) {
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kBadParameterError;
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  suppression_level_ = level;
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return Configure();
188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgEchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level()
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const {
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return suppression_level_;
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::enable_drift_compensation(bool enable) {
196a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  drift_compensation_enabled_ = enable;
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return Configure();
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool EchoCancellationImpl::is_drift_compensation_enabled() const {
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return drift_compensation_enabled_;
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
205b563e5e8b34fd7f0c6c02fa4176e9be83c2bf795andrew@webrtc.orgvoid EchoCancellationImpl::set_stream_drift_samples(int drift) {
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  was_stream_drift_set_ = true;
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  stream_drift_samples_ = drift;
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::stream_drift_samples() const {
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return stream_drift_samples_;
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::enable_metrics(bool enable) {
215a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics_enabled_ = enable;
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return Configure();
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool EchoCancellationImpl::are_metrics_enabled() const {
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return metrics_enabled_;
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// TODO(ajm): we currently just use the metrics from the first AEC. Think more
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//            aboue the best way to extend this to multi-channel.
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::GetMetrics(Metrics* metrics) {
227a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (metrics == NULL) {
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNullPointerError;
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!is_component_enabled() || !metrics_enabled_) {
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNotEnabledError;
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  AecMetrics my_metrics;
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  memset(&my_metrics, 0, sizeof(my_metrics));
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  memset(metrics, 0, sizeof(Metrics));
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  Handle* my_handle = static_cast<Handle*>(handle(0));
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int err = WebRtcAec_GetMetrics(my_handle, &my_metrics);
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (err != apm_->kNoError) {
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return GetHandleError(my_handle);
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant;
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->residual_echo_return_loss.average = my_metrics.rerl.average;
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max;
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min;
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->echo_return_loss.instant = my_metrics.erl.instant;
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->echo_return_loss.average = my_metrics.erl.average;
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->echo_return_loss.maximum = my_metrics.erl.max;
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->echo_return_loss.minimum = my_metrics.erl.min;
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant;
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->echo_return_loss_enhancement.average = my_metrics.erle.average;
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max;
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min;
260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->a_nlp.instant = my_metrics.aNlp.instant;
262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->a_nlp.average = my_metrics.aNlp.average;
263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->a_nlp.maximum = my_metrics.aNlp.max;
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  metrics->a_nlp.minimum = my_metrics.aNlp.min;
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->kNoError;
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool EchoCancellationImpl::stream_has_echo() const {
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return stream_has_echo_;
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::enable_delay_logging(bool enable) {
274a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  delay_logging_enabled_ = enable;
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return Configure();
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool EchoCancellationImpl::is_delay_logging_enabled() const {
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return delay_logging_enabled_;
281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// TODO(bjornv): How should we handle the multi-channel case?
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::GetDelayMetrics(int* median, int* std) {
285a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (median == NULL) {
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNullPointerError;
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (std == NULL) {
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNullPointerError;
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!is_component_enabled() || !delay_logging_enabled_) {
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return apm_->kNotEnabledError;
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  Handle* my_handle = static_cast<Handle*>(handle(0));
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (WebRtcAec_GetDelayMetrics(my_handle, median, std) !=
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      apm_->kNoError) {
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return GetHandleError(my_handle);
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->kNoError;
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
3064c2225fdfc806db5372139b6d2c3a138d4aaf10bbjornv@webrtc.orgstruct AecCore* EchoCancellationImpl::aec_core() const {
307a1a60018a1f1ec863451ad0ed4eae58239882920andrew@webrtc.org  CriticalSectionScoped crit_scoped(crit_);
3084c2225fdfc806db5372139b6d2c3a138d4aaf10bbjornv@webrtc.org  if (!is_component_enabled()) {
3094c2225fdfc806db5372139b6d2c3a138d4aaf10bbjornv@webrtc.org    return NULL;
3104c2225fdfc806db5372139b6d2c3a138d4aaf10bbjornv@webrtc.org  }
3114c2225fdfc806db5372139b6d2c3a138d4aaf10bbjornv@webrtc.org  Handle* my_handle = static_cast<Handle*>(handle(0));
3124c2225fdfc806db5372139b6d2c3a138d4aaf10bbjornv@webrtc.org  return WebRtcAec_aec_core(my_handle);
3134c2225fdfc806db5372139b6d2c3a138d4aaf10bbjornv@webrtc.org}
3144c2225fdfc806db5372139b6d2c3a138d4aaf10bbjornv@webrtc.org
315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::Initialize() {
316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int err = ProcessingComponent::Initialize();
317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (err != apm_->kNoError || !is_component_enabled()) {
318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return err;
319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->kNoError;
322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
3248ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.orgvoid EchoCancellationImpl::SetExtraOptions(const Config& config) {
3258ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org  delay_correction_enabled_ = config.Get<DelayCorrection>().enabled;
326b96d9c72c7286b3505e7a122e34d770377a46052bjornv@webrtc.org  reported_delay_enabled_ = config.Get<ReportedDelay>().enabled;
3278ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org  Configure();
3288ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org}
3298ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org
330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid* EchoCancellationImpl::CreateHandle() const {
331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  Handle* handle = NULL;
332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (WebRtcAec_Create(&handle) != apm_->kNoError) {
333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    handle = NULL;
334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  } else {
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(handle != NULL);
336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return handle;
339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
341ffc2de0133683fb103eef61f21134f469bc099dbbjornv@webrtc.orgvoid EchoCancellationImpl::DestroyHandle(void* handle) const {
342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(handle != NULL);
343ffc2de0133683fb103eef61f21134f469bc099dbbjornv@webrtc.org  WebRtcAec_Free(static_cast<Handle*>(handle));
344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::InitializeHandle(void* handle) const {
347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(handle != NULL);
348467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org  // TODO(ajm): Drift compensation is disabled in practice. If restored, it
349467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org  // should be managed internally and not depend on the hardware sample rate.
350467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org  // For now, just hardcode a 48 kHz value.
351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return WebRtcAec_Init(static_cast<Handle*>(handle),
352467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org                       apm_->proc_sample_rate_hz(),
353467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org                       48000);
354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::ConfigureHandle(void* handle) const {
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(handle != NULL);
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  AecConfig config;
359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  config.metricsMode = metrics_enabled_;
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  config.nlpMode = MapSetting(suppression_level_);
361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  config.skewMode = drift_compensation_enabled_;
362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  config.delay_logging = delay_logging_enabled_;
363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
3648ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org  WebRtcAec_enable_delay_correction(WebRtcAec_aec_core(
3658ddec2c539a1daf4dd08607561090ac163cb9a7aandrew@webrtc.org      static_cast<Handle*>(handle)), delay_correction_enabled_ ? 1 : 0);
366376df2cf3dd5f653dd551f79021815ab3c4a02c4bjornv@webrtc.org  WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(
367376df2cf3dd5f653dd551f79021815ab3c4a02c4bjornv@webrtc.org      static_cast<Handle*>(handle)), reported_delay_enabled_ ? 1 : 0);
368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return WebRtcAec_set_config(static_cast<Handle*>(handle), config);
369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::num_handles_required() const {
372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return apm_->num_output_channels() *
373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         apm_->num_reverse_channels();
374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
376b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint EchoCancellationImpl::GetHandleError(void* handle) const {
377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(handle != NULL);
378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return MapError(WebRtcAec_get_error_code(static_cast<Handle*>(handle)));
379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace webrtc
381