Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / audio_processing / echo_control_mobile_impl.cc
1 /*
2  *  Copyright (c) 2012 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 "webrtc/modules/audio_processing/echo_control_mobile_impl.h"
12
13 #include <assert.h>
14 #include <string.h>
15
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"
20
21 namespace webrtc {
22
23 typedef void Handle;
24
25 namespace {
26 int16_t MapSetting(EchoControlMobile::RoutingMode mode) {
27   switch (mode) {
28     case EchoControlMobile::kQuietEarpieceOrHeadset:
29       return 0;
30     case EchoControlMobile::kEarpiece:
31       return 1;
32     case EchoControlMobile::kLoudEarpiece:
33       return 2;
34     case EchoControlMobile::kSpeakerphone:
35       return 3;
36     case EchoControlMobile::kLoudSpeakerphone:
37       return 4;
38   }
39   assert(false);
40   return -1;
41 }
42
43 AudioProcessing::Error MapError(int err) {
44   switch (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;
53     default:
54       // AECM_UNSPECIFIED_ERROR
55       // AECM_UNINITIALIZED_ERROR
56       return AudioProcessing::kUnspecifiedError;
57   }
58 }
59 }  // namespace
60
61 size_t EchoControlMobile::echo_path_size_bytes() {
62     return WebRtcAecm_echo_path_size_bytes();
63 }
64
65 EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessing* apm,
66                                              CriticalSectionWrapper* crit)
67   : ProcessingComponent(),
68     apm_(apm),
69     crit_(crit),
70     routing_mode_(kSpeakerphone),
71     comfort_noise_enabled_(true),
72     external_echo_path_(NULL) {}
73
74 EchoControlMobileImpl::~EchoControlMobileImpl() {
75     if (external_echo_path_ != NULL) {
76       delete [] external_echo_path_;
77       external_echo_path_ = NULL;
78     }
79 }
80
81 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) {
82   if (!is_component_enabled()) {
83     return apm_->kNoError;
84   }
85
86   assert(audio->samples_per_split_channel() <= 160);
87   assert(audio->num_channels() == apm_->num_reverse_channels());
88
89   int err = apm_->kNoError;
90
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(
97           my_handle,
98           audio->low_pass_split_data(j),
99           static_cast<int16_t>(audio->samples_per_split_channel()));
100
101       if (err != apm_->kNoError) {
102         return GetHandleError(my_handle);  // TODO(ajm): warning possible?
103       }
104
105       handle_index++;
106     }
107   }
108
109   return apm_->kNoError;
110 }
111
112 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) {
113   if (!is_component_enabled()) {
114     return apm_->kNoError;
115   }
116
117   if (!apm_->was_stream_delay_set()) {
118     return apm_->kStreamParameterNotSetError;
119   }
120
121   assert(audio->samples_per_split_channel() <= 160);
122   assert(audio->num_channels() == apm_->num_output_channels());
123
124   int err = apm_->kNoError;
125
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);
133     if (noisy == NULL) {
134       noisy = clean;
135       clean = NULL;
136     }
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(
140           my_handle,
141           noisy,
142           clean,
143           audio->low_pass_split_data(i),
144           static_cast<int16_t>(audio->samples_per_split_channel()),
145           apm_->stream_delay_ms());
146
147       if (err != apm_->kNoError) {
148         return GetHandleError(my_handle);  // TODO(ajm): warning possible?
149       }
150
151       handle_index++;
152     }
153   }
154
155   return apm_->kNoError;
156 }
157
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;
163   }
164
165   return EnableComponent(enable);
166 }
167
168 bool EchoControlMobileImpl::is_enabled() const {
169   return is_component_enabled();
170 }
171
172 int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
173   CriticalSectionScoped crit_scoped(crit_);
174   if (MapSetting(mode) == -1) {
175     return apm_->kBadParameterError;
176   }
177
178   routing_mode_ = mode;
179   return Configure();
180 }
181
182 EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
183     const {
184   return routing_mode_;
185 }
186
187 int EchoControlMobileImpl::enable_comfort_noise(bool enable) {
188   CriticalSectionScoped crit_scoped(crit_);
189   comfort_noise_enabled_ = enable;
190   return Configure();
191 }
192
193 bool EchoControlMobileImpl::is_comfort_noise_enabled() const {
194   return comfort_noise_enabled_;
195 }
196
197 int EchoControlMobileImpl::SetEchoPath(const void* echo_path,
198                                        size_t size_bytes) {
199   CriticalSectionScoped crit_scoped(crit_);
200   if (echo_path == NULL) {
201     return apm_->kNullPointerError;
202   }
203   if (size_bytes != echo_path_size_bytes()) {
204     // Size mismatch
205     return apm_->kBadParameterError;
206   }
207
208   if (external_echo_path_ == NULL) {
209     external_echo_path_ = new unsigned char[size_bytes];
210   }
211   memcpy(external_echo_path_, echo_path, size_bytes);
212
213   return Initialize();
214 }
215
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;
221   }
222   if (size_bytes != echo_path_size_bytes()) {
223     // Size mismatch
224     return apm_->kBadParameterError;
225   }
226   if (!is_component_enabled()) {
227     return apm_->kNotEnabledError;
228   }
229
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);
234   }
235
236   return apm_->kNoError;
237 }
238
239 int EchoControlMobileImpl::Initialize() {
240   if (!is_component_enabled()) {
241     return apm_->kNoError;
242   }
243
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;
247   }
248
249   return ProcessingComponent::Initialize();
250 }
251
252 void* EchoControlMobileImpl::CreateHandle() const {
253   Handle* handle = NULL;
254   if (WebRtcAecm_Create(&handle) != apm_->kNoError) {
255     handle = NULL;
256   } else {
257     assert(handle != NULL);
258   }
259
260   return handle;
261 }
262
263 void EchoControlMobileImpl::DestroyHandle(void* handle) const {
264   WebRtcAecm_Free(static_cast<Handle*>(handle));
265 }
266
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);
272   }
273   if (external_echo_path_ != NULL) {
274     if (WebRtcAecm_InitEchoPath(my_handle,
275                                 external_echo_path_,
276                                 echo_path_size_bytes()) != 0) {
277       return GetHandleError(my_handle);
278     }
279   }
280
281   return apm_->kNoError;
282 }
283
284 int EchoControlMobileImpl::ConfigureHandle(void* handle) const {
285   AecmConfig config;
286   config.cngMode = comfort_noise_enabled_;
287   config.echoMode = MapSetting(routing_mode_);
288
289   return WebRtcAecm_set_config(static_cast<Handle*>(handle), config);
290 }
291
292 int EchoControlMobileImpl::num_handles_required() const {
293   return apm_->num_output_channels() *
294          apm_->num_reverse_channels();
295 }
296
297 int EchoControlMobileImpl::GetHandleError(void* handle) const {
298   assert(handle != NULL);
299   return MapError(WebRtcAecm_get_error_code(static_cast<Handle*>(handle)));
300 }
301 }  // namespace webrtc