OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/audio_processing/echo_control_mobile_impl.h" | 11 #include "webrtc/modules/audio_processing/echo_control_mobile_impl.h" |
12 | 12 |
13 #include <assert.h> | 13 #include <assert.h> |
14 #include <string.h> | 14 #include <string.h> |
15 | 15 |
16 #include "webrtc/modules/audio_processing/aecm/echo_control_mobile.h" | 16 #include "webrtc/modules/audio_processing/aecm/echo_control_mobile.h" |
17 #include "webrtc/modules/audio_processing/audio_buffer.h" | 17 #include "webrtc/modules/audio_processing/audio_buffer.h" |
18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
19 #include "webrtc/system_wrappers/include/logging.h" | 18 #include "webrtc/system_wrappers/include/logging.h" |
20 | 19 |
21 namespace webrtc { | 20 namespace webrtc { |
22 | 21 |
23 typedef void Handle; | 22 typedef void Handle; |
24 | 23 |
25 namespace { | 24 namespace { |
26 int16_t MapSetting(EchoControlMobile::RoutingMode mode) { | 25 int16_t MapSetting(EchoControlMobile::RoutingMode mode) { |
27 switch (mode) { | 26 switch (mode) { |
28 case EchoControlMobile::kQuietEarpieceOrHeadset: | 27 case EchoControlMobile::kQuietEarpieceOrHeadset: |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 // Maximum number of frames to buffer in the render queue. | 60 // Maximum number of frames to buffer in the render queue. |
62 // TODO(peah): Decrease this once we properly handle hugely unbalanced | 61 // TODO(peah): Decrease this once we properly handle hugely unbalanced |
63 // reverse and forward call numbers. | 62 // reverse and forward call numbers. |
64 static const size_t kMaxNumFramesToBuffer = 100; | 63 static const size_t kMaxNumFramesToBuffer = 100; |
65 } // namespace | 64 } // namespace |
66 | 65 |
67 size_t EchoControlMobile::echo_path_size_bytes() { | 66 size_t EchoControlMobile::echo_path_size_bytes() { |
68 return WebRtcAecm_echo_path_size_bytes(); | 67 return WebRtcAecm_echo_path_size_bytes(); |
69 } | 68 } |
70 | 69 |
71 EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessing* apm, | 70 EchoControlMobileImpl::EchoControlMobileImpl( |
72 CriticalSectionWrapper* crit) | 71 const AudioProcessing* apm, |
| 72 rtc::CriticalSection* crit_render, |
| 73 rtc::CriticalSection* crit_capture) |
73 : ProcessingComponent(), | 74 : ProcessingComponent(), |
74 apm_(apm), | 75 apm_(apm), |
75 crit_(crit), | 76 crit_render_(crit_render), |
| 77 crit_capture_(crit_capture), |
76 routing_mode_(kSpeakerphone), | 78 routing_mode_(kSpeakerphone), |
77 comfort_noise_enabled_(true), | 79 comfort_noise_enabled_(true), |
78 external_echo_path_(NULL), | 80 external_echo_path_(NULL), |
79 render_queue_element_max_size_(0) {} | 81 render_queue_element_max_size_(0) { |
| 82 RTC_DCHECK(apm); |
| 83 RTC_DCHECK(crit_render); |
| 84 RTC_DCHECK(crit_capture); |
| 85 } |
80 | 86 |
81 EchoControlMobileImpl::~EchoControlMobileImpl() { | 87 EchoControlMobileImpl::~EchoControlMobileImpl() { |
82 if (external_echo_path_ != NULL) { | 88 if (external_echo_path_ != NULL) { |
83 delete [] external_echo_path_; | 89 delete [] external_echo_path_; |
84 external_echo_path_ = NULL; | 90 external_echo_path_ = NULL; |
85 } | 91 } |
86 } | 92 } |
87 | 93 |
88 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { | 94 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { |
| 95 rtc::CritScope cs_render(crit_render_); |
| 96 |
89 if (!is_component_enabled()) { | 97 if (!is_component_enabled()) { |
90 return apm_->kNoError; | 98 return AudioProcessing::kNoError; |
91 } | 99 } |
92 | 100 |
93 assert(audio->num_frames_per_band() <= 160); | 101 assert(audio->num_frames_per_band() <= 160); |
94 assert(audio->num_channels() == apm_->num_reverse_channels()); | 102 assert(audio->num_channels() == apm_->num_reverse_channels()); |
95 | 103 |
96 int err = apm_->kNoError; | 104 int err = AudioProcessing::kNoError; |
97 | |
98 // The ordering convention must be followed to pass to the correct AECM. | 105 // The ordering convention must be followed to pass to the correct AECM. |
99 size_t handle_index = 0; | 106 size_t handle_index = 0; |
100 render_queue_buffer_.clear(); | 107 render_queue_buffer_.clear(); |
101 for (int i = 0; i < apm_->num_output_channels(); i++) { | 108 for (int i = 0; i < apm_->num_output_channels(); i++) { |
102 for (int j = 0; j < audio->num_channels(); j++) { | 109 for (int j = 0; j < audio->num_channels(); j++) { |
103 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); | 110 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); |
104 err = WebRtcAecm_GetBufferFarendError( | 111 err = WebRtcAecm_GetBufferFarendError( |
105 my_handle, audio->split_bands_const(j)[kBand0To8kHz], | 112 my_handle, audio->split_bands_const(j)[kBand0To8kHz], |
106 audio->num_frames_per_band()); | 113 audio->num_frames_per_band()); |
107 | 114 |
108 if (err != apm_->kNoError) | 115 if (err != AudioProcessing::kNoError) |
109 return MapError(err); // TODO(ajm): warning possible?); | 116 return MapError(err); // TODO(ajm): warning possible?); |
110 | 117 |
111 // Buffer the samples in the render queue. | 118 // Buffer the samples in the render queue. |
112 render_queue_buffer_.insert(render_queue_buffer_.end(), | 119 render_queue_buffer_.insert(render_queue_buffer_.end(), |
113 audio->split_bands_const(j)[kBand0To8kHz], | 120 audio->split_bands_const(j)[kBand0To8kHz], |
114 (audio->split_bands_const(j)[kBand0To8kHz] + | 121 (audio->split_bands_const(j)[kBand0To8kHz] + |
115 audio->num_frames_per_band())); | 122 audio->num_frames_per_band())); |
116 | 123 |
117 handle_index++; | 124 handle_index++; |
118 } | 125 } |
119 } | 126 } |
120 | 127 |
121 // Insert the samples into the queue. | 128 // Insert the samples into the queue. |
122 if (!render_signal_queue_->Insert(&render_queue_buffer_)) { | 129 if (!render_signal_queue_->Insert(&render_queue_buffer_)) { |
| 130 // The data queue is full and needs to be emptied. |
123 ReadQueuedRenderData(); | 131 ReadQueuedRenderData(); |
124 | 132 |
125 // Retry the insert (should always work). | 133 // Retry the insert (should always work). |
126 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); | 134 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); |
127 } | 135 } |
128 | 136 |
129 return apm_->kNoError; | 137 return AudioProcessing::kNoError; |
130 } | 138 } |
131 | 139 |
132 // Read chunks of data that were received and queued on the render side from | 140 // Read chunks of data that were received and queued on the render side from |
133 // a queue. All the data chunks are buffered into the farend signal of the AEC. | 141 // a queue. All the data chunks are buffered into the farend signal of the AEC. |
134 void EchoControlMobileImpl::ReadQueuedRenderData() { | 142 void EchoControlMobileImpl::ReadQueuedRenderData() { |
| 143 rtc::CritScope cs_capture(crit_capture_); |
| 144 |
135 if (!is_component_enabled()) { | 145 if (!is_component_enabled()) { |
136 return; | 146 return; |
137 } | 147 } |
138 | 148 |
139 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { | 149 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { |
140 size_t handle_index = 0; | 150 size_t handle_index = 0; |
141 int buffer_index = 0; | 151 int buffer_index = 0; |
142 const int num_frames_per_band = | 152 const int num_frames_per_band = |
143 capture_queue_buffer_.size() / | 153 capture_queue_buffer_.size() / |
144 (apm_->num_output_channels() * apm_->num_reverse_channels()); | 154 (apm_->num_output_channels() * apm_->num_reverse_channels()); |
145 for (int i = 0; i < apm_->num_output_channels(); i++) { | 155 for (int i = 0; i < apm_->num_output_channels(); i++) { |
146 for (int j = 0; j < apm_->num_reverse_channels(); j++) { | 156 for (int j = 0; j < apm_->num_reverse_channels(); j++) { |
147 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); | 157 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); |
148 WebRtcAecm_BufferFarend(my_handle, &capture_queue_buffer_[buffer_index], | 158 WebRtcAecm_BufferFarend(my_handle, &capture_queue_buffer_[buffer_index], |
149 num_frames_per_band); | 159 num_frames_per_band); |
150 | 160 |
151 buffer_index += num_frames_per_band; | 161 buffer_index += num_frames_per_band; |
152 handle_index++; | 162 handle_index++; |
153 } | 163 } |
154 } | 164 } |
155 } | 165 } |
156 } | 166 } |
157 | 167 |
158 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { | 168 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { |
| 169 rtc::CritScope cs_capture(crit_capture_); |
| 170 |
159 if (!is_component_enabled()) { | 171 if (!is_component_enabled()) { |
160 return apm_->kNoError; | 172 return AudioProcessing::kNoError; |
161 } | 173 } |
162 | 174 |
163 if (!apm_->was_stream_delay_set()) { | 175 if (!apm_->was_stream_delay_set()) { |
164 return apm_->kStreamParameterNotSetError; | 176 return AudioProcessing::kStreamParameterNotSetError; |
165 } | 177 } |
166 | 178 |
167 assert(audio->num_frames_per_band() <= 160); | 179 assert(audio->num_frames_per_band() <= 160); |
168 assert(audio->num_channels() == apm_->num_output_channels()); | 180 assert(audio->num_channels() == apm_->num_output_channels()); |
169 | 181 |
170 int err = apm_->kNoError; | 182 int err = AudioProcessing::kNoError; |
171 | 183 |
172 // The ordering convention must be followed to pass to the correct AECM. | 184 // The ordering convention must be followed to pass to the correct AECM. |
173 size_t handle_index = 0; | 185 size_t handle_index = 0; |
174 for (int i = 0; i < audio->num_channels(); i++) { | 186 for (int i = 0; i < audio->num_channels(); i++) { |
175 // TODO(ajm): improve how this works, possibly inside AECM. | 187 // TODO(ajm): improve how this works, possibly inside AECM. |
176 // This is kind of hacked up. | 188 // This is kind of hacked up. |
177 const int16_t* noisy = audio->low_pass_reference(i); | 189 const int16_t* noisy = audio->low_pass_reference(i); |
178 const int16_t* clean = audio->split_bands_const(i)[kBand0To8kHz]; | 190 const int16_t* clean = audio->split_bands_const(i)[kBand0To8kHz]; |
179 if (noisy == NULL) { | 191 if (noisy == NULL) { |
180 noisy = clean; | 192 noisy = clean; |
181 clean = NULL; | 193 clean = NULL; |
182 } | 194 } |
183 for (int j = 0; j < apm_->num_reverse_channels(); j++) { | 195 for (int j = 0; j < apm_->num_reverse_channels(); j++) { |
184 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); | 196 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); |
185 err = WebRtcAecm_Process( | 197 err = WebRtcAecm_Process( |
186 my_handle, | 198 my_handle, |
187 noisy, | 199 noisy, |
188 clean, | 200 clean, |
189 audio->split_bands(i)[kBand0To8kHz], | 201 audio->split_bands(i)[kBand0To8kHz], |
190 audio->num_frames_per_band(), | 202 audio->num_frames_per_band(), |
191 apm_->stream_delay_ms()); | 203 apm_->stream_delay_ms()); |
192 | 204 |
193 if (err != apm_->kNoError) | 205 if (err != AudioProcessing::kNoError) |
194 return MapError(err); | 206 return MapError(err); |
195 | 207 |
196 handle_index++; | 208 handle_index++; |
197 } | 209 } |
198 } | 210 } |
199 | 211 |
200 return apm_->kNoError; | 212 return AudioProcessing::kNoError; |
201 } | 213 } |
202 | 214 |
203 int EchoControlMobileImpl::Enable(bool enable) { | 215 int EchoControlMobileImpl::Enable(bool enable) { |
204 CriticalSectionScoped crit_scoped(crit_); | |
205 // Ensure AEC and AECM are not both enabled. | 216 // Ensure AEC and AECM are not both enabled. |
| 217 rtc::CritScope cs_render(crit_render_); |
| 218 rtc::CritScope cs_capture(crit_capture_); |
| 219 // The is_enabled call is safe from a deadlock perspective |
| 220 // as both locks are allready held in the correct order. |
206 if (enable && apm_->echo_cancellation()->is_enabled()) { | 221 if (enable && apm_->echo_cancellation()->is_enabled()) { |
207 return apm_->kBadParameterError; | 222 return AudioProcessing::kBadParameterError; |
208 } | 223 } |
209 | 224 |
210 return EnableComponent(enable); | 225 return EnableComponent(enable); |
211 } | 226 } |
212 | 227 |
213 bool EchoControlMobileImpl::is_enabled() const { | 228 bool EchoControlMobileImpl::is_enabled() const { |
| 229 rtc::CritScope cs(crit_capture_); |
214 return is_component_enabled(); | 230 return is_component_enabled(); |
215 } | 231 } |
216 | 232 |
217 int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) { | 233 int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) { |
218 CriticalSectionScoped crit_scoped(crit_); | |
219 if (MapSetting(mode) == -1) { | 234 if (MapSetting(mode) == -1) { |
220 return apm_->kBadParameterError; | 235 return AudioProcessing::kBadParameterError; |
221 } | 236 } |
222 | 237 |
223 routing_mode_ = mode; | 238 { |
| 239 rtc::CritScope cs(crit_capture_); |
| 240 routing_mode_ = mode; |
| 241 } |
224 return Configure(); | 242 return Configure(); |
225 } | 243 } |
226 | 244 |
227 EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode() | 245 EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode() |
228 const { | 246 const { |
| 247 rtc::CritScope cs(crit_capture_); |
229 return routing_mode_; | 248 return routing_mode_; |
230 } | 249 } |
231 | 250 |
232 int EchoControlMobileImpl::enable_comfort_noise(bool enable) { | 251 int EchoControlMobileImpl::enable_comfort_noise(bool enable) { |
233 CriticalSectionScoped crit_scoped(crit_); | 252 { |
234 comfort_noise_enabled_ = enable; | 253 rtc::CritScope cs(crit_capture_); |
| 254 comfort_noise_enabled_ = enable; |
| 255 } |
235 return Configure(); | 256 return Configure(); |
236 } | 257 } |
237 | 258 |
238 bool EchoControlMobileImpl::is_comfort_noise_enabled() const { | 259 bool EchoControlMobileImpl::is_comfort_noise_enabled() const { |
| 260 rtc::CritScope cs(crit_capture_); |
239 return comfort_noise_enabled_; | 261 return comfort_noise_enabled_; |
240 } | 262 } |
241 | 263 |
242 int EchoControlMobileImpl::SetEchoPath(const void* echo_path, | 264 int EchoControlMobileImpl::SetEchoPath(const void* echo_path, |
243 size_t size_bytes) { | 265 size_t size_bytes) { |
244 CriticalSectionScoped crit_scoped(crit_); | 266 { |
245 if (echo_path == NULL) { | 267 rtc::CritScope cs_render(crit_render_); |
246 return apm_->kNullPointerError; | 268 rtc::CritScope cs_capture(crit_capture_); |
| 269 if (echo_path == NULL) { |
| 270 return AudioProcessing::kNullPointerError; |
| 271 } |
| 272 if (size_bytes != echo_path_size_bytes()) { |
| 273 // Size mismatch |
| 274 return AudioProcessing::kBadParameterError; |
| 275 } |
| 276 |
| 277 if (external_echo_path_ == NULL) { |
| 278 external_echo_path_ = new unsigned char[size_bytes]; |
| 279 } |
| 280 memcpy(external_echo_path_, echo_path, size_bytes); |
247 } | 281 } |
248 if (size_bytes != echo_path_size_bytes()) { | |
249 // Size mismatch | |
250 return apm_->kBadParameterError; | |
251 } | |
252 | |
253 if (external_echo_path_ == NULL) { | |
254 external_echo_path_ = new unsigned char[size_bytes]; | |
255 } | |
256 memcpy(external_echo_path_, echo_path, size_bytes); | |
257 | 282 |
258 return Initialize(); | 283 return Initialize(); |
259 } | 284 } |
260 | 285 |
261 int EchoControlMobileImpl::GetEchoPath(void* echo_path, | 286 int EchoControlMobileImpl::GetEchoPath(void* echo_path, |
262 size_t size_bytes) const { | 287 size_t size_bytes) const { |
263 CriticalSectionScoped crit_scoped(crit_); | 288 rtc::CritScope cs(crit_capture_); |
264 if (echo_path == NULL) { | 289 if (echo_path == NULL) { |
265 return apm_->kNullPointerError; | 290 return AudioProcessing::kNullPointerError; |
266 } | 291 } |
267 if (size_bytes != echo_path_size_bytes()) { | 292 if (size_bytes != echo_path_size_bytes()) { |
268 // Size mismatch | 293 // Size mismatch |
269 return apm_->kBadParameterError; | 294 return AudioProcessing::kBadParameterError; |
270 } | 295 } |
271 if (!is_component_enabled()) { | 296 if (!is_component_enabled()) { |
272 return apm_->kNotEnabledError; | 297 return AudioProcessing::kNotEnabledError; |
273 } | 298 } |
274 | 299 |
275 // Get the echo path from the first channel | 300 // Get the echo path from the first channel |
276 Handle* my_handle = static_cast<Handle*>(handle(0)); | 301 Handle* my_handle = static_cast<Handle*>(handle(0)); |
277 int32_t err = WebRtcAecm_GetEchoPath(my_handle, echo_path, size_bytes); | 302 int32_t err = WebRtcAecm_GetEchoPath(my_handle, echo_path, size_bytes); |
278 if (err != 0) | 303 if (err != 0) |
279 return MapError(err); | 304 return MapError(err); |
280 | 305 |
281 return apm_->kNoError; | 306 return AudioProcessing::kNoError; |
282 } | 307 } |
283 | 308 |
284 int EchoControlMobileImpl::Initialize() { | 309 int EchoControlMobileImpl::Initialize() { |
285 if (!is_component_enabled()) { | 310 { |
286 return apm_->kNoError; | 311 rtc::CritScope cs_capture(crit_capture_); |
| 312 if (!is_component_enabled()) { |
| 313 return AudioProcessing::kNoError; |
| 314 } |
287 } | 315 } |
288 | 316 |
289 if (apm_->proc_sample_rate_hz() > apm_->kSampleRate16kHz) { | 317 if (apm_->proc_sample_rate_hz() > AudioProcessing::kSampleRate16kHz) { |
290 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; | 318 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; |
291 return apm_->kBadSampleRateError; | 319 return AudioProcessing::kBadSampleRateError; |
292 } | 320 } |
293 | 321 |
294 int err = ProcessingComponent::Initialize(); | 322 int err = ProcessingComponent::Initialize(); |
295 if (err != apm_->kNoError) { | 323 if (err != AudioProcessing::kNoError) { |
296 return err; | 324 return err; |
297 } | 325 } |
298 | 326 |
299 AllocateRenderQueue(); | 327 AllocateRenderQueue(); |
300 | 328 |
301 return apm_->kNoError; | 329 return AudioProcessing::kNoError; |
302 } | 330 } |
303 | 331 |
304 void EchoControlMobileImpl::AllocateRenderQueue() { | 332 void EchoControlMobileImpl::AllocateRenderQueue() { |
305 const size_t new_render_queue_element_max_size = std::max<size_t>( | 333 const size_t new_render_queue_element_max_size = std::max<size_t>( |
306 static_cast<size_t>(1), | 334 static_cast<size_t>(1), |
307 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); | 335 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); |
308 | 336 |
| 337 rtc::CritScope cs_render(crit_render_); |
| 338 rtc::CritScope cs_capture(crit_capture_); |
| 339 |
309 // Reallocate the queue if the queue item size is too small to fit the | 340 // Reallocate the queue if the queue item size is too small to fit the |
310 // data to put in the queue. | 341 // data to put in the queue. |
311 if (render_queue_element_max_size_ < new_render_queue_element_max_size) { | 342 if (render_queue_element_max_size_ < new_render_queue_element_max_size) { |
312 render_queue_element_max_size_ = new_render_queue_element_max_size; | 343 render_queue_element_max_size_ = new_render_queue_element_max_size; |
313 | 344 |
314 std::vector<int16_t> template_queue_element(render_queue_element_max_size_); | 345 std::vector<int16_t> template_queue_element(render_queue_element_max_size_); |
315 | 346 |
316 render_signal_queue_.reset( | 347 render_signal_queue_.reset( |
317 new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>( | 348 new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>( |
318 kMaxNumFramesToBuffer, template_queue_element, | 349 kMaxNumFramesToBuffer, template_queue_element, |
319 RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_))); | 350 RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_))); |
320 | 351 |
321 render_queue_buffer_.resize(render_queue_element_max_size_); | 352 render_queue_buffer_.resize(render_queue_element_max_size_); |
322 capture_queue_buffer_.resize(render_queue_element_max_size_); | 353 capture_queue_buffer_.resize(render_queue_element_max_size_); |
323 } else { | 354 } else { |
324 render_signal_queue_->Clear(); | 355 render_signal_queue_->Clear(); |
325 } | 356 } |
326 } | 357 } |
327 | 358 |
328 void* EchoControlMobileImpl::CreateHandle() const { | 359 void* EchoControlMobileImpl::CreateHandle() const { |
329 return WebRtcAecm_Create(); | 360 return WebRtcAecm_Create(); |
330 } | 361 } |
331 | 362 |
332 void EchoControlMobileImpl::DestroyHandle(void* handle) const { | 363 void EchoControlMobileImpl::DestroyHandle(void* handle) const { |
| 364 // This method is only called in a non-concurrent manner during APM |
| 365 // destruction. |
333 WebRtcAecm_Free(static_cast<Handle*>(handle)); | 366 WebRtcAecm_Free(static_cast<Handle*>(handle)); |
334 } | 367 } |
335 | 368 |
336 int EchoControlMobileImpl::InitializeHandle(void* handle) const { | 369 int EchoControlMobileImpl::InitializeHandle(void* handle) const { |
| 370 rtc::CritScope cs_render(crit_render_); |
| 371 rtc::CritScope cs_capture(crit_capture_); |
337 assert(handle != NULL); | 372 assert(handle != NULL); |
338 Handle* my_handle = static_cast<Handle*>(handle); | 373 Handle* my_handle = static_cast<Handle*>(handle); |
339 if (WebRtcAecm_Init(my_handle, apm_->proc_sample_rate_hz()) != 0) { | 374 if (WebRtcAecm_Init(my_handle, apm_->proc_sample_rate_hz()) != 0) { |
340 return GetHandleError(my_handle); | 375 return GetHandleError(my_handle); |
341 } | 376 } |
342 if (external_echo_path_ != NULL) { | 377 if (external_echo_path_ != NULL) { |
343 if (WebRtcAecm_InitEchoPath(my_handle, | 378 if (WebRtcAecm_InitEchoPath(my_handle, |
344 external_echo_path_, | 379 external_echo_path_, |
345 echo_path_size_bytes()) != 0) { | 380 echo_path_size_bytes()) != 0) { |
346 return GetHandleError(my_handle); | 381 return GetHandleError(my_handle); |
347 } | 382 } |
348 } | 383 } |
349 | 384 |
350 return apm_->kNoError; | 385 return AudioProcessing::kNoError; |
351 } | 386 } |
352 | 387 |
353 int EchoControlMobileImpl::ConfigureHandle(void* handle) const { | 388 int EchoControlMobileImpl::ConfigureHandle(void* handle) const { |
| 389 rtc::CritScope cs_render(crit_render_); |
| 390 rtc::CritScope cs_capture(crit_capture_); |
354 AecmConfig config; | 391 AecmConfig config; |
355 config.cngMode = comfort_noise_enabled_; | 392 config.cngMode = comfort_noise_enabled_; |
356 config.echoMode = MapSetting(routing_mode_); | 393 config.echoMode = MapSetting(routing_mode_); |
357 | 394 |
358 return WebRtcAecm_set_config(static_cast<Handle*>(handle), config); | 395 return WebRtcAecm_set_config(static_cast<Handle*>(handle), config); |
359 } | 396 } |
360 | 397 |
361 int EchoControlMobileImpl::num_handles_required() const { | 398 int EchoControlMobileImpl::num_handles_required() const { |
| 399 // Not locked as it only relies on APM public API which is threadsafe. |
362 return apm_->num_output_channels() * | 400 return apm_->num_output_channels() * |
363 apm_->num_reverse_channels(); | 401 apm_->num_reverse_channels(); |
364 } | 402 } |
365 | 403 |
366 int EchoControlMobileImpl::GetHandleError(void* handle) const { | 404 int EchoControlMobileImpl::GetHandleError(void* handle) const { |
| 405 // Not locked as it does not rely on anything in the state. |
367 assert(handle != NULL); | 406 assert(handle != NULL); |
368 return AudioProcessing::kUnspecifiedError; | 407 return AudioProcessing::kUnspecifiedError; |
369 } | 408 } |
370 } // namespace webrtc | 409 } // namespace webrtc |
OLD | NEW |