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