• 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_control_mobile_impl.h"
12 
13 #include <cassert>
14 
15 #include "critical_section_wrapper.h"
16 #include "echo_control_mobile.h"
17 
18 #include "audio_processing_impl.h"
19 #include "audio_buffer.h"
20 
21 namespace webrtc {
22 
23 typedef void Handle;
24 
25 namespace {
MapSetting(EchoControlMobile::RoutingMode mode)26 WebRtc_Word16 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     default:
39       return -1;
40   }
41 }
42 
MapError(int err)43 int MapError(int err) {
44   switch (err) {
45     case AECM_UNSUPPORTED_FUNCTION_ERROR:
46       return AudioProcessing::kUnsupportedFunctionError;
47     case AECM_BAD_PARAMETER_ERROR:
48       return AudioProcessing::kBadParameterError;
49     case AECM_BAD_PARAMETER_WARNING:
50       return AudioProcessing::kBadStreamParameterWarning;
51     default:
52       // AECMOBFIX_UNSPECIFIED_ERROR
53       // AECMOBFIX_UNINITIALIZED_ERROR
54       // AECMOBFIX_NULL_POINTER_ERROR
55       return AudioProcessing::kUnspecifiedError;
56   }
57 }
58 }  // namespace
59 
EchoControlMobileImpl(const AudioProcessingImpl * apm)60 EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessingImpl* apm)
61   : ProcessingComponent(apm),
62     apm_(apm),
63     routing_mode_(kSpeakerphone),
64     comfort_noise_enabled_(true) {}
65 
~EchoControlMobileImpl()66 EchoControlMobileImpl::~EchoControlMobileImpl() {}
67 
ProcessRenderAudio(const AudioBuffer * audio)68 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) {
69   if (!is_component_enabled()) {
70     return apm_->kNoError;
71   }
72 
73   assert(audio->samples_per_split_channel() <= 160);
74   assert(audio->num_channels() == apm_->num_reverse_channels());
75 
76   int err = apm_->kNoError;
77 
78   // The ordering convention must be followed to pass to the correct AECM.
79   size_t handle_index = 0;
80   for (int i = 0; i < apm_->num_output_channels(); i++) {
81     for (int j = 0; j < audio->num_channels(); j++) {
82       Handle* my_handle = static_cast<Handle*>(handle(handle_index));
83       err = WebRtcAecm_BufferFarend(
84           my_handle,
85           audio->low_pass_split_data(j),
86           static_cast<WebRtc_Word16>(audio->samples_per_split_channel()));
87 
88       if (err != apm_->kNoError) {
89         return GetHandleError(my_handle);  // TODO(ajm): warning possible?
90       }
91 
92       handle_index++;
93     }
94   }
95 
96   return apm_->kNoError;
97 }
98 
ProcessCaptureAudio(AudioBuffer * audio)99 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) {
100   if (!is_component_enabled()) {
101     return apm_->kNoError;
102   }
103 
104   if (!apm_->was_stream_delay_set()) {
105     return apm_->kStreamParameterNotSetError;
106   }
107 
108   assert(audio->samples_per_split_channel() <= 160);
109   assert(audio->num_channels() == apm_->num_output_channels());
110 
111   int err = apm_->kNoError;
112 
113   // The ordering convention must be followed to pass to the correct AECM.
114   size_t handle_index = 0;
115   for (int i = 0; i < audio->num_channels(); i++) {
116     // TODO(ajm): improve how this works, possibly inside AECM.
117     //            This is kind of hacked up.
118     WebRtc_Word16* noisy = audio->low_pass_reference(i);
119     WebRtc_Word16* clean = audio->low_pass_split_data(i);
120     if (noisy == NULL) {
121       noisy = clean;
122       clean = NULL;
123     }
124     for (int j = 0; j < apm_->num_reverse_channels(); j++) {
125       Handle* my_handle = static_cast<Handle*>(handle(handle_index));
126       err = WebRtcAecm_Process(
127           my_handle,
128           noisy,
129           clean,
130           audio->low_pass_split_data(i),
131           static_cast<WebRtc_Word16>(audio->samples_per_split_channel()),
132           apm_->stream_delay_ms());
133 
134       if (err != apm_->kNoError) {
135         return GetHandleError(my_handle);  // TODO(ajm): warning possible?
136       }
137 
138       handle_index++;
139     }
140   }
141 
142   return apm_->kNoError;
143 }
144 
Enable(bool enable)145 int EchoControlMobileImpl::Enable(bool enable) {
146   CriticalSectionScoped crit_scoped(*apm_->crit());
147   // Ensure AEC and AECM are not both enabled.
148   if (enable && apm_->echo_cancellation()->is_enabled()) {
149     return apm_->kBadParameterError;
150   }
151 
152   return EnableComponent(enable);
153 }
154 
is_enabled() const155 bool EchoControlMobileImpl::is_enabled() const {
156   return is_component_enabled();
157 }
158 
set_routing_mode(RoutingMode mode)159 int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
160   CriticalSectionScoped crit_scoped(*apm_->crit());
161   if (MapSetting(mode) == -1) {
162     return apm_->kBadParameterError;
163   }
164 
165   routing_mode_ = mode;
166   return Configure();
167 }
168 
routing_mode() const169 EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
170     const {
171   return routing_mode_;
172 }
173 
enable_comfort_noise(bool enable)174 int EchoControlMobileImpl::enable_comfort_noise(bool enable) {
175   CriticalSectionScoped crit_scoped(*apm_->crit());
176   comfort_noise_enabled_ = enable;
177   return Configure();
178 }
179 
is_comfort_noise_enabled() const180 bool EchoControlMobileImpl::is_comfort_noise_enabled() const {
181   return comfort_noise_enabled_;
182 }
183 
Initialize()184 int EchoControlMobileImpl::Initialize() {
185   if (!is_component_enabled()) {
186     return apm_->kNoError;
187   }
188 
189   if (apm_->sample_rate_hz() == apm_->kSampleRate32kHz) {
190     // AECM doesn't support super-wideband.
191     return apm_->kBadSampleRateError;
192   }
193 
194   return ProcessingComponent::Initialize();
195 }
196 
get_version(char * version,int version_len_bytes) const197 int EchoControlMobileImpl::get_version(char* version,
198                                        int version_len_bytes) const {
199   if (WebRtcAecm_get_version(version, version_len_bytes) != 0) {
200       return apm_->kBadParameterError;
201   }
202 
203   return apm_->kNoError;
204 }
205 
CreateHandle() const206 void* EchoControlMobileImpl::CreateHandle() const {
207   Handle* handle = NULL;
208   if (WebRtcAecm_Create(&handle) != apm_->kNoError) {
209     handle = NULL;
210   } else {
211     assert(handle != NULL);
212   }
213 
214   return handle;
215 }
216 
DestroyHandle(void * handle) const217 int EchoControlMobileImpl::DestroyHandle(void* handle) const {
218   return WebRtcAecm_Free(static_cast<Handle*>(handle));
219 }
220 
InitializeHandle(void * handle) const221 int EchoControlMobileImpl::InitializeHandle(void* handle) const {
222   return WebRtcAecm_Init(static_cast<Handle*>(handle),
223                          apm_->sample_rate_hz(),
224                          48000); // Dummy value. This isn't actually
225                                  // required by AECM.
226 }
227 
ConfigureHandle(void * handle) const228 int EchoControlMobileImpl::ConfigureHandle(void* handle) const {
229   AecmConfig config;
230   config.cngMode = comfort_noise_enabled_;
231   config.echoMode = MapSetting(routing_mode_);
232 
233   return WebRtcAecm_set_config(static_cast<Handle*>(handle), config);
234 }
235 
num_handles_required() const236 int EchoControlMobileImpl::num_handles_required() const {
237   return apm_->num_output_channels() *
238          apm_->num_reverse_channels();
239 }
240 
GetHandleError(void * handle) const241 int EchoControlMobileImpl::GetHandleError(void* handle) const {
242   assert(handle != NULL);
243   return MapError(WebRtcAecm_get_error_code(static_cast<Handle*>(handle)));
244 }
245 }  // namespace webrtc
246