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_cancellation_impl.h" | 11 #include "webrtc/modules/audio_processing/echo_cancellation_impl.h" |
12 | 12 |
13 #include <assert.h> | 13 #include <assert.h> |
14 #include <string.h> | 14 #include <string.h> |
15 | 15 |
16 extern "C" { | 16 extern "C" { |
17 #include "webrtc/modules/audio_processing/aec/aec_core.h" | 17 #include "webrtc/modules/audio_processing/aec/aec_core.h" |
18 } | 18 } |
19 #include "webrtc/modules/audio_processing/aec/echo_cancellation.h" | 19 #include "webrtc/modules/audio_processing/aec/echo_cancellation.h" |
20 #include "webrtc/modules/audio_processing/audio_buffer.h" | 20 #include "webrtc/modules/audio_processing/audio_buffer.h" |
21 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
22 | 21 |
23 namespace webrtc { | 22 namespace webrtc { |
24 | 23 |
25 typedef void Handle; | 24 typedef void Handle; |
26 | 25 |
27 namespace { | 26 namespace { |
28 int16_t MapSetting(EchoCancellation::SuppressionLevel level) { | 27 int16_t MapSetting(EchoCancellation::SuppressionLevel level) { |
29 switch (level) { | 28 switch (level) { |
30 case EchoCancellation::kLowSuppression: | 29 case EchoCancellation::kLowSuppression: |
31 return kAecNlpConservative; | 30 return kAecNlpConservative; |
(...skipping 24 matching lines...) Expand all Loading... |
56 | 55 |
57 // Maximum length that a frame of samples can have. | 56 // Maximum length that a frame of samples can have. |
58 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; | 57 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; |
59 // Maximum number of frames to buffer in the render queue. | 58 // Maximum number of frames to buffer in the render queue. |
60 // TODO(peah): Decrease this once we properly handle hugely unbalanced | 59 // TODO(peah): Decrease this once we properly handle hugely unbalanced |
61 // reverse and forward call numbers. | 60 // reverse and forward call numbers. |
62 static const size_t kMaxNumFramesToBuffer = 100; | 61 static const size_t kMaxNumFramesToBuffer = 100; |
63 } // namespace | 62 } // namespace |
64 | 63 |
65 EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm, | 64 EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm, |
66 CriticalSectionWrapper* crit) | 65 rtc::CriticalSection* crit_render, |
| 66 rtc::CriticalSection* crit_capture) |
67 : ProcessingComponent(), | 67 : ProcessingComponent(), |
68 apm_(apm), | 68 apm_(apm), |
69 crit_(crit), | 69 crit_render_(crit_render), |
| 70 crit_capture_(crit_capture), |
70 drift_compensation_enabled_(false), | 71 drift_compensation_enabled_(false), |
71 metrics_enabled_(false), | 72 metrics_enabled_(false), |
72 suppression_level_(kModerateSuppression), | 73 suppression_level_(kModerateSuppression), |
73 stream_drift_samples_(0), | 74 stream_drift_samples_(0), |
74 was_stream_drift_set_(false), | 75 was_stream_drift_set_(false), |
75 stream_has_echo_(false), | 76 stream_has_echo_(false), |
76 delay_logging_enabled_(false), | 77 delay_logging_enabled_(false), |
77 extended_filter_enabled_(false), | 78 extended_filter_enabled_(false), |
78 delay_agnostic_enabled_(false), | 79 delay_agnostic_enabled_(false), |
79 render_queue_element_max_size_(0) {} | 80 render_queue_element_max_size_(0) { |
| 81 RTC_DCHECK(apm); |
| 82 RTC_DCHECK(crit_render); |
| 83 RTC_DCHECK(crit_capture); |
| 84 } |
80 | 85 |
81 EchoCancellationImpl::~EchoCancellationImpl() {} | 86 EchoCancellationImpl::~EchoCancellationImpl() {} |
82 | 87 |
83 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { | 88 int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { |
| 89 rtc::CritScope cs_render(crit_render_); |
84 if (!is_component_enabled()) { | 90 if (!is_component_enabled()) { |
85 return apm_->kNoError; | 91 return AudioProcessing::kNoError; |
86 } | 92 } |
87 | 93 |
88 assert(audio->num_frames_per_band() <= 160); | 94 assert(audio->num_frames_per_band() <= 160); |
89 assert(audio->num_channels() == apm_->num_reverse_channels()); | 95 assert(audio->num_channels() == apm_->num_reverse_channels()); |
90 | 96 |
91 int err = apm_->kNoError; | 97 int err = AudioProcessing::kNoError; |
92 | 98 |
93 // The ordering convention must be followed to pass to the correct AEC. | 99 // The ordering convention must be followed to pass to the correct AEC. |
94 size_t handle_index = 0; | 100 size_t handle_index = 0; |
95 render_queue_buffer_.clear(); | 101 render_queue_buffer_.clear(); |
96 for (int i = 0; i < apm_->num_output_channels(); i++) { | 102 for (int i = 0; i < apm_->num_output_channels(); i++) { |
97 for (int j = 0; j < audio->num_channels(); j++) { | 103 for (int j = 0; j < audio->num_channels(); j++) { |
98 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); | 104 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); |
99 // Retrieve any error code produced by the buffering of the farend | 105 // Retrieve any error code produced by the buffering of the farend |
100 // signal | 106 // signal |
101 err = WebRtcAec_GetBufferFarendError( | 107 err = WebRtcAec_GetBufferFarendError( |
102 my_handle, audio->split_bands_const_f(j)[kBand0To8kHz], | 108 my_handle, audio->split_bands_const_f(j)[kBand0To8kHz], |
103 audio->num_frames_per_band()); | 109 audio->num_frames_per_band()); |
104 | 110 |
105 if (err != apm_->kNoError) { | 111 if (err != AudioProcessing::kNoError) { |
106 return MapError(err); // TODO(ajm): warning possible? | 112 return MapError(err); // TODO(ajm): warning possible? |
107 } | 113 } |
108 | 114 |
109 // Buffer the samples in the render queue. | 115 // Buffer the samples in the render queue. |
110 render_queue_buffer_.insert(render_queue_buffer_.end(), | 116 render_queue_buffer_.insert(render_queue_buffer_.end(), |
111 audio->split_bands_const_f(j)[kBand0To8kHz], | 117 audio->split_bands_const_f(j)[kBand0To8kHz], |
112 (audio->split_bands_const_f(j)[kBand0To8kHz] + | 118 (audio->split_bands_const_f(j)[kBand0To8kHz] + |
113 audio->num_frames_per_band())); | 119 audio->num_frames_per_band())); |
114 } | 120 } |
115 } | 121 } |
116 | 122 |
117 // Insert the samples into the queue. | 123 // Insert the samples into the queue. |
118 if (!render_signal_queue_->Insert(&render_queue_buffer_)) { | 124 if (!render_signal_queue_->Insert(&render_queue_buffer_)) { |
| 125 // The data queue is full and needs to be emptied. |
119 ReadQueuedRenderData(); | 126 ReadQueuedRenderData(); |
120 | 127 |
121 // Retry the insert (should always work). | 128 // Retry the insert (should always work). |
122 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); | 129 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); |
123 } | 130 } |
124 | 131 |
125 return apm_->kNoError; | 132 return AudioProcessing::kNoError; |
126 } | 133 } |
127 | 134 |
128 // Read chunks of data that were received and queued on the render side from | 135 // Read chunks of data that were received and queued on the render side from |
129 // a queue. All the data chunks are buffered into the farend signal of the AEC. | 136 // a queue. All the data chunks are buffered into the farend signal of the AEC. |
130 void EchoCancellationImpl::ReadQueuedRenderData() { | 137 void EchoCancellationImpl::ReadQueuedRenderData() { |
| 138 rtc::CritScope cs_capture(crit_capture_); |
131 if (!is_component_enabled()) { | 139 if (!is_component_enabled()) { |
132 return; | 140 return; |
133 } | 141 } |
134 | 142 |
135 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { | 143 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { |
136 size_t handle_index = 0; | 144 size_t handle_index = 0; |
137 int buffer_index = 0; | 145 int buffer_index = 0; |
138 const int num_frames_per_band = | 146 const int num_frames_per_band = |
139 capture_queue_buffer_.size() / | 147 capture_queue_buffer_.size() / |
140 (apm_->num_output_channels() * apm_->num_reverse_channels()); | 148 (apm_->num_output_channels() * apm_->num_reverse_channels()); |
141 for (int i = 0; i < apm_->num_output_channels(); i++) { | 149 for (int i = 0; i < apm_->num_output_channels(); i++) { |
142 for (int j = 0; j < apm_->num_reverse_channels(); j++) { | 150 for (int j = 0; j < apm_->num_reverse_channels(); j++) { |
143 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); | 151 Handle* my_handle = static_cast<Handle*>(handle(handle_index)); |
144 WebRtcAec_BufferFarend(my_handle, &capture_queue_buffer_[buffer_index], | 152 WebRtcAec_BufferFarend(my_handle, &capture_queue_buffer_[buffer_index], |
145 num_frames_per_band); | 153 num_frames_per_band); |
146 | 154 |
147 buffer_index += num_frames_per_band; | 155 buffer_index += num_frames_per_band; |
148 handle_index++; | 156 handle_index++; |
149 } | 157 } |
150 } | 158 } |
151 } | 159 } |
152 } | 160 } |
153 | 161 |
154 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { | 162 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { |
| 163 rtc::CritScope cs_capture(crit_capture_); |
155 if (!is_component_enabled()) { | 164 if (!is_component_enabled()) { |
156 return apm_->kNoError; | 165 return AudioProcessing::kNoError; |
157 } | 166 } |
158 | 167 |
159 if (!apm_->was_stream_delay_set()) { | 168 if (!apm_->was_stream_delay_set()) { |
160 return apm_->kStreamParameterNotSetError; | 169 return AudioProcessing::kStreamParameterNotSetError; |
161 } | 170 } |
162 | 171 |
163 if (drift_compensation_enabled_ && !was_stream_drift_set_) { | 172 if (drift_compensation_enabled_ && !was_stream_drift_set_) { |
164 return apm_->kStreamParameterNotSetError; | 173 return AudioProcessing::kStreamParameterNotSetError; |
165 } | 174 } |
166 | 175 |
167 assert(audio->num_frames_per_band() <= 160); | 176 assert(audio->num_frames_per_band() <= 160); |
168 assert(audio->num_channels() == apm_->num_output_channels()); | 177 assert(audio->num_channels() == apm_->num_output_channels()); |
169 | 178 |
170 int err = apm_->kNoError; | 179 int err = AudioProcessing::kNoError; |
171 | 180 |
172 // The ordering convention must be followed to pass to the correct AEC. | 181 // The ordering convention must be followed to pass to the correct AEC. |
173 size_t handle_index = 0; | 182 size_t handle_index = 0; |
174 stream_has_echo_ = false; | 183 stream_has_echo_ = false; |
175 for (int i = 0; i < audio->num_channels(); i++) { | 184 for (int i = 0; i < audio->num_channels(); i++) { |
176 for (int j = 0; j < apm_->num_reverse_channels(); j++) { | 185 for (int j = 0; j < apm_->num_reverse_channels(); j++) { |
177 Handle* my_handle = handle(handle_index); | 186 Handle* my_handle = handle(handle_index); |
178 err = WebRtcAec_Process( | 187 err = WebRtcAec_Process(my_handle, audio->split_bands_const_f(i), |
179 my_handle, | 188 audio->num_bands(), audio->split_bands_f(i), |
180 audio->split_bands_const_f(i), | 189 audio->num_frames_per_band(), |
181 audio->num_bands(), | 190 apm_->stream_delay_ms(), stream_drift_samples_); |
182 audio->split_bands_f(i), | |
183 audio->num_frames_per_band(), | |
184 apm_->stream_delay_ms(), | |
185 stream_drift_samples_); | |
186 | 191 |
187 if (err != apm_->kNoError) { | 192 if (err != AudioProcessing::kNoError) { |
188 err = MapError(err); | 193 err = MapError(err); |
189 // TODO(ajm): Figure out how to return warnings properly. | 194 // TODO(ajm): Figure out how to return warnings properly. |
190 if (err != apm_->kBadStreamParameterWarning) { | 195 if (err != AudioProcessing::kBadStreamParameterWarning) { |
191 return err; | 196 return err; |
192 } | 197 } |
193 } | 198 } |
194 | 199 |
195 int status = 0; | 200 int status = 0; |
196 err = WebRtcAec_get_echo_status(my_handle, &status); | 201 err = WebRtcAec_get_echo_status(my_handle, &status); |
197 if (err != apm_->kNoError) { | 202 if (err != AudioProcessing::kNoError) { |
198 return MapError(err); | 203 return MapError(err); |
199 } | 204 } |
200 | 205 |
201 if (status == 1) { | 206 if (status == 1) { |
202 stream_has_echo_ = true; | 207 stream_has_echo_ = true; |
203 } | 208 } |
204 | 209 |
205 handle_index++; | 210 handle_index++; |
206 } | 211 } |
207 } | 212 } |
208 | 213 |
209 was_stream_drift_set_ = false; | 214 was_stream_drift_set_ = false; |
210 return apm_->kNoError; | 215 return AudioProcessing::kNoError; |
211 } | 216 } |
212 | 217 |
213 int EchoCancellationImpl::Enable(bool enable) { | 218 int EchoCancellationImpl::Enable(bool enable) { |
214 CriticalSectionScoped crit_scoped(crit_); | 219 // Run in a single-threaded manner. |
| 220 rtc::CritScope cs_render(crit_render_); |
| 221 rtc::CritScope cs_capture(crit_capture_); |
215 // Ensure AEC and AECM are not both enabled. | 222 // Ensure AEC and AECM are not both enabled. |
| 223 // The is_enabled call is safe from a deadlock perspective |
| 224 // as both locks are already held in the correct order. |
216 if (enable && apm_->echo_control_mobile()->is_enabled()) { | 225 if (enable && apm_->echo_control_mobile()->is_enabled()) { |
217 return apm_->kBadParameterError; | 226 return AudioProcessing::kBadParameterError; |
218 } | 227 } |
219 | 228 |
220 return EnableComponent(enable); | 229 return EnableComponent(enable); |
221 } | 230 } |
222 | 231 |
223 bool EchoCancellationImpl::is_enabled() const { | 232 bool EchoCancellationImpl::is_enabled() const { |
| 233 rtc::CritScope cs(crit_capture_); |
224 return is_component_enabled(); | 234 return is_component_enabled(); |
225 } | 235 } |
226 | 236 |
227 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) { | 237 int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) { |
228 CriticalSectionScoped crit_scoped(crit_); | 238 { |
229 if (MapSetting(level) == -1) { | 239 if (MapSetting(level) == -1) { |
230 return apm_->kBadParameterError; | 240 return AudioProcessing::kBadParameterError; |
| 241 } |
| 242 rtc::CritScope cs(crit_capture_); |
| 243 suppression_level_ = level; |
231 } | 244 } |
232 | |
233 suppression_level_ = level; | |
234 return Configure(); | 245 return Configure(); |
235 } | 246 } |
236 | 247 |
237 EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level() | 248 EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level() |
238 const { | 249 const { |
| 250 rtc::CritScope cs(crit_capture_); |
239 return suppression_level_; | 251 return suppression_level_; |
240 } | 252 } |
241 | 253 |
242 int EchoCancellationImpl::enable_drift_compensation(bool enable) { | 254 int EchoCancellationImpl::enable_drift_compensation(bool enable) { |
243 CriticalSectionScoped crit_scoped(crit_); | 255 { |
244 drift_compensation_enabled_ = enable; | 256 rtc::CritScope cs(crit_capture_); |
| 257 drift_compensation_enabled_ = enable; |
| 258 } |
245 return Configure(); | 259 return Configure(); |
246 } | 260 } |
247 | 261 |
248 bool EchoCancellationImpl::is_drift_compensation_enabled() const { | 262 bool EchoCancellationImpl::is_drift_compensation_enabled() const { |
| 263 rtc::CritScope cs(crit_capture_); |
249 return drift_compensation_enabled_; | 264 return drift_compensation_enabled_; |
250 } | 265 } |
251 | 266 |
252 void EchoCancellationImpl::set_stream_drift_samples(int drift) { | 267 void EchoCancellationImpl::set_stream_drift_samples(int drift) { |
| 268 rtc::CritScope cs(crit_capture_); |
253 was_stream_drift_set_ = true; | 269 was_stream_drift_set_ = true; |
254 stream_drift_samples_ = drift; | 270 stream_drift_samples_ = drift; |
255 } | 271 } |
256 | 272 |
257 int EchoCancellationImpl::stream_drift_samples() const { | 273 int EchoCancellationImpl::stream_drift_samples() const { |
| 274 rtc::CritScope cs(crit_capture_); |
258 return stream_drift_samples_; | 275 return stream_drift_samples_; |
259 } | 276 } |
260 | 277 |
261 int EchoCancellationImpl::enable_metrics(bool enable) { | 278 int EchoCancellationImpl::enable_metrics(bool enable) { |
262 CriticalSectionScoped crit_scoped(crit_); | 279 { |
263 metrics_enabled_ = enable; | 280 rtc::CritScope cs(crit_capture_); |
| 281 metrics_enabled_ = enable; |
| 282 } |
264 return Configure(); | 283 return Configure(); |
265 } | 284 } |
266 | 285 |
267 bool EchoCancellationImpl::are_metrics_enabled() const { | 286 bool EchoCancellationImpl::are_metrics_enabled() const { |
| 287 rtc::CritScope cs(crit_capture_); |
268 return metrics_enabled_; | 288 return metrics_enabled_; |
269 } | 289 } |
270 | 290 |
271 // TODO(ajm): we currently just use the metrics from the first AEC. Think more | 291 // TODO(ajm): we currently just use the metrics from the first AEC. Think more |
272 // aboue the best way to extend this to multi-channel. | 292 // aboue the best way to extend this to multi-channel. |
273 int EchoCancellationImpl::GetMetrics(Metrics* metrics) { | 293 int EchoCancellationImpl::GetMetrics(Metrics* metrics) { |
274 CriticalSectionScoped crit_scoped(crit_); | 294 rtc::CritScope cs(crit_capture_); |
275 if (metrics == NULL) { | 295 if (metrics == NULL) { |
276 return apm_->kNullPointerError; | 296 return AudioProcessing::kNullPointerError; |
277 } | 297 } |
278 | 298 |
279 if (!is_component_enabled() || !metrics_enabled_) { | 299 if (!is_component_enabled() || !metrics_enabled_) { |
280 return apm_->kNotEnabledError; | 300 return AudioProcessing::kNotEnabledError; |
281 } | 301 } |
282 | 302 |
283 AecMetrics my_metrics; | 303 AecMetrics my_metrics; |
284 memset(&my_metrics, 0, sizeof(my_metrics)); | 304 memset(&my_metrics, 0, sizeof(my_metrics)); |
285 memset(metrics, 0, sizeof(Metrics)); | 305 memset(metrics, 0, sizeof(Metrics)); |
286 | 306 |
287 Handle* my_handle = static_cast<Handle*>(handle(0)); | 307 Handle* my_handle = static_cast<Handle*>(handle(0)); |
288 int err = WebRtcAec_GetMetrics(my_handle, &my_metrics); | 308 int err = WebRtcAec_GetMetrics(my_handle, &my_metrics); |
289 if (err != apm_->kNoError) { | 309 if (err != AudioProcessing::kNoError) { |
290 return MapError(err); | 310 return MapError(err); |
291 } | 311 } |
292 | 312 |
293 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant; | 313 metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant; |
294 metrics->residual_echo_return_loss.average = my_metrics.rerl.average; | 314 metrics->residual_echo_return_loss.average = my_metrics.rerl.average; |
295 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max; | 315 metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max; |
296 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min; | 316 metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min; |
297 | 317 |
298 metrics->echo_return_loss.instant = my_metrics.erl.instant; | 318 metrics->echo_return_loss.instant = my_metrics.erl.instant; |
299 metrics->echo_return_loss.average = my_metrics.erl.average; | 319 metrics->echo_return_loss.average = my_metrics.erl.average; |
300 metrics->echo_return_loss.maximum = my_metrics.erl.max; | 320 metrics->echo_return_loss.maximum = my_metrics.erl.max; |
301 metrics->echo_return_loss.minimum = my_metrics.erl.min; | 321 metrics->echo_return_loss.minimum = my_metrics.erl.min; |
302 | 322 |
303 metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant; | 323 metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant; |
304 metrics->echo_return_loss_enhancement.average = my_metrics.erle.average; | 324 metrics->echo_return_loss_enhancement.average = my_metrics.erle.average; |
305 metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max; | 325 metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max; |
306 metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min; | 326 metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min; |
307 | 327 |
308 metrics->a_nlp.instant = my_metrics.aNlp.instant; | 328 metrics->a_nlp.instant = my_metrics.aNlp.instant; |
309 metrics->a_nlp.average = my_metrics.aNlp.average; | 329 metrics->a_nlp.average = my_metrics.aNlp.average; |
310 metrics->a_nlp.maximum = my_metrics.aNlp.max; | 330 metrics->a_nlp.maximum = my_metrics.aNlp.max; |
311 metrics->a_nlp.minimum = my_metrics.aNlp.min; | 331 metrics->a_nlp.minimum = my_metrics.aNlp.min; |
312 | 332 |
313 return apm_->kNoError; | 333 return AudioProcessing::kNoError; |
314 } | 334 } |
315 | 335 |
316 bool EchoCancellationImpl::stream_has_echo() const { | 336 bool EchoCancellationImpl::stream_has_echo() const { |
| 337 rtc::CritScope cs(crit_capture_); |
317 return stream_has_echo_; | 338 return stream_has_echo_; |
318 } | 339 } |
319 | 340 |
320 int EchoCancellationImpl::enable_delay_logging(bool enable) { | 341 int EchoCancellationImpl::enable_delay_logging(bool enable) { |
321 CriticalSectionScoped crit_scoped(crit_); | 342 { |
322 delay_logging_enabled_ = enable; | 343 rtc::CritScope cs(crit_capture_); |
| 344 delay_logging_enabled_ = enable; |
| 345 } |
323 return Configure(); | 346 return Configure(); |
324 } | 347 } |
325 | 348 |
326 bool EchoCancellationImpl::is_delay_logging_enabled() const { | 349 bool EchoCancellationImpl::is_delay_logging_enabled() const { |
| 350 rtc::CritScope cs(crit_capture_); |
327 return delay_logging_enabled_; | 351 return delay_logging_enabled_; |
328 } | 352 } |
329 | 353 |
330 bool EchoCancellationImpl::is_delay_agnostic_enabled() const { | 354 bool EchoCancellationImpl::is_delay_agnostic_enabled() const { |
| 355 rtc::CritScope cs(crit_capture_); |
331 return delay_agnostic_enabled_; | 356 return delay_agnostic_enabled_; |
332 } | 357 } |
333 | 358 |
334 bool EchoCancellationImpl::is_extended_filter_enabled() const { | 359 bool EchoCancellationImpl::is_extended_filter_enabled() const { |
| 360 rtc::CritScope cs(crit_capture_); |
335 return extended_filter_enabled_; | 361 return extended_filter_enabled_; |
336 } | 362 } |
337 | 363 |
338 // TODO(bjornv): How should we handle the multi-channel case? | 364 // TODO(bjornv): How should we handle the multi-channel case? |
339 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) { | 365 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) { |
| 366 rtc::CritScope cs(crit_capture_); |
340 float fraction_poor_delays = 0; | 367 float fraction_poor_delays = 0; |
341 return GetDelayMetrics(median, std, &fraction_poor_delays); | 368 return GetDelayMetrics(median, std, &fraction_poor_delays); |
342 } | 369 } |
343 | 370 |
344 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std, | 371 int EchoCancellationImpl::GetDelayMetrics(int* median, int* std, |
345 float* fraction_poor_delays) { | 372 float* fraction_poor_delays) { |
346 CriticalSectionScoped crit_scoped(crit_); | 373 rtc::CritScope cs(crit_capture_); |
347 if (median == NULL) { | 374 if (median == NULL) { |
348 return apm_->kNullPointerError; | 375 return AudioProcessing::kNullPointerError; |
349 } | 376 } |
350 if (std == NULL) { | 377 if (std == NULL) { |
351 return apm_->kNullPointerError; | 378 return AudioProcessing::kNullPointerError; |
352 } | 379 } |
353 | 380 |
354 if (!is_component_enabled() || !delay_logging_enabled_) { | 381 if (!is_component_enabled() || !delay_logging_enabled_) { |
355 return apm_->kNotEnabledError; | 382 return AudioProcessing::kNotEnabledError; |
356 } | 383 } |
357 | 384 |
358 Handle* my_handle = static_cast<Handle*>(handle(0)); | 385 Handle* my_handle = static_cast<Handle*>(handle(0)); |
359 const int err = | 386 const int err = |
360 WebRtcAec_GetDelayMetrics(my_handle, median, std, fraction_poor_delays); | 387 WebRtcAec_GetDelayMetrics(my_handle, median, std, fraction_poor_delays); |
361 if (err != apm_->kNoError) { | 388 if (err != AudioProcessing::kNoError) { |
362 return MapError(err); | 389 return MapError(err); |
363 } | 390 } |
364 | 391 |
365 return apm_->kNoError; | 392 return AudioProcessing::kNoError; |
366 } | 393 } |
367 | 394 |
368 struct AecCore* EchoCancellationImpl::aec_core() const { | 395 struct AecCore* EchoCancellationImpl::aec_core() const { |
369 CriticalSectionScoped crit_scoped(crit_); | 396 rtc::CritScope cs(crit_capture_); |
370 if (!is_component_enabled()) { | 397 if (!is_component_enabled()) { |
371 return NULL; | 398 return NULL; |
372 } | 399 } |
373 Handle* my_handle = static_cast<Handle*>(handle(0)); | 400 Handle* my_handle = static_cast<Handle*>(handle(0)); |
374 return WebRtcAec_aec_core(my_handle); | 401 return WebRtcAec_aec_core(my_handle); |
375 } | 402 } |
376 | 403 |
377 int EchoCancellationImpl::Initialize() { | 404 int EchoCancellationImpl::Initialize() { |
378 int err = ProcessingComponent::Initialize(); | 405 int err = ProcessingComponent::Initialize(); |
379 if (err != apm_->kNoError || !is_component_enabled()) { | 406 { |
380 return err; | 407 rtc::CritScope cs(crit_capture_); |
| 408 if (err != AudioProcessing::kNoError || !is_component_enabled()) { |
| 409 return err; |
| 410 } |
381 } | 411 } |
382 | 412 |
383 AllocateRenderQueue(); | 413 AllocateRenderQueue(); |
384 | 414 |
385 return apm_->kNoError; | 415 return AudioProcessing::kNoError; |
386 } | 416 } |
387 | 417 |
388 void EchoCancellationImpl::AllocateRenderQueue() { | 418 void EchoCancellationImpl::AllocateRenderQueue() { |
389 const size_t new_render_queue_element_max_size = std::max<size_t>( | 419 const size_t new_render_queue_element_max_size = std::max<size_t>( |
390 static_cast<size_t>(1), | 420 static_cast<size_t>(1), |
391 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); | 421 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); |
392 | 422 |
| 423 rtc::CritScope cs_render(crit_render_); |
| 424 rtc::CritScope cs_capture(crit_capture_); |
| 425 |
393 // Reallocate the queue if the queue item size is too small to fit the | 426 // Reallocate the queue if the queue item size is too small to fit the |
394 // data to put in the queue. | 427 // data to put in the queue. |
395 if (render_queue_element_max_size_ < new_render_queue_element_max_size) { | 428 if (render_queue_element_max_size_ < new_render_queue_element_max_size) { |
396 render_queue_element_max_size_ = new_render_queue_element_max_size; | 429 render_queue_element_max_size_ = new_render_queue_element_max_size; |
397 | 430 |
398 std::vector<float> template_queue_element(render_queue_element_max_size_); | 431 std::vector<float> template_queue_element(render_queue_element_max_size_); |
399 | 432 |
400 render_signal_queue_.reset( | 433 render_signal_queue_.reset( |
401 new SwapQueue<std::vector<float>, RenderQueueItemVerifier<float>>( | 434 new SwapQueue<std::vector<float>, RenderQueueItemVerifier<float>>( |
402 kMaxNumFramesToBuffer, template_queue_element, | 435 kMaxNumFramesToBuffer, template_queue_element, |
403 RenderQueueItemVerifier<float>(render_queue_element_max_size_))); | 436 RenderQueueItemVerifier<float>(render_queue_element_max_size_))); |
404 | 437 |
405 render_queue_buffer_.resize(render_queue_element_max_size_); | 438 render_queue_buffer_.resize(render_queue_element_max_size_); |
406 capture_queue_buffer_.resize(render_queue_element_max_size_); | 439 capture_queue_buffer_.resize(render_queue_element_max_size_); |
407 } else { | 440 } else { |
408 render_signal_queue_->Clear(); | 441 render_signal_queue_->Clear(); |
409 } | 442 } |
410 } | 443 } |
411 | 444 |
412 void EchoCancellationImpl::SetExtraOptions(const Config& config) { | 445 void EchoCancellationImpl::SetExtraOptions(const Config& config) { |
413 extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled; | 446 { |
414 delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled; | 447 rtc::CritScope cs(crit_capture_); |
| 448 extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled; |
| 449 delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled; |
| 450 } |
415 Configure(); | 451 Configure(); |
416 } | 452 } |
417 | 453 |
418 void* EchoCancellationImpl::CreateHandle() const { | 454 void* EchoCancellationImpl::CreateHandle() const { |
419 return WebRtcAec_Create(); | 455 return WebRtcAec_Create(); |
420 } | 456 } |
421 | 457 |
422 void EchoCancellationImpl::DestroyHandle(void* handle) const { | 458 void EchoCancellationImpl::DestroyHandle(void* handle) const { |
423 assert(handle != NULL); | 459 assert(handle != NULL); |
424 WebRtcAec_Free(static_cast<Handle*>(handle)); | 460 WebRtcAec_Free(static_cast<Handle*>(handle)); |
425 } | 461 } |
426 | 462 |
427 int EchoCancellationImpl::InitializeHandle(void* handle) const { | 463 int EchoCancellationImpl::InitializeHandle(void* handle) const { |
| 464 // Not locked as it only relies on APM public API which is threadsafe. |
| 465 |
428 assert(handle != NULL); | 466 assert(handle != NULL); |
429 // TODO(ajm): Drift compensation is disabled in practice. If restored, it | 467 // TODO(ajm): Drift compensation is disabled in practice. If restored, it |
430 // should be managed internally and not depend on the hardware sample rate. | 468 // should be managed internally and not depend on the hardware sample rate. |
431 // For now, just hardcode a 48 kHz value. | 469 // For now, just hardcode a 48 kHz value. |
432 return WebRtcAec_Init(static_cast<Handle*>(handle), | 470 return WebRtcAec_Init(static_cast<Handle*>(handle), |
433 apm_->proc_sample_rate_hz(), | 471 apm_->proc_sample_rate_hz(), 48000); |
434 48000); | |
435 } | 472 } |
436 | 473 |
437 int EchoCancellationImpl::ConfigureHandle(void* handle) const { | 474 int EchoCancellationImpl::ConfigureHandle(void* handle) const { |
| 475 rtc::CritScope cs_render(crit_render_); |
| 476 rtc::CritScope cs_capture(crit_capture_); |
438 assert(handle != NULL); | 477 assert(handle != NULL); |
439 AecConfig config; | 478 AecConfig config; |
440 config.metricsMode = metrics_enabled_; | 479 config.metricsMode = metrics_enabled_; |
441 config.nlpMode = MapSetting(suppression_level_); | 480 config.nlpMode = MapSetting(suppression_level_); |
442 config.skewMode = drift_compensation_enabled_; | 481 config.skewMode = drift_compensation_enabled_; |
443 config.delay_logging = delay_logging_enabled_; | 482 config.delay_logging = delay_logging_enabled_; |
444 | |
445 WebRtcAec_enable_extended_filter( | 483 WebRtcAec_enable_extended_filter( |
446 WebRtcAec_aec_core(static_cast<Handle*>(handle)), | 484 WebRtcAec_aec_core(static_cast<Handle*>(handle)), |
447 extended_filter_enabled_ ? 1 : 0); | 485 extended_filter_enabled_ ? 1 : 0); |
448 WebRtcAec_enable_delay_agnostic( | 486 WebRtcAec_enable_delay_agnostic( |
449 WebRtcAec_aec_core(static_cast<Handle*>(handle)), | 487 WebRtcAec_aec_core(static_cast<Handle*>(handle)), |
450 delay_agnostic_enabled_ ? 1 : 0); | 488 delay_agnostic_enabled_ ? 1 : 0); |
451 return WebRtcAec_set_config(static_cast<Handle*>(handle), config); | 489 return WebRtcAec_set_config(static_cast<Handle*>(handle), config); |
452 } | 490 } |
453 | 491 |
454 int EchoCancellationImpl::num_handles_required() const { | 492 int EchoCancellationImpl::num_handles_required() const { |
| 493 // Not locked as it only relies on APM public API which is threadsafe. |
455 return apm_->num_output_channels() * | 494 return apm_->num_output_channels() * |
456 apm_->num_reverse_channels(); | 495 apm_->num_reverse_channels(); |
457 } | 496 } |
458 | 497 |
459 int EchoCancellationImpl::GetHandleError(void* handle) const { | 498 int EchoCancellationImpl::GetHandleError(void* handle) const { |
| 499 // Not locked as it does not rely on anything in the state. |
460 assert(handle != NULL); | 500 assert(handle != NULL); |
461 return AudioProcessing::kUnspecifiedError; | 501 return AudioProcessing::kUnspecifiedError; |
462 } | 502 } |
463 } // namespace webrtc | 503 } // namespace webrtc |
OLD | NEW |