2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/audio_processing/echo_control_mobile_impl.h"
16 #include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
17 #include "webrtc/modules/audio_processing/audio_buffer.h"
18 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19 #include "webrtc/system_wrappers/interface/logging.h"
26 int16_t MapSetting(EchoControlMobile::RoutingMode mode) {
28 case EchoControlMobile::kQuietEarpieceOrHeadset:
30 case EchoControlMobile::kEarpiece:
32 case EchoControlMobile::kLoudEarpiece:
34 case EchoControlMobile::kSpeakerphone:
36 case EchoControlMobile::kLoudSpeakerphone:
43 AudioProcessing::Error MapError(int err) {
45 case AECM_UNSUPPORTED_FUNCTION_ERROR:
46 return AudioProcessing::kUnsupportedFunctionError;
47 case AECM_NULL_POINTER_ERROR:
48 return AudioProcessing::kNullPointerError;
49 case AECM_BAD_PARAMETER_ERROR:
50 return AudioProcessing::kBadParameterError;
51 case AECM_BAD_PARAMETER_WARNING:
52 return AudioProcessing::kBadStreamParameterWarning;
54 // AECM_UNSPECIFIED_ERROR
55 // AECM_UNINITIALIZED_ERROR
56 return AudioProcessing::kUnspecifiedError;
61 size_t EchoControlMobile::echo_path_size_bytes() {
62 return WebRtcAecm_echo_path_size_bytes();
65 EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessing* apm,
66 CriticalSectionWrapper* crit)
67 : ProcessingComponent(),
70 routing_mode_(kSpeakerphone),
71 comfort_noise_enabled_(true),
72 external_echo_path_(NULL) {}
74 EchoControlMobileImpl::~EchoControlMobileImpl() {
75 if (external_echo_path_ != NULL) {
76 delete [] external_echo_path_;
77 external_echo_path_ = NULL;
81 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) {
82 if (!is_component_enabled()) {
83 return apm_->kNoError;
86 assert(audio->samples_per_split_channel() <= 160);
87 assert(audio->num_channels() == apm_->num_reverse_channels());
89 int err = apm_->kNoError;
91 // The ordering convention must be followed to pass to the correct AECM.
92 size_t handle_index = 0;
93 for (int i = 0; i < apm_->num_output_channels(); i++) {
94 for (int j = 0; j < audio->num_channels(); j++) {
95 Handle* my_handle = static_cast<Handle*>(handle(handle_index));
96 err = WebRtcAecm_BufferFarend(
98 audio->low_pass_split_data(j),
99 static_cast<int16_t>(audio->samples_per_split_channel()));
101 if (err != apm_->kNoError) {
102 return GetHandleError(my_handle); // TODO(ajm): warning possible?
109 return apm_->kNoError;
112 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) {
113 if (!is_component_enabled()) {
114 return apm_->kNoError;
117 if (!apm_->was_stream_delay_set()) {
118 return apm_->kStreamParameterNotSetError;
121 assert(audio->samples_per_split_channel() <= 160);
122 assert(audio->num_channels() == apm_->num_output_channels());
124 int err = apm_->kNoError;
126 // The ordering convention must be followed to pass to the correct AECM.
127 size_t handle_index = 0;
128 for (int i = 0; i < audio->num_channels(); i++) {
129 // TODO(ajm): improve how this works, possibly inside AECM.
130 // This is kind of hacked up.
131 const int16_t* noisy = audio->low_pass_reference(i);
132 int16_t* clean = audio->low_pass_split_data(i);
137 for (int j = 0; j < apm_->num_reverse_channels(); j++) {
138 Handle* my_handle = static_cast<Handle*>(handle(handle_index));
139 err = WebRtcAecm_Process(
143 audio->low_pass_split_data(i),
144 static_cast<int16_t>(audio->samples_per_split_channel()),
145 apm_->stream_delay_ms());
147 if (err != apm_->kNoError) {
148 return GetHandleError(my_handle); // TODO(ajm): warning possible?
155 return apm_->kNoError;
158 int EchoControlMobileImpl::Enable(bool enable) {
159 CriticalSectionScoped crit_scoped(crit_);
160 // Ensure AEC and AECM are not both enabled.
161 if (enable && apm_->echo_cancellation()->is_enabled()) {
162 return apm_->kBadParameterError;
165 return EnableComponent(enable);
168 bool EchoControlMobileImpl::is_enabled() const {
169 return is_component_enabled();
172 int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
173 CriticalSectionScoped crit_scoped(crit_);
174 if (MapSetting(mode) == -1) {
175 return apm_->kBadParameterError;
178 routing_mode_ = mode;
182 EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
184 return routing_mode_;
187 int EchoControlMobileImpl::enable_comfort_noise(bool enable) {
188 CriticalSectionScoped crit_scoped(crit_);
189 comfort_noise_enabled_ = enable;
193 bool EchoControlMobileImpl::is_comfort_noise_enabled() const {
194 return comfort_noise_enabled_;
197 int EchoControlMobileImpl::SetEchoPath(const void* echo_path,
199 CriticalSectionScoped crit_scoped(crit_);
200 if (echo_path == NULL) {
201 return apm_->kNullPointerError;
203 if (size_bytes != echo_path_size_bytes()) {
205 return apm_->kBadParameterError;
208 if (external_echo_path_ == NULL) {
209 external_echo_path_ = new unsigned char[size_bytes];
211 memcpy(external_echo_path_, echo_path, size_bytes);
216 int EchoControlMobileImpl::GetEchoPath(void* echo_path,
217 size_t size_bytes) const {
218 CriticalSectionScoped crit_scoped(crit_);
219 if (echo_path == NULL) {
220 return apm_->kNullPointerError;
222 if (size_bytes != echo_path_size_bytes()) {
224 return apm_->kBadParameterError;
226 if (!is_component_enabled()) {
227 return apm_->kNotEnabledError;
230 // Get the echo path from the first channel
231 Handle* my_handle = static_cast<Handle*>(handle(0));
232 if (WebRtcAecm_GetEchoPath(my_handle, echo_path, size_bytes) != 0) {
233 return GetHandleError(my_handle);
236 return apm_->kNoError;
239 int EchoControlMobileImpl::Initialize() {
240 if (!is_component_enabled()) {
241 return apm_->kNoError;
244 if (apm_->proc_sample_rate_hz() > apm_->kSampleRate16kHz) {
245 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
246 return apm_->kBadSampleRateError;
249 return ProcessingComponent::Initialize();
252 void* EchoControlMobileImpl::CreateHandle() const {
253 Handle* handle = NULL;
254 if (WebRtcAecm_Create(&handle) != apm_->kNoError) {
257 assert(handle != NULL);
263 void EchoControlMobileImpl::DestroyHandle(void* handle) const {
264 WebRtcAecm_Free(static_cast<Handle*>(handle));
267 int EchoControlMobileImpl::InitializeHandle(void* handle) const {
268 assert(handle != NULL);
269 Handle* my_handle = static_cast<Handle*>(handle);
270 if (WebRtcAecm_Init(my_handle, apm_->proc_sample_rate_hz()) != 0) {
271 return GetHandleError(my_handle);
273 if (external_echo_path_ != NULL) {
274 if (WebRtcAecm_InitEchoPath(my_handle,
276 echo_path_size_bytes()) != 0) {
277 return GetHandleError(my_handle);
281 return apm_->kNoError;
284 int EchoControlMobileImpl::ConfigureHandle(void* handle) const {
286 config.cngMode = comfort_noise_enabled_;
287 config.echoMode = MapSetting(routing_mode_);
289 return WebRtcAecm_set_config(static_cast<Handle*>(handle), config);
292 int EchoControlMobileImpl::num_handles_required() const {
293 return apm_->num_output_channels() *
294 apm_->num_reverse_channels();
297 int EchoControlMobileImpl::GetHandleError(void* handle) const {
298 assert(handle != NULL);
299 return MapError(WebRtcAecm_get_error_code(static_cast<Handle*>(handle)));
301 } // namespace webrtc