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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 case AECM_BAD_PARAMETER_ERROR: | 46 case AECM_BAD_PARAMETER_ERROR: |
47 return AudioProcessing::kBadParameterError; | 47 return AudioProcessing::kBadParameterError; |
48 case AECM_BAD_PARAMETER_WARNING: | 48 case AECM_BAD_PARAMETER_WARNING: |
49 return AudioProcessing::kBadStreamParameterWarning; | 49 return AudioProcessing::kBadStreamParameterWarning; |
50 default: | 50 default: |
51 // AECM_UNSPECIFIED_ERROR | 51 // AECM_UNSPECIFIED_ERROR |
52 // AECM_UNINITIALIZED_ERROR | 52 // AECM_UNINITIALIZED_ERROR |
53 return AudioProcessing::kUnspecifiedError; | 53 return AudioProcessing::kUnspecifiedError; |
54 } | 54 } |
55 } | 55 } |
56 // Maximum length that a frame of samples can have. | |
57 static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; | |
58 // Maximum number of frames to buffer in the render queue. | |
59 // TODO(peah): Decrease this once we properly handle hugely unbalanced | |
60 // reverse and forward call numbers. | |
61 static const size_t kMaxNumFramesToBuffer = 100; | |
62 } // namespace | 56 } // namespace |
63 | 57 |
64 size_t EchoControlMobile::echo_path_size_bytes() { | 58 size_t EchoControlMobile::echo_path_size_bytes() { |
65 return WebRtcAecm_echo_path_size_bytes(); | 59 return WebRtcAecm_echo_path_size_bytes(); |
66 } | 60 } |
67 | 61 |
68 struct EchoControlMobileImpl::StreamProperties { | 62 struct EchoControlMobileImpl::StreamProperties { |
69 StreamProperties() = delete; | 63 StreamProperties() = delete; |
70 StreamProperties(int sample_rate_hz, | 64 StreamProperties(int sample_rate_hz, |
71 size_t num_reverse_channels, | 65 size_t num_reverse_channels, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 void* state_; | 107 void* state_; |
114 RTC_DISALLOW_COPY_AND_ASSIGN(Canceller); | 108 RTC_DISALLOW_COPY_AND_ASSIGN(Canceller); |
115 }; | 109 }; |
116 | 110 |
117 EchoControlMobileImpl::EchoControlMobileImpl(rtc::CriticalSection* crit_render, | 111 EchoControlMobileImpl::EchoControlMobileImpl(rtc::CriticalSection* crit_render, |
118 rtc::CriticalSection* crit_capture) | 112 rtc::CriticalSection* crit_capture) |
119 : crit_render_(crit_render), | 113 : crit_render_(crit_render), |
120 crit_capture_(crit_capture), | 114 crit_capture_(crit_capture), |
121 routing_mode_(kSpeakerphone), | 115 routing_mode_(kSpeakerphone), |
122 comfort_noise_enabled_(true), | 116 comfort_noise_enabled_(true), |
123 external_echo_path_(NULL), | 117 external_echo_path_(NULL) { |
124 render_queue_element_max_size_(0) { | |
125 RTC_DCHECK(crit_render); | 118 RTC_DCHECK(crit_render); |
126 RTC_DCHECK(crit_capture); | 119 RTC_DCHECK(crit_capture); |
127 } | 120 } |
128 | 121 |
129 EchoControlMobileImpl::~EchoControlMobileImpl() { | 122 EchoControlMobileImpl::~EchoControlMobileImpl() { |
130 if (external_echo_path_ != NULL) { | 123 if (external_echo_path_ != NULL) { |
131 delete [] external_echo_path_; | 124 delete [] external_echo_path_; |
132 external_echo_path_ = NULL; | 125 external_echo_path_ = NULL; |
133 } | 126 } |
134 } | 127 } |
135 | 128 |
136 int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { | 129 void EchoControlMobileImpl::ProcessRenderAudio( |
137 rtc::CritScope cs_render(crit_render_); | 130 rtc::ArrayView<const int16_t> packed_render_audio) { |
138 if (!enabled_) { | |
139 return AudioProcessing::kNoError; | |
140 } | |
141 | |
142 RTC_DCHECK(stream_properties_); | |
143 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | |
144 RTC_DCHECK_EQ(audio->num_channels(), | |
145 stream_properties_->num_reverse_channels); | |
146 RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_output_channels * | |
147 audio->num_channels()); | |
148 | |
149 int err = AudioProcessing::kNoError; | |
150 // The ordering convention must be followed to pass to the correct AECM. | |
151 render_queue_buffer_.clear(); | |
152 int render_channel = 0; | |
153 for (auto& canceller : cancellers_) { | |
154 err = WebRtcAecm_GetBufferFarendError( | |
155 canceller->state(), | |
156 audio->split_bands_const(render_channel)[kBand0To8kHz], | |
157 audio->num_frames_per_band()); | |
158 | |
159 if (err != AudioProcessing::kNoError) | |
160 return MapError(err); // TODO(ajm): warning possible?); | |
161 | |
162 // Buffer the samples in the render queue. | |
163 render_queue_buffer_.insert( | |
164 render_queue_buffer_.end(), | |
165 audio->split_bands_const(render_channel)[kBand0To8kHz], | |
166 (audio->split_bands_const(render_channel)[kBand0To8kHz] + | |
167 audio->num_frames_per_band())); | |
168 render_channel = (render_channel + 1) % audio->num_channels(); | |
169 } | |
170 | |
171 // Insert the samples into the queue. | |
172 if (!render_signal_queue_->Insert(&render_queue_buffer_)) { | |
173 // The data queue is full and needs to be emptied. | |
174 ReadQueuedRenderData(); | |
175 | |
176 // Retry the insert (should always work). | |
177 bool result = render_signal_queue_->Insert(&render_queue_buffer_); | |
178 RTC_DCHECK(result); | |
179 } | |
180 | |
181 return AudioProcessing::kNoError; | |
182 } | |
183 | |
184 // Read chunks of data that were received and queued on the render side from | |
185 // a queue. All the data chunks are buffered into the farend signal of the AEC. | |
186 void EchoControlMobileImpl::ReadQueuedRenderData() { | |
187 rtc::CritScope cs_capture(crit_capture_); | 131 rtc::CritScope cs_capture(crit_capture_); |
188 RTC_DCHECK(stream_properties_); | |
189 | |
190 if (!enabled_) { | 132 if (!enabled_) { |
191 return; | 133 return; |
192 } | 134 } |
193 | 135 |
194 while (render_signal_queue_->Remove(&capture_queue_buffer_)) { | 136 RTC_DCHECK(stream_properties_); |
195 size_t buffer_index = 0; | |
196 size_t num_frames_per_band = capture_queue_buffer_.size() / | |
197 (stream_properties_->num_output_channels * | |
198 stream_properties_->num_reverse_channels); | |
199 | 137 |
200 for (auto& canceller : cancellers_) { | 138 size_t buffer_index = 0; |
201 WebRtcAecm_BufferFarend(canceller->state(), | 139 size_t num_frames_per_band = |
202 &capture_queue_buffer_[buffer_index], | 140 packed_render_audio.size() / (stream_properties_->num_output_channels * |
203 num_frames_per_band); | 141 stream_properties_->num_reverse_channels); |
204 | 142 |
205 buffer_index += num_frames_per_band; | 143 for (auto& canceller : cancellers_) { |
| 144 WebRtcAecm_BufferFarend(canceller->state(), |
| 145 &packed_render_audio[buffer_index], |
| 146 num_frames_per_band); |
| 147 |
| 148 buffer_index += num_frames_per_band; |
| 149 } |
| 150 } |
| 151 |
| 152 void EchoControlMobileImpl::PackRenderAudioBuffer( |
| 153 const AudioBuffer* audio, |
| 154 size_t num_output_channels, |
| 155 size_t num_channels, |
| 156 std::vector<int16_t>* packed_buffer) { |
| 157 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
| 158 RTC_DCHECK_EQ(num_channels, audio->num_channels()); |
| 159 |
| 160 // The ordering convention must be followed to pass to the correct AECM. |
| 161 packed_buffer->clear(); |
| 162 int render_channel = 0; |
| 163 for (size_t i = 0; i < num_output_channels; i++) { |
| 164 for (size_t j = 0; j < audio->num_channels(); j++) { |
| 165 // Buffer the samples in the render queue. |
| 166 packed_buffer->insert( |
| 167 packed_buffer->end(), |
| 168 audio->split_bands_const(render_channel)[kBand0To8kHz], |
| 169 (audio->split_bands_const(render_channel)[kBand0To8kHz] + |
| 170 audio->num_frames_per_band())); |
| 171 render_channel = (render_channel + 1) % audio->num_channels(); |
206 } | 172 } |
207 } | 173 } |
208 } | 174 } |
209 | 175 |
| 176 size_t EchoControlMobileImpl::NumCancellersRequired( |
| 177 size_t num_output_channels, |
| 178 size_t num_reverse_channels) { |
| 179 return num_output_channels * num_reverse_channels; |
| 180 } |
| 181 |
210 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio, | 182 int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio, |
211 int stream_delay_ms) { | 183 int stream_delay_ms) { |
212 rtc::CritScope cs_capture(crit_capture_); | 184 rtc::CritScope cs_capture(crit_capture_); |
213 if (!enabled_) { | 185 if (!enabled_) { |
214 return AudioProcessing::kNoError; | 186 return AudioProcessing::kNoError; |
215 } | 187 } |
216 | 188 |
217 RTC_DCHECK(stream_properties_); | 189 RTC_DCHECK(stream_properties_); |
218 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); | 190 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
219 RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_output_channels); | 191 RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_output_channels); |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 sample_rate_hz, num_reverse_channels, num_output_channels)); | 350 sample_rate_hz, num_reverse_channels, num_output_channels)); |
379 | 351 |
380 if (!enabled_) { | 352 if (!enabled_) { |
381 return; | 353 return; |
382 } | 354 } |
383 | 355 |
384 if (stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) { | 356 if (stream_properties_->sample_rate_hz > AudioProcessing::kSampleRate16kHz) { |
385 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; | 357 LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates"; |
386 } | 358 } |
387 | 359 |
388 cancellers_.resize(num_handles_required()); | 360 cancellers_.resize( |
| 361 NumCancellersRequired(stream_properties_->num_output_channels, |
| 362 stream_properties_->num_reverse_channels)); |
| 363 |
389 for (auto& canceller : cancellers_) { | 364 for (auto& canceller : cancellers_) { |
390 if (!canceller) { | 365 if (!canceller) { |
391 canceller.reset(new Canceller()); | 366 canceller.reset(new Canceller()); |
392 } | 367 } |
393 canceller->Initialize(sample_rate_hz, external_echo_path_, | 368 canceller->Initialize(sample_rate_hz, external_echo_path_, |
394 echo_path_size_bytes()); | 369 echo_path_size_bytes()); |
395 } | 370 } |
396 | 371 |
397 Configure(); | 372 Configure(); |
398 | |
399 AllocateRenderQueue(); | |
400 } | |
401 | |
402 void EchoControlMobileImpl::AllocateRenderQueue() { | |
403 const size_t new_render_queue_element_max_size = std::max<size_t>( | |
404 static_cast<size_t>(1), | |
405 kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); | |
406 | |
407 rtc::CritScope cs_render(crit_render_); | |
408 rtc::CritScope cs_capture(crit_capture_); | |
409 | |
410 // Reallocate the queue if the queue item size is too small to fit the | |
411 // data to put in the queue. | |
412 if (render_queue_element_max_size_ < new_render_queue_element_max_size) { | |
413 render_queue_element_max_size_ = new_render_queue_element_max_size; | |
414 | |
415 std::vector<int16_t> template_queue_element(render_queue_element_max_size_); | |
416 | |
417 render_signal_queue_.reset( | |
418 new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>( | |
419 kMaxNumFramesToBuffer, template_queue_element, | |
420 RenderQueueItemVerifier<int16_t>(render_queue_element_max_size_))); | |
421 | |
422 render_queue_buffer_.resize(render_queue_element_max_size_); | |
423 capture_queue_buffer_.resize(render_queue_element_max_size_); | |
424 } else { | |
425 render_signal_queue_->Clear(); | |
426 } | |
427 } | 373 } |
428 | 374 |
429 int EchoControlMobileImpl::Configure() { | 375 int EchoControlMobileImpl::Configure() { |
430 rtc::CritScope cs_render(crit_render_); | 376 rtc::CritScope cs_render(crit_render_); |
431 rtc::CritScope cs_capture(crit_capture_); | 377 rtc::CritScope cs_capture(crit_capture_); |
432 AecmConfig config; | 378 AecmConfig config; |
433 config.cngMode = comfort_noise_enabled_; | 379 config.cngMode = comfort_noise_enabled_; |
434 config.echoMode = MapSetting(routing_mode_); | 380 config.echoMode = MapSetting(routing_mode_); |
435 int error = AudioProcessing::kNoError; | 381 int error = AudioProcessing::kNoError; |
436 for (auto& canceller : cancellers_) { | 382 for (auto& canceller : cancellers_) { |
437 int handle_error = WebRtcAecm_set_config(canceller->state(), config); | 383 int handle_error = WebRtcAecm_set_config(canceller->state(), config); |
438 if (handle_error != AudioProcessing::kNoError) { | 384 if (handle_error != AudioProcessing::kNoError) { |
439 error = handle_error; | 385 error = handle_error; |
440 } | 386 } |
441 } | 387 } |
442 return error; | 388 return error; |
443 } | 389 } |
444 | 390 |
445 size_t EchoControlMobileImpl::num_handles_required() const { | |
446 RTC_DCHECK(stream_properties_); | |
447 return stream_properties_->num_output_channels * | |
448 stream_properties_->num_reverse_channels; | |
449 } | |
450 } // namespace webrtc | 391 } // namespace webrtc |
OLD | NEW |