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 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 // Maximum number of frames to buffer in the render queue. | 57 // Maximum number of frames to buffer in the render queue. |
58 // TODO(peah): Decrease this once we properly handle hugely unbalanced | 58 // TODO(peah): Decrease this once we properly handle hugely unbalanced |
59 // reverse and forward call numbers. | 59 // reverse and forward call numbers. |
60 static const size_t kMaxNumFramesToBuffer = 100; | 60 static const size_t kMaxNumFramesToBuffer = 100; |
61 } // namespace | 61 } // namespace |
62 | 62 |
63 size_t EchoControlMobile::echo_path_size_bytes() { | 63 size_t EchoControlMobile::echo_path_size_bytes() { |
64 return WebRtcAecm_echo_path_size_bytes(); | 64 return WebRtcAecm_echo_path_size_bytes(); |
65 } | 65 } |
66 | 66 |
| 67 struct EchoControlMobileImpl::StreamProperties { |
| 68 StreamProperties() = delete; |
| 69 StreamProperties(int sample_rate_hz, |
| 70 size_t num_reverse_channels, |
| 71 size_t num_output_channels) |
| 72 : sample_rate_hz(sample_rate_hz), |
| 73 num_reverse_channels(num_reverse_channels), |
| 74 num_output_channels(num_output_channels) {} |
| 75 |
| 76 int sample_rate_hz; |
| 77 size_t num_reverse_channels; |
| 78 size_t num_output_channels; |
| 79 }; |
| 80 |
67 class EchoControlMobileImpl::Canceller { | 81 class EchoControlMobileImpl::Canceller { |
68 public: | 82 public: |
69 Canceller() { | 83 Canceller() { |
70 state_ = WebRtcAecm_Create(); | 84 state_ = WebRtcAecm_Create(); |
71 RTC_CHECK(state_); | 85 RTC_CHECK(state_); |
72 } | 86 } |
73 | 87 |
74 ~Canceller() { | 88 ~Canceller() { |
75 RTC_DCHECK(state_); | 89 RTC_DCHECK(state_); |
76 WebRtcAecm_Free(state_); | 90 WebRtcAecm_Free(state_); |
(...skipping 15 matching lines...) Expand all Loading... |
92 echo_path_size_bytes); | 106 echo_path_size_bytes); |
93 RTC_DCHECK_EQ(AudioProcessing::kNoError, error); | 107 RTC_DCHECK_EQ(AudioProcessing::kNoError, error); |
94 } | 108 } |
95 } | 109 } |
96 | 110 |
97 private: | 111 private: |
98 void* state_; | 112 void* state_; |
99 RTC_DISALLOW_COPY_AND_ASSIGN(Canceller); | 113 RTC_DISALLOW_COPY_AND_ASSIGN(Canceller); |
100 }; | 114 }; |
101 | 115 |
102 EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessing* apm, | 116 EchoControlMobileImpl::EchoControlMobileImpl(rtc::CriticalSection* crit_render, |
103 rtc::CriticalSection* crit_render, | |
104 rtc::CriticalSection* crit_capture) | 117 rtc::CriticalSection* crit_capture) |
105 : apm_(apm), | 118 : crit_render_(crit_render), |
106 crit_render_(crit_render), | |
107 crit_capture_(crit_capture), | 119 crit_capture_(crit_capture), |
108 routing_mode_(kSpeakerphone), | 120 routing_mode_(kSpeakerphone), |
109 comfort_noise_enabled_(true), | 121 comfort_noise_enabled_(true), |
110 external_echo_path_(NULL), | 122 external_echo_path_(NULL), |
111 render_queue_element_max_size_(0) { | 123 render_queue_element_max_size_(0) { |
112 RTC_DCHECK(apm); | |
113 RTC_DCHECK(crit_render); | 124 RTC_DCHECK(crit_render); |
114 RTC_DCHECK(crit_capture); | 125 RTC_DCHECK(crit_capture); |
115 } | 126 } |
116 | 127 |
117 EchoControlMobileImpl::~EchoControlMobileImpl() { | 128 EchoControlMobileImpl::~EchoControlMobileImpl() { |
118 if (external_echo_path_ != NULL) { | 129 if (external_echo_path_ != NULL) { |
119 delete [] external_echo_path_; | 130 delete [] external_echo_path_; |
120 external_echo_path_ = NULL; | 131 external_echo_path_ = NULL; |
121 } | 132 } |
122 } | 133 } |
123 | 134 |
124 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { | 135 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { |
125 rtc::CritScope cs_render(crit_render_); | 136 rtc::CritScope cs_render(crit_render_); |
126 if (!enabled_) { | 137 if (!enabled_) { |
127 return AudioProcessing::kNoError; | 138 return AudioProcessing::kNoError; |
128 } | 139 } |
129 | 140 |
130 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 141 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
131 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_reverse_channels()); | 142 RTC_DCHECK_EQ(audio->num_channels(), |
132 RTC_DCHECK_GE(cancellers_.size(), | 143 stream_properties_->num_reverse_channels); |
133 apm_->num_output_channels() * audio->num_channels()); | 144 RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_output_channels * |
| 145 audio->num_channels()); |
134 | 146 |
135 int err = AudioProcessing::kNoError; | 147 int err = AudioProcessing::kNoError; |
136 // The ordering convention must be followed to pass to the correct AECM. | 148 // The ordering convention must be followed to pass to the correct AECM. |
137 render_queue_buffer_.clear(); | 149 render_queue_buffer_.clear(); |
138 int render_channel = 0; | 150 int render_channel = 0; |
139 for (auto& canceller : cancellers_) { | 151 for (auto& canceller : cancellers_) { |
140 err = WebRtcAecm_GetBufferFarendError( | 152 err = WebRtcAecm_GetBufferFarendError( |
141 canceller->state(), | 153 canceller->state(), |
142 audio->split_bands_const(render_channel)[kBand0To8kHz], | 154 audio->split_bands_const(render_channel)[kBand0To8kHz], |
143 audio->num_frames_per_band()); | 155 audio->num_frames_per_band()); |
(...skipping 26 matching lines...) Expand all Loading... |
170 // a queue. All the data chunks are buffered into the farend signal of the AEC. | 182 // a queue. All the data chunks are buffered into the farend signal of the AEC. |
171 void EchoControlMobileImpl::ReadQueuedRenderData() { | 183 void EchoControlMobileImpl::ReadQueuedRenderData() { |
172 rtc::CritScope cs_capture(crit_capture_); | 184 rtc::CritScope cs_capture(crit_capture_); |
173 | 185 |
174 if (!enabled_) { | 186 if (!enabled_) { |
175 return; | 187 return; |
176 } | 188 } |
177 | 189 |
178 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { | 190 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { |
179 size_t buffer_index = 0; | 191 size_t buffer_index = 0; |
180 size_t num_frames_per_band = | 192 size_t num_frames_per_band = capture_queue_buffer_.size() / |
181 capture_queue_buffer_.size() / | 193 (stream_properties_->num_output_channels * |
182 (apm_->num_output_channels() * apm_->num_reverse_channels()); | 194 stream_properties_->num_reverse_channels); |
183 | 195 |
184 for (auto& canceller : cancellers_) { | 196 for (auto& canceller : cancellers_) { |
185 WebRtcAecm_BufferFarend(canceller->state(), | 197 WebRtcAecm_BufferFarend(canceller->state(), |
186 &capture_queue_buffer_[buffer_index], | 198 &capture_queue_buffer_[buffer_index], |
187 num_frames_per_band); | 199 num_frames_per_band); |
188 | 200 |
189 buffer_index += num_frames_per_band; | 201 buffer_index += num_frames_per_band; |
190 } | 202 } |
191 } | 203 } |
192 } | 204 } |
193 | 205 |
194 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { | 206 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio, |
| 207 int stream_delay_ms) { |
195 rtc::CritScope cs_capture(crit_capture_); | 208 rtc::CritScope cs_capture(crit_capture_); |
196 if (!enabled_) { | 209 if (!enabled_) { |
197 return AudioProcessing::kNoError; | 210 return AudioProcessing::kNoError; |
198 } | 211 } |
199 | 212 |
200 if (!apm_->was_stream_delay_set()) { | |
201 return AudioProcessing::kStreamParameterNotSetError; | |
202 } | |
203 | |
204 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 213 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
205 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_output_channels()); | 214 RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_output_channels); |
206 RTC_DCHECK_GE(cancellers_.size(), | 215 RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_reverse_channels * |
207 apm_->num_reverse_channels() * audio->num_channels()); | 216 audio->num_channels()); |
208 | 217 |
209 int err = AudioProcessing::kNoError; | 218 int err = AudioProcessing::kNoError; |
210 | 219 |
211 // The ordering convention must be followed to pass to the correct AECM. | 220 // The ordering convention must be followed to pass to the correct AECM. |
212 size_t handle_index = 0; | 221 size_t handle_index = 0; |
213 for (size_t capture = 0; capture < audio->num_channels(); ++capture) { | 222 for (size_t capture = 0; capture < audio->num_channels(); ++capture) { |
214 // TODO(ajm): improve how this works, possibly inside AECM. | 223 // TODO(ajm): improve how this works, possibly inside AECM. |
215 // This is kind of hacked up. | 224 // This is kind of hacked up. |
216 const int16_t* noisy = audio->low_pass_reference(capture); | 225 const int16_t* noisy = audio->low_pass_reference(capture); |
217 const int16_t* clean = audio->split_bands_const(capture)[kBand0To8kHz]; | 226 const int16_t* clean = audio->split_bands_const(capture)[kBand0To8kHz]; |
218 if (noisy == NULL) { | 227 if (noisy == NULL) { |
219 noisy = clean; | 228 noisy = clean; |
220 clean = NULL; | 229 clean = NULL; |
221 } | 230 } |
222 for (size_t render = 0; render < apm_->num_reverse_channels(); ++render) { | 231 for (size_t render = 0; render < stream_properties_->num_reverse_channels; |
| 232 ++render) { |
223 err = WebRtcAecm_Process(cancellers_[handle_index]->state(), noisy, clean, | 233 err = WebRtcAecm_Process(cancellers_[handle_index]->state(), noisy, clean, |
224 audio->split_bands(capture)[kBand0To8kHz], | 234 audio->split_bands(capture)[kBand0To8kHz], |
225 audio->num_frames_per_band(), | 235 audio->num_frames_per_band(), stream_delay_ms); |
226 apm_->stream_delay_ms()); | |
227 | 236 |
228 if (err != AudioProcessing::kNoError) { | 237 if (err != AudioProcessing::kNoError) { |
229 return MapError(err); | 238 return MapError(err); |
230 } | 239 } |
231 | 240 |
232 ++handle_index; | 241 ++handle_index; |
233 } | 242 } |
234 } | 243 } |
235 return AudioProcessing::kNoError; | 244 return AudioProcessing::kNoError; |
236 } | 245 } |
237 | 246 |
238 int EchoControlMobileImpl::Enable(bool enable) { | 247 int EchoControlMobileImpl::Enable(bool enable) { |
239 // Ensure AEC and AECM are not both enabled. | 248 // Ensure AEC and AECM are not both enabled. |
240 rtc::CritScope cs_render(crit_render_); | 249 rtc::CritScope cs_render(crit_render_); |
241 rtc::CritScope cs_capture(crit_capture_); | 250 rtc::CritScope cs_capture(crit_capture_); |
242 // The is_enabled call is safe from a deadlock perspective | |
243 // as both locks are allready held in the correct order. | |
244 if (enable && apm_->echo_cancellation()->is_enabled()) { | |
245 return AudioProcessing::kBadParameterError; | |
246 } | |
247 | 251 |
248 if (enable && | 252 if (enable && |
249 apm_->proc_sample_rate_hz() > AudioProcessing::kSampleRate16kHz) { | 253 stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) { |
250 return AudioProcessing::kBadSampleRateError; | 254 return AudioProcessing::kBadSampleRateError; |
251 } | 255 } |
252 | 256 |
253 if (enable && !enabled_) { | 257 if (enable && !enabled_) { |
254 enabled_ = enable; // Must be set before Initialize() is called. | 258 enabled_ = enable; // Must be set before Initialize() is called. |
255 Initialize(); | 259 |
| 260 // TODO(peah): Simplify once the Enable function has been removed from |
| 261 // the public APM API. |
| 262 RTC_DCHECK(stream_properties_); |
| 263 Initialize(stream_properties_->sample_rate_hz, |
| 264 stream_properties_->num_reverse_channels, |
| 265 stream_properties_->num_output_channels); |
256 } else { | 266 } else { |
257 enabled_ = enable; | 267 enabled_ = enable; |
258 } | 268 } |
259 return AudioProcessing::kNoError; | 269 return AudioProcessing::kNoError; |
260 } | 270 } |
261 | 271 |
262 bool EchoControlMobileImpl::is_enabled() const { | 272 bool EchoControlMobileImpl::is_enabled() const { |
263 rtc::CritScope cs(crit_capture_); | 273 rtc::CritScope cs(crit_capture_); |
264 return enabled_; | 274 return enabled_; |
265 } | 275 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 // Size mismatch | 317 // Size mismatch |
308 return AudioProcessing::kBadParameterError; | 318 return AudioProcessing::kBadParameterError; |
309 } | 319 } |
310 | 320 |
311 if (external_echo_path_ == NULL) { | 321 if (external_echo_path_ == NULL) { |
312 external_echo_path_ = new unsigned char[size_bytes]; | 322 external_echo_path_ = new unsigned char[size_bytes]; |
313 } | 323 } |
314 memcpy(external_echo_path_, echo_path, size_bytes); | 324 memcpy(external_echo_path_, echo_path, size_bytes); |
315 } | 325 } |
316 | 326 |
317 Initialize(); | 327 // TODO(peah): Simplify once the Enable function has been removed from |
| 328 // the public APM API. |
| 329 RTC_DCHECK(stream_properties_); |
| 330 Initialize(stream_properties_->sample_rate_hz, |
| 331 stream_properties_->num_reverse_channels, |
| 332 stream_properties_->num_output_channels); |
318 return AudioProcessing::kNoError; | 333 return AudioProcessing::kNoError; |
319 } | 334 } |
320 | 335 |
321 int EchoControlMobileImpl::GetEchoPath(void* echo_path, | 336 int EchoControlMobileImpl::GetEchoPath(void* echo_path, |
322 size_t size_bytes) const { | 337 size_t size_bytes) const { |
323 rtc::CritScope cs(crit_capture_); | 338 rtc::CritScope cs(crit_capture_); |
324 if (echo_path == NULL) { | 339 if (echo_path == NULL) { |
325 return AudioProcessing::kNullPointerError; | 340 return AudioProcessing::kNullPointerError; |
326 } | 341 } |
327 if (size_bytes != echo_path_size_bytes()) { | 342 if (size_bytes != echo_path_size_bytes()) { |
328 // Size mismatch | 343 // Size mismatch |
329 return AudioProcessing::kBadParameterError; | 344 return AudioProcessing::kBadParameterError; |
330 } | 345 } |
331 if (!enabled_) { | 346 if (!enabled_) { |
332 return AudioProcessing::kNotEnabledError; | 347 return AudioProcessing::kNotEnabledError; |
333 } | 348 } |
334 | 349 |
335 // Get the echo path from the first channel | 350 // Get the echo path from the first channel |
336 int32_t err = | 351 int32_t err = |
337 WebRtcAecm_GetEchoPath(cancellers_[0]->state(), echo_path, size_bytes); | 352 WebRtcAecm_GetEchoPath(cancellers_[0]->state(), echo_path, size_bytes); |
338 if (err != 0) { | 353 if (err != 0) { |
339 return MapError(err); | 354 return MapError(err); |
340 } | 355 } |
341 | 356 |
342 return AudioProcessing::kNoError; | 357 return AudioProcessing::kNoError; |
343 } | 358 } |
344 | 359 |
345 void EchoControlMobileImpl::Initialize() { | 360 void EchoControlMobileImpl::Initialize(int sample_rate_hz, |
| 361 size_t num_reverse_channels, |
| 362 size_t num_output_channels) { |
346 rtc::CritScope cs_render(crit_render_); | 363 rtc::CritScope cs_render(crit_render_); |
347 rtc::CritScope cs_capture(crit_capture_); | 364 rtc::CritScope cs_capture(crit_capture_); |
| 365 |
| 366 stream_properties_.reset(new StreamProperties( |
| 367 sample_rate_hz, num_reverse_channels, num_output_channels)); |
| 368 |
348 if (!enabled_) { | 369 if (!enabled_) { |
349 return; | 370 return; |
350 } | 371 } |
351 | 372 |
352 if (apm_->proc_sample_rate_hz() > AudioProcessing::kSampleRate16kHz) { | 373 if (stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) { |
353 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; | 374 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; |
354 } | 375 } |
355 | 376 |
356 int sample_rate_hz = apm_->proc_sample_rate_hz(); | |
357 cancellers_.resize(num_handles_required()); | 377 cancellers_.resize(num_handles_required()); |
358 for (auto& canceller : cancellers_) { | 378 for (auto& canceller : cancellers_) { |
359 if (!canceller) { | 379 if (!canceller) { |
360 canceller.reset(new Canceller()); | 380 canceller.reset(new Canceller()); |
361 } | 381 } |
362 canceller->Initialize(sample_rate_hz, external_echo_path_, | 382 canceller->Initialize(sample_rate_hz, external_echo_path_, |
363 echo_path_size_bytes()); | 383 echo_path_size_bytes()); |
364 } | 384 } |
365 | 385 |
366 Configure(); | 386 Configure(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 int handle_error = WebRtcAecm_set_config(canceller->state(), config); | 426 int handle_error = WebRtcAecm_set_config(canceller->state(), config); |
407 if (handle_error != AudioProcessing::kNoError) { | 427 if (handle_error != AudioProcessing::kNoError) { |
408 error = handle_error; | 428 error = handle_error; |
409 } | 429 } |
410 } | 430 } |
411 return error; | 431 return error; |
412 } | 432 } |
413 | 433 |
414 size_t EchoControlMobileImpl::num_handles_required() const { | 434 size_t EchoControlMobileImpl::num_handles_required() const { |
415 // Not locked as it only relies on APM public API which is threadsafe. | 435 // Not locked as it only relies on APM public API which is threadsafe. |
416 return apm_->num_output_channels() * apm_->num_reverse_channels(); | 436 return stream_properties_->num_output_channels * |
| 437 stream_properties_->num_reverse_channels; |
417 } | 438 } |
418 } // namespace webrtc | 439 } // namespace webrtc |
OLD | NEW |