| 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 |