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 |
| 141 RTC_DCHECK(stream_properties_); |
130 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 142 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
131 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_reverse_channels()); | 143 RTC_DCHECK_EQ(audio->num_channels(), |
132 RTC_DCHECK_GE(cancellers_.size(), | 144 stream_properties_->num_reverse_channels); |
133 apm_->num_output_channels() * audio->num_channels()); | 145 RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_output_channels * |
| 146 audio->num_channels()); |
134 | 147 |
135 int err = AudioProcessing::kNoError; | 148 int err = AudioProcessing::kNoError; |
136 // The ordering convention must be followed to pass to the correct AECM. | 149 // The ordering convention must be followed to pass to the correct AECM. |
137 render_queue_buffer_.clear(); | 150 render_queue_buffer_.clear(); |
138 int render_channel = 0; | 151 int render_channel = 0; |
139 for (auto& canceller : cancellers_) { | 152 for (auto& canceller : cancellers_) { |
140 err = WebRtcAecm_GetBufferFarendError( | 153 err = WebRtcAecm_GetBufferFarendError( |
141 canceller->state(), | 154 canceller->state(), |
142 audio->split_bands_const(render_channel)[kBand0To8kHz], | 155 audio->split_bands_const(render_channel)[kBand0To8kHz], |
143 audio->num_frames_per_band()); | 156 audio->num_frames_per_band()); |
(...skipping 19 matching lines...) Expand all Loading... |
163 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); | 176 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); |
164 } | 177 } |
165 | 178 |
166 return AudioProcessing::kNoError; | 179 return AudioProcessing::kNoError; |
167 } | 180 } |
168 | 181 |
169 // Read chunks of data that were received and queued on the render side from | 182 // Read chunks of data that were received and queued on the render side from |
170 // a queue. All the data chunks are buffered into the farend signal of the AEC. | 183 // a queue. All the data chunks are buffered into the farend signal of the AEC. |
171 void EchoControlMobileImpl::ReadQueuedRenderData() { | 184 void EchoControlMobileImpl::ReadQueuedRenderData() { |
172 rtc::CritScope cs_capture(crit_capture_); | 185 rtc::CritScope cs_capture(crit_capture_); |
| 186 RTC_DCHECK(stream_properties_); |
173 | 187 |
174 if (!enabled_) { | 188 if (!enabled_) { |
175 return; | 189 return; |
176 } | 190 } |
177 | 191 |
178 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { | 192 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { |
179 size_t buffer_index = 0; | 193 size_t buffer_index = 0; |
180 size_t num_frames_per_band = | 194 size_t num_frames_per_band = capture_queue_buffer_.size() / |
181 capture_queue_buffer_.size() / | 195 (stream_properties_->num_output_channels * |
182 (apm_->num_output_channels() * apm_->num_reverse_channels()); | 196 stream_properties_->num_reverse_channels); |
183 | 197 |
184 for (auto& canceller : cancellers_) { | 198 for (auto& canceller : cancellers_) { |
185 WebRtcAecm_BufferFarend(canceller->state(), | 199 WebRtcAecm_BufferFarend(canceller->state(), |
186 &capture_queue_buffer_[buffer_index], | 200 &capture_queue_buffer_[buffer_index], |
187 num_frames_per_band); | 201 num_frames_per_band); |
188 | 202 |
189 buffer_index += num_frames_per_band; | 203 buffer_index += num_frames_per_band; |
190 } | 204 } |
191 } | 205 } |
192 } | 206 } |
193 | 207 |
194 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { | 208 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio, |
| 209 int stream_delay_ms) { |
195 rtc::CritScope cs_capture(crit_capture_); | 210 rtc::CritScope cs_capture(crit_capture_); |
196 if (!enabled_) { | 211 if (!enabled_) { |
197 return AudioProcessing::kNoError; | 212 return AudioProcessing::kNoError; |
198 } | 213 } |
199 | 214 |
200 if (!apm_->was_stream_delay_set()) { | 215 RTC_DCHECK(stream_properties_); |
201 return AudioProcessing::kStreamParameterNotSetError; | |
202 } | |
203 | |
204 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 216 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
205 RTC_DCHECK_EQ(audio->num_channels(), apm_->num_output_channels()); | 217 RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_output_channels); |
206 RTC_DCHECK_GE(cancellers_.size(), | 218 RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_reverse_channels * |
207 apm_->num_reverse_channels() * audio->num_channels()); | 219 audio->num_channels()); |
208 | 220 |
209 int err = AudioProcessing::kNoError; | 221 int err = AudioProcessing::kNoError; |
210 | 222 |
211 // The ordering convention must be followed to pass to the correct AECM. | 223 // The ordering convention must be followed to pass to the correct AECM. |
212 size_t handle_index = 0; | 224 size_t handle_index = 0; |
213 for (size_t capture = 0; capture < audio->num_channels(); ++capture) { | 225 for (size_t capture = 0; capture < audio->num_channels(); ++capture) { |
214 // TODO(ajm): improve how this works, possibly inside AECM. | 226 // TODO(ajm): improve how this works, possibly inside AECM. |
215 // This is kind of hacked up. | 227 // This is kind of hacked up. |
216 const int16_t* noisy = audio->low_pass_reference(capture); | 228 const int16_t* noisy = audio->low_pass_reference(capture); |
217 const int16_t* clean = audio->split_bands_const(capture)[kBand0To8kHz]; | 229 const int16_t* clean = audio->split_bands_const(capture)[kBand0To8kHz]; |
218 if (noisy == NULL) { | 230 if (noisy == NULL) { |
219 noisy = clean; | 231 noisy = clean; |
220 clean = NULL; | 232 clean = NULL; |
221 } | 233 } |
222 for (size_t render = 0; render < apm_->num_reverse_channels(); ++render) { | 234 for (size_t render = 0; render < stream_properties_->num_reverse_channels; |
| 235 ++render) { |
223 err = WebRtcAecm_Process(cancellers_[handle_index]->state(), noisy, clean, | 236 err = WebRtcAecm_Process(cancellers_[handle_index]->state(), noisy, clean, |
224 audio->split_bands(capture)[kBand0To8kHz], | 237 audio->split_bands(capture)[kBand0To8kHz], |
225 audio->num_frames_per_band(), | 238 audio->num_frames_per_band(), stream_delay_ms); |
226 apm_->stream_delay_ms()); | |
227 | 239 |
228 if (err != AudioProcessing::kNoError) { | 240 if (err != AudioProcessing::kNoError) { |
229 return MapError(err); | 241 return MapError(err); |
230 } | 242 } |
231 | 243 |
232 ++handle_index; | 244 ++handle_index; |
233 } | 245 } |
234 } | 246 } |
235 return AudioProcessing::kNoError; | 247 return AudioProcessing::kNoError; |
236 } | 248 } |
237 | 249 |
238 int EchoControlMobileImpl::Enable(bool enable) { | 250 int EchoControlMobileImpl::Enable(bool enable) { |
239 // Ensure AEC and AECM are not both enabled. | 251 // Ensure AEC and AECM are not both enabled. |
240 rtc::CritScope cs_render(crit_render_); | 252 rtc::CritScope cs_render(crit_render_); |
241 rtc::CritScope cs_capture(crit_capture_); | 253 rtc::CritScope cs_capture(crit_capture_); |
242 // The is_enabled call is safe from a deadlock perspective | 254 RTC_DCHECK(stream_properties_); |
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 | 255 |
248 if (enable && | 256 if (enable && |
249 apm_->proc_sample_rate_hz() > AudioProcessing::kSampleRate16kHz) { | 257 stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) { |
250 return AudioProcessing::kBadSampleRateError; | 258 return AudioProcessing::kBadSampleRateError; |
251 } | 259 } |
252 | 260 |
253 if (enable && !enabled_) { | 261 if (enable && !enabled_) { |
254 enabled_ = enable; // Must be set before Initialize() is called. | 262 enabled_ = enable; // Must be set before Initialize() is called. |
255 Initialize(); | 263 |
| 264 // TODO(peah): Simplify once the Enable function has been removed from |
| 265 // the public APM API. |
| 266 Initialize(stream_properties_->sample_rate_hz, |
| 267 stream_properties_->num_reverse_channels, |
| 268 stream_properties_->num_output_channels); |
256 } else { | 269 } else { |
257 enabled_ = enable; | 270 enabled_ = enable; |
258 } | 271 } |
259 return AudioProcessing::kNoError; | 272 return AudioProcessing::kNoError; |
260 } | 273 } |
261 | 274 |
262 bool EchoControlMobileImpl::is_enabled() const { | 275 bool EchoControlMobileImpl::is_enabled() const { |
263 rtc::CritScope cs(crit_capture_); | 276 rtc::CritScope cs(crit_capture_); |
264 return enabled_; | 277 return enabled_; |
265 } | 278 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 // Size mismatch | 320 // Size mismatch |
308 return AudioProcessing::kBadParameterError; | 321 return AudioProcessing::kBadParameterError; |
309 } | 322 } |
310 | 323 |
311 if (external_echo_path_ == NULL) { | 324 if (external_echo_path_ == NULL) { |
312 external_echo_path_ = new unsigned char[size_bytes]; | 325 external_echo_path_ = new unsigned char[size_bytes]; |
313 } | 326 } |
314 memcpy(external_echo_path_, echo_path, size_bytes); | 327 memcpy(external_echo_path_, echo_path, size_bytes); |
315 } | 328 } |
316 | 329 |
317 Initialize(); | 330 // TODO(peah): Simplify once the Enable function has been removed from |
| 331 // the public APM API. |
| 332 RTC_DCHECK(stream_properties_); |
| 333 Initialize(stream_properties_->sample_rate_hz, |
| 334 stream_properties_->num_reverse_channels, |
| 335 stream_properties_->num_output_channels); |
318 return AudioProcessing::kNoError; | 336 return AudioProcessing::kNoError; |
319 } | 337 } |
320 | 338 |
321 int EchoControlMobileImpl::GetEchoPath(void* echo_path, | 339 int EchoControlMobileImpl::GetEchoPath(void* echo_path, |
322 size_t size_bytes) const { | 340 size_t size_bytes) const { |
323 rtc::CritScope cs(crit_capture_); | 341 rtc::CritScope cs(crit_capture_); |
324 if (echo_path == NULL) { | 342 if (echo_path == NULL) { |
325 return AudioProcessing::kNullPointerError; | 343 return AudioProcessing::kNullPointerError; |
326 } | 344 } |
327 if (size_bytes != echo_path_size_bytes()) { | 345 if (size_bytes != echo_path_size_bytes()) { |
328 // Size mismatch | 346 // Size mismatch |
329 return AudioProcessing::kBadParameterError; | 347 return AudioProcessing::kBadParameterError; |
330 } | 348 } |
331 if (!enabled_) { | 349 if (!enabled_) { |
332 return AudioProcessing::kNotEnabledError; | 350 return AudioProcessing::kNotEnabledError; |
333 } | 351 } |
334 | 352 |
335 // Get the echo path from the first channel | 353 // Get the echo path from the first channel |
336 int32_t err = | 354 int32_t err = |
337 WebRtcAecm_GetEchoPath(cancellers_[0]->state(), echo_path, size_bytes); | 355 WebRtcAecm_GetEchoPath(cancellers_[0]->state(), echo_path, size_bytes); |
338 if (err != 0) { | 356 if (err != 0) { |
339 return MapError(err); | 357 return MapError(err); |
340 } | 358 } |
341 | 359 |
342 return AudioProcessing::kNoError; | 360 return AudioProcessing::kNoError; |
343 } | 361 } |
344 | 362 |
345 void EchoControlMobileImpl::Initialize() { | 363 void EchoControlMobileImpl::Initialize(int sample_rate_hz, |
| 364 size_t num_reverse_channels, |
| 365 size_t num_output_channels) { |
346 rtc::CritScope cs_render(crit_render_); | 366 rtc::CritScope cs_render(crit_render_); |
347 rtc::CritScope cs_capture(crit_capture_); | 367 rtc::CritScope cs_capture(crit_capture_); |
| 368 |
| 369 stream_properties_.reset(new StreamProperties( |
| 370 sample_rate_hz, num_reverse_channels, num_output_channels)); |
| 371 |
348 if (!enabled_) { | 372 if (!enabled_) { |
349 return; | 373 return; |
350 } | 374 } |
351 | 375 |
352 if (apm_->proc_sample_rate_hz() > AudioProcessing::kSampleRate16kHz) { | 376 if (stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) { |
353 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; | 377 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; |
354 } | 378 } |
355 | 379 |
356 int sample_rate_hz = apm_->proc_sample_rate_hz(); | |
357 cancellers_.resize(num_handles_required()); | 380 cancellers_.resize(num_handles_required()); |
358 for (auto& canceller : cancellers_) { | 381 for (auto& canceller : cancellers_) { |
359 if (!canceller) { | 382 if (!canceller) { |
360 canceller.reset(new Canceller()); | 383 canceller.reset(new Canceller()); |
361 } | 384 } |
362 canceller->Initialize(sample_rate_hz, external_echo_path_, | 385 canceller->Initialize(sample_rate_hz, external_echo_path_, |
363 echo_path_size_bytes()); | 386 echo_path_size_bytes()); |
364 } | 387 } |
365 | 388 |
366 Configure(); | 389 Configure(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 for (auto& canceller : cancellers_) { | 428 for (auto& canceller : cancellers_) { |
406 int handle_error = WebRtcAecm_set_config(canceller->state(), config); | 429 int handle_error = WebRtcAecm_set_config(canceller->state(), config); |
407 if (handle_error != AudioProcessing::kNoError) { | 430 if (handle_error != AudioProcessing::kNoError) { |
408 error = handle_error; | 431 error = handle_error; |
409 } | 432 } |
410 } | 433 } |
411 return error; | 434 return error; |
412 } | 435 } |
413 | 436 |
414 size_t EchoControlMobileImpl::num_handles_required() const { | 437 size_t EchoControlMobileImpl::num_handles_required() const { |
415 // Not locked as it only relies on APM public API which is threadsafe. | 438 RTC_DCHECK(stream_properties_); |
416 return apm_->num_output_channels() * apm_->num_reverse_channels(); | 439 return stream_properties_->num_output_channels * |
| 440 stream_properties_->num_reverse_channels; |
417 } | 441 } |
418 } // namespace webrtc | 442 } // namespace webrtc |
OLD | NEW |