echo_canceller3.cc (43108B)
1 /* 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. 3 * 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 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 #include "modules/audio_processing/aec3/echo_canceller3.h" 11 12 #include <algorithm> 13 #include <atomic> 14 #include <cstddef> 15 #include <memory> 16 #include <optional> 17 #include <string> 18 #include <utility> 19 #include <vector> 20 21 #include "absl/strings/string_view.h" 22 #include "api/array_view.h" 23 #include "api/audio/echo_canceller3_config.h" 24 #include "api/audio/echo_control.h" 25 #include "api/environment/environment.h" 26 #include "api/field_trials_view.h" 27 #include "modules/audio_processing/aec3/aec3_common.h" 28 #include "modules/audio_processing/aec3/block.h" 29 #include "modules/audio_processing/aec3/block_delay_buffer.h" 30 #include "modules/audio_processing/aec3/block_framer.h" 31 #include "modules/audio_processing/aec3/block_processor.h" 32 #include "modules/audio_processing/aec3/frame_blocker.h" 33 #include "modules/audio_processing/high_pass_filter.h" 34 #include "modules/audio_processing/logging/apm_data_dumper.h" 35 #include "rtc_base/checks.h" 36 #include "rtc_base/experiments/field_trial_parser.h" 37 #include "rtc_base/logging.h" 38 #include "rtc_base/race_checker.h" 39 #include "rtc_base/swap_queue.h" 40 41 namespace webrtc { 42 43 namespace { 44 45 enum class EchoCanceller3ApiCall { kCapture, kRender }; 46 47 bool DetectSaturation(ArrayView<const float> y) { 48 for (size_t k = 0; k < y.size(); ++k) { 49 if (y[k] >= 32700.0f || y[k] <= -32700.0f) { 50 return true; 51 } 52 } 53 return false; 54 } 55 56 // Retrieves a value from a field trial if it is available. If no value is 57 // present, the default value is returned. If the retrieved value is beyond the 58 // specified limits, the default value is returned instead. 59 void RetrieveFieldTrialValue(const FieldTrialsView& field_trials, 60 absl::string_view trial_name, 61 float min, 62 float max, 63 float* value_to_update) { 64 const std::string field_trial_str = field_trials.Lookup(trial_name); 65 66 FieldTrialParameter<double> field_trial_param(/*key=*/"", *value_to_update); 67 68 ParseFieldTrial({&field_trial_param}, field_trial_str); 69 float field_trial_value = static_cast<float>(field_trial_param.Get()); 70 71 if (field_trial_value >= min && field_trial_value <= max && 72 field_trial_value != *value_to_update) { 73 RTC_LOG(LS_INFO) << "Key " << trial_name 74 << " changing AEC3 parameter value from " 75 << *value_to_update << " to " << field_trial_value; 76 *value_to_update = field_trial_value; 77 } 78 } 79 80 void RetrieveFieldTrialValue(const FieldTrialsView& field_trials, 81 absl::string_view trial_name, 82 int min, 83 int max, 84 int* value_to_update) { 85 const std::string field_trial_str = field_trials.Lookup(trial_name); 86 87 FieldTrialParameter<int> field_trial_param(/*key=*/"", *value_to_update); 88 89 ParseFieldTrial({&field_trial_param}, field_trial_str); 90 float field_trial_value = field_trial_param.Get(); 91 92 if (field_trial_value >= min && field_trial_value <= max && 93 field_trial_value != *value_to_update) { 94 RTC_LOG(LS_INFO) << "Key " << trial_name 95 << " changing AEC3 parameter value from " 96 << *value_to_update << " to " << field_trial_value; 97 *value_to_update = field_trial_value; 98 } 99 } 100 101 void FillSubFrameView( 102 AudioBuffer* frame, 103 size_t sub_frame_index, 104 std::vector<std::vector<ArrayView<float>>>* sub_frame_view) { 105 RTC_DCHECK_GE(1, sub_frame_index); 106 RTC_DCHECK_LE(0, sub_frame_index); 107 RTC_DCHECK_EQ(frame->num_bands(), sub_frame_view->size()); 108 RTC_DCHECK_EQ(frame->num_channels(), (*sub_frame_view)[0].size()); 109 for (size_t band = 0; band < sub_frame_view->size(); ++band) { 110 for (size_t channel = 0; channel < (*sub_frame_view)[0].size(); ++channel) { 111 (*sub_frame_view)[band][channel] = ArrayView<float>( 112 &frame->split_bands(channel)[band][sub_frame_index * kSubFrameLength], 113 kSubFrameLength); 114 } 115 } 116 } 117 118 void FillSubFrameView( 119 bool proper_downmix_needed, 120 std::vector<std::vector<std::vector<float>>>* frame, 121 size_t sub_frame_index, 122 std::vector<std::vector<ArrayView<float>>>* sub_frame_view) { 123 RTC_DCHECK_GE(1, sub_frame_index); 124 RTC_DCHECK_EQ(frame->size(), sub_frame_view->size()); 125 const size_t frame_num_channels = (*frame)[0].size(); 126 const size_t sub_frame_num_channels = (*sub_frame_view)[0].size(); 127 if (frame_num_channels > sub_frame_num_channels) { 128 RTC_DCHECK_EQ(sub_frame_num_channels, 1u); 129 if (proper_downmix_needed) { 130 // When a proper downmix is needed (which is the case when proper stereo 131 // is present in the echo reference signal but the echo canceller does the 132 // processing in mono) downmix the echo reference by averaging the channel 133 // content (otherwise downmixing is done by selecting channel 0). 134 for (size_t band = 0; band < frame->size(); ++band) { 135 for (size_t ch = 1; ch < frame_num_channels; ++ch) { 136 for (size_t k = 0; k < kSubFrameLength; ++k) { 137 (*frame)[band][/*channel=*/0] 138 [sub_frame_index * kSubFrameLength + k] += 139 (*frame)[band][ch][sub_frame_index * kSubFrameLength + k]; 140 } 141 } 142 const float one_by_num_channels = 1.0f / frame_num_channels; 143 for (size_t k = 0; k < kSubFrameLength; ++k) { 144 (*frame)[band][/*channel=*/0][sub_frame_index * kSubFrameLength + 145 k] *= one_by_num_channels; 146 } 147 } 148 } 149 for (size_t band = 0; band < frame->size(); ++band) { 150 (*sub_frame_view)[band][/*channel=*/0] = ArrayView<float>( 151 &(*frame)[band][/*channel=*/0][sub_frame_index * kSubFrameLength], 152 kSubFrameLength); 153 } 154 } else { 155 RTC_DCHECK_EQ(frame_num_channels, sub_frame_num_channels); 156 for (size_t band = 0; band < frame->size(); ++band) { 157 for (size_t channel = 0; channel < (*frame)[band].size(); ++channel) { 158 (*sub_frame_view)[band][channel] = ArrayView<float>( 159 &(*frame)[band][channel][sub_frame_index * kSubFrameLength], 160 kSubFrameLength); 161 } 162 } 163 } 164 } 165 166 void ProcessCaptureFrameContent( 167 AudioBuffer* linear_output, 168 AudioBuffer* capture, 169 bool level_change, 170 bool aec_reference_is_downmixed_stereo, 171 bool saturated_microphone_signal, 172 size_t sub_frame_index, 173 FrameBlocker* capture_blocker, 174 BlockFramer* linear_output_framer, 175 BlockFramer* output_framer, 176 BlockProcessor* block_processor, 177 Block* linear_output_block, 178 std::vector<std::vector<ArrayView<float>>>* linear_output_sub_frame_view, 179 Block* capture_block, 180 std::vector<std::vector<ArrayView<float>>>* capture_sub_frame_view) { 181 FillSubFrameView(capture, sub_frame_index, capture_sub_frame_view); 182 183 if (linear_output) { 184 RTC_DCHECK(linear_output_framer); 185 RTC_DCHECK(linear_output_block); 186 RTC_DCHECK(linear_output_sub_frame_view); 187 FillSubFrameView(linear_output, sub_frame_index, 188 linear_output_sub_frame_view); 189 } 190 191 capture_blocker->InsertSubFrameAndExtractBlock(*capture_sub_frame_view, 192 capture_block); 193 block_processor->ProcessCapture( 194 /*echo_path_gain_change=*/level_change || 195 aec_reference_is_downmixed_stereo, 196 saturated_microphone_signal, linear_output_block, capture_block); 197 output_framer->InsertBlockAndExtractSubFrame(*capture_block, 198 capture_sub_frame_view); 199 200 if (linear_output) { 201 RTC_DCHECK(linear_output_framer); 202 linear_output_framer->InsertBlockAndExtractSubFrame( 203 *linear_output_block, linear_output_sub_frame_view); 204 } 205 } 206 207 void ProcessRemainingCaptureFrameContent(bool level_change, 208 bool aec_reference_is_downmixed_stereo, 209 bool saturated_microphone_signal, 210 FrameBlocker* capture_blocker, 211 BlockFramer* linear_output_framer, 212 BlockFramer* output_framer, 213 BlockProcessor* block_processor, 214 Block* linear_output_block, 215 Block* block) { 216 if (!capture_blocker->IsBlockAvailable()) { 217 return; 218 } 219 220 capture_blocker->ExtractBlock(block); 221 block_processor->ProcessCapture( 222 /*echo_path_gain_change=*/level_change || 223 aec_reference_is_downmixed_stereo, 224 saturated_microphone_signal, linear_output_block, block); 225 output_framer->InsertBlock(*block); 226 227 if (linear_output_framer) { 228 RTC_DCHECK(linear_output_block); 229 linear_output_framer->InsertBlock(*linear_output_block); 230 } 231 } 232 233 void BufferRenderFrameContent( 234 bool proper_downmix_needed, 235 std::vector<std::vector<std::vector<float>>>* render_frame, 236 size_t sub_frame_index, 237 FrameBlocker* render_blocker, 238 BlockProcessor* block_processor, 239 Block* block, 240 std::vector<std::vector<ArrayView<float>>>* sub_frame_view) { 241 FillSubFrameView(proper_downmix_needed, render_frame, sub_frame_index, 242 sub_frame_view); 243 render_blocker->InsertSubFrameAndExtractBlock(*sub_frame_view, block); 244 block_processor->BufferRender(*block); 245 } 246 247 void BufferRemainingRenderFrameContent(FrameBlocker* render_blocker, 248 BlockProcessor* block_processor, 249 Block* block) { 250 if (!render_blocker->IsBlockAvailable()) { 251 return; 252 } 253 render_blocker->ExtractBlock(block); 254 block_processor->BufferRender(*block); 255 } 256 257 void CopyBufferIntoFrame(const AudioBuffer& buffer, 258 size_t num_bands, 259 size_t num_channels, 260 std::vector<std::vector<std::vector<float>>>* frame) { 261 RTC_DCHECK_EQ(num_bands, frame->size()); 262 RTC_DCHECK_EQ(num_channels, (*frame)[0].size()); 263 RTC_DCHECK_EQ(AudioBuffer::kSplitBandSize, (*frame)[0][0].size()); 264 for (size_t band = 0; band < num_bands; ++band) { 265 for (size_t channel = 0; channel < num_channels; ++channel) { 266 ArrayView<const float> buffer_view( 267 &buffer.split_bands_const(channel)[band][0], 268 AudioBuffer::kSplitBandSize); 269 std::copy(buffer_view.begin(), buffer_view.end(), 270 (*frame)[band][channel].begin()); 271 } 272 } 273 } 274 275 } // namespace 276 277 // TODO(webrtc:5298): Move this to a separate file. 278 EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config, 279 const FieldTrialsView& field_trials) { 280 EchoCanceller3Config adjusted_cfg = config; 281 282 if (field_trials.IsEnabled("WebRTC-Aec3StereoContentDetectionKillSwitch")) { 283 adjusted_cfg.multi_channel.detect_stereo_content = false; 284 } 285 286 if (field_trials.IsEnabled("WebRTC-Aec3AntiHowlingMinimizationKillSwitch")) { 287 adjusted_cfg.suppressor.high_bands_suppression 288 .anti_howling_activation_threshold = 25.f; 289 adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain = 0.01f; 290 } 291 292 if (field_trials.IsEnabled("WebRTC-Aec3UseShortConfigChangeDuration")) { 293 adjusted_cfg.filter.config_change_duration_blocks = 10; 294 } 295 296 if (field_trials.IsEnabled("WebRTC-Aec3UseZeroInitialStateDuration")) { 297 adjusted_cfg.filter.initial_state_seconds = 0.f; 298 } else if (field_trials.IsEnabled( 299 "WebRTC-Aec3UseDot1SecondsInitialStateDuration")) { 300 adjusted_cfg.filter.initial_state_seconds = .1f; 301 } else if (field_trials.IsEnabled( 302 "WebRTC-Aec3UseDot2SecondsInitialStateDuration")) { 303 adjusted_cfg.filter.initial_state_seconds = .2f; 304 } else if (field_trials.IsEnabled( 305 "WebRTC-Aec3UseDot3SecondsInitialStateDuration")) { 306 adjusted_cfg.filter.initial_state_seconds = .3f; 307 } else if (field_trials.IsEnabled( 308 "WebRTC-Aec3UseDot6SecondsInitialStateDuration")) { 309 adjusted_cfg.filter.initial_state_seconds = .6f; 310 } else if (field_trials.IsEnabled( 311 "WebRTC-Aec3UseDot9SecondsInitialStateDuration")) { 312 adjusted_cfg.filter.initial_state_seconds = .9f; 313 } else if (field_trials.IsEnabled( 314 "WebRTC-Aec3Use1Dot2SecondsInitialStateDuration")) { 315 adjusted_cfg.filter.initial_state_seconds = 1.2f; 316 } else if (field_trials.IsEnabled( 317 "WebRTC-Aec3Use1Dot6SecondsInitialStateDuration")) { 318 adjusted_cfg.filter.initial_state_seconds = 1.6f; 319 } else if (field_trials.IsEnabled( 320 "WebRTC-Aec3Use2Dot0SecondsInitialStateDuration")) { 321 adjusted_cfg.filter.initial_state_seconds = 2.0f; 322 } 323 324 if (field_trials.IsEnabled("WebRTC-Aec3HighPassFilterEchoReference")) { 325 adjusted_cfg.filter.high_pass_filter_echo_reference = true; 326 } 327 328 if (field_trials.IsEnabled("WebRTC-Aec3EchoSaturationDetectionKillSwitch")) { 329 adjusted_cfg.ep_strength.echo_can_saturate = false; 330 } 331 332 const std::string use_nearend_reverb_len_tunings = 333 field_trials.Lookup("WebRTC-Aec3UseNearendReverbLen"); 334 FieldTrialParameter<double> nearend_reverb_default_len( 335 "default_len", adjusted_cfg.ep_strength.default_len); 336 FieldTrialParameter<double> nearend_reverb_nearend_len( 337 "nearend_len", adjusted_cfg.ep_strength.nearend_len); 338 339 ParseFieldTrial({&nearend_reverb_default_len, &nearend_reverb_nearend_len}, 340 use_nearend_reverb_len_tunings); 341 float default_len = static_cast<float>(nearend_reverb_default_len.Get()); 342 float nearend_len = static_cast<float>(nearend_reverb_nearend_len.Get()); 343 if (default_len > -1 && default_len < 1 && nearend_len > -1 && 344 nearend_len < 1) { 345 adjusted_cfg.ep_strength.default_len = 346 static_cast<float>(nearend_reverb_default_len.Get()); 347 adjusted_cfg.ep_strength.nearend_len = 348 static_cast<float>(nearend_reverb_nearend_len.Get()); 349 } 350 351 if (field_trials.IsEnabled("WebRTC-Aec3ConservativeTailFreqResponse")) { 352 adjusted_cfg.ep_strength.use_conservative_tail_frequency_response = true; 353 } 354 355 if (field_trials.IsDisabled("WebRTC-Aec3ConservativeTailFreqResponse")) { 356 adjusted_cfg.ep_strength.use_conservative_tail_frequency_response = false; 357 } 358 359 if (field_trials.IsEnabled("WebRTC-Aec3ShortHeadroomKillSwitch")) { 360 // Two blocks headroom. 361 adjusted_cfg.delay.delay_headroom_samples = kBlockSize * 2; 362 } 363 364 if (field_trials.IsEnabled("WebRTC-Aec3ClampInstQualityToZeroKillSwitch")) { 365 adjusted_cfg.erle.clamp_quality_estimate_to_zero = false; 366 } 367 368 if (field_trials.IsEnabled("WebRTC-Aec3ClampInstQualityToOneKillSwitch")) { 369 adjusted_cfg.erle.clamp_quality_estimate_to_one = false; 370 } 371 372 if (field_trials.IsEnabled("WebRTC-Aec3OnsetDetectionKillSwitch")) { 373 adjusted_cfg.erle.onset_detection = false; 374 } 375 376 if (field_trials.IsEnabled( 377 "WebRTC-Aec3EnforceRenderDelayEstimationDownmixing")) { 378 adjusted_cfg.delay.render_alignment_mixing.downmix = true; 379 adjusted_cfg.delay.render_alignment_mixing.adaptive_selection = false; 380 } 381 382 if (field_trials.IsEnabled( 383 "WebRTC-Aec3EnforceCaptureDelayEstimationDownmixing")) { 384 adjusted_cfg.delay.capture_alignment_mixing.downmix = true; 385 adjusted_cfg.delay.capture_alignment_mixing.adaptive_selection = false; 386 } 387 388 if (field_trials.IsEnabled( 389 "WebRTC-Aec3EnforceCaptureDelayEstimationLeftRightPrioritization")) { 390 adjusted_cfg.delay.capture_alignment_mixing.prefer_first_two_channels = 391 true; 392 } 393 394 if (field_trials.IsEnabled( 395 "WebRTC-" 396 "Aec3RenderDelayEstimationLeftRightPrioritizationKillSwitch")) { 397 adjusted_cfg.delay.capture_alignment_mixing.prefer_first_two_channels = 398 false; 399 } 400 401 if (field_trials.IsEnabled("WebRTC-Aec3SensitiveDominantNearendActivation")) { 402 adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold = 0.5f; 403 } else if (field_trials.IsEnabled( 404 "WebRTC-Aec3VerySensitiveDominantNearendActivation")) { 405 adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold = 0.75f; 406 } 407 408 if (field_trials.IsEnabled("WebRTC-Aec3TransparentAntiHowlingGain")) { 409 adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain = 1.f; 410 } 411 412 if (field_trials.IsEnabled( 413 "WebRTC-Aec3EnforceMoreTransparentNormalSuppressorTuning")) { 414 adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent = 0.4f; 415 adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress = 0.5f; 416 } 417 418 if (field_trials.IsEnabled( 419 "WebRTC-Aec3EnforceMoreTransparentNearendSuppressorTuning")) { 420 adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent = 1.29f; 421 adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress = 1.3f; 422 } 423 424 if (field_trials.IsEnabled( 425 "WebRTC-Aec3EnforceMoreTransparentNormalSuppressorHfTuning")) { 426 adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent = 0.3f; 427 adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress = 0.4f; 428 } 429 430 if (field_trials.IsEnabled( 431 "WebRTC-Aec3EnforceMoreTransparentNearendSuppressorHfTuning")) { 432 adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent = 1.09f; 433 adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress = 1.1f; 434 } 435 436 if (field_trials.IsEnabled( 437 "WebRTC-Aec3EnforceRapidlyAdjustingNormalSuppressorTunings")) { 438 adjusted_cfg.suppressor.normal_tuning.max_inc_factor = 2.5f; 439 } 440 441 if (field_trials.IsEnabled( 442 "WebRTC-Aec3EnforceRapidlyAdjustingNearendSuppressorTunings")) { 443 adjusted_cfg.suppressor.nearend_tuning.max_inc_factor = 2.5f; 444 } 445 446 if (field_trials.IsEnabled( 447 "WebRTC-Aec3EnforceSlowlyAdjustingNormalSuppressorTunings")) { 448 adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf = .2f; 449 } 450 451 if (field_trials.IsEnabled( 452 "WebRTC-Aec3EnforceSlowlyAdjustingNearendSuppressorTunings")) { 453 adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf = .2f; 454 } 455 456 if (field_trials.IsEnabled("WebRTC-Aec3EnforceConservativeHfSuppression")) { 457 adjusted_cfg.suppressor.conservative_hf_suppression = true; 458 } 459 460 if (field_trials.IsEnabled("WebRTC-Aec3EnforceStationarityProperties")) { 461 adjusted_cfg.echo_audibility.use_stationarity_properties = true; 462 } 463 464 if (field_trials.IsEnabled( 465 "WebRTC-Aec3EnforceStationarityPropertiesAtInit")) { 466 adjusted_cfg.echo_audibility.use_stationarity_properties_at_init = true; 467 } 468 469 if (field_trials.IsEnabled("WebRTC-Aec3EnforceLowActiveRenderLimit")) { 470 adjusted_cfg.render_levels.active_render_limit = 50.f; 471 } else if (field_trials.IsEnabled( 472 "WebRTC-Aec3EnforceVeryLowActiveRenderLimit")) { 473 adjusted_cfg.render_levels.active_render_limit = 30.f; 474 } 475 476 if (field_trials.IsEnabled("WebRTC-Aec3NonlinearModeReverbKillSwitch")) { 477 adjusted_cfg.echo_model.model_reverb_in_nonlinear_mode = false; 478 } 479 480 // Field-trial based override for the whole suppressor tuning. 481 const std::string suppressor_tuning_override_trial_name = 482 field_trials.Lookup("WebRTC-Aec3SuppressorTuningOverride"); 483 484 FieldTrialParameter<double> nearend_tuning_mask_lf_enr_transparent( 485 "nearend_tuning_mask_lf_enr_transparent", 486 adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent); 487 FieldTrialParameter<double> nearend_tuning_mask_lf_enr_suppress( 488 "nearend_tuning_mask_lf_enr_suppress", 489 adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress); 490 FieldTrialParameter<double> nearend_tuning_mask_hf_enr_transparent( 491 "nearend_tuning_mask_hf_enr_transparent", 492 adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent); 493 FieldTrialParameter<double> nearend_tuning_mask_hf_enr_suppress( 494 "nearend_tuning_mask_hf_enr_suppress", 495 adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress); 496 FieldTrialParameter<double> nearend_tuning_max_inc_factor( 497 "nearend_tuning_max_inc_factor", 498 adjusted_cfg.suppressor.nearend_tuning.max_inc_factor); 499 FieldTrialParameter<double> nearend_tuning_max_dec_factor_lf( 500 "nearend_tuning_max_dec_factor_lf", 501 adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf); 502 FieldTrialParameter<double> normal_tuning_mask_lf_enr_transparent( 503 "normal_tuning_mask_lf_enr_transparent", 504 adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent); 505 FieldTrialParameter<double> normal_tuning_mask_lf_enr_suppress( 506 "normal_tuning_mask_lf_enr_suppress", 507 adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress); 508 FieldTrialParameter<double> normal_tuning_mask_hf_enr_transparent( 509 "normal_tuning_mask_hf_enr_transparent", 510 adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent); 511 FieldTrialParameter<double> normal_tuning_mask_hf_enr_suppress( 512 "normal_tuning_mask_hf_enr_suppress", 513 adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress); 514 FieldTrialParameter<double> normal_tuning_max_inc_factor( 515 "normal_tuning_max_inc_factor", 516 adjusted_cfg.suppressor.normal_tuning.max_inc_factor); 517 FieldTrialParameter<double> normal_tuning_max_dec_factor_lf( 518 "normal_tuning_max_dec_factor_lf", 519 adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf); 520 FieldTrialParameter<double> dominant_nearend_detection_enr_threshold( 521 "dominant_nearend_detection_enr_threshold", 522 adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold); 523 FieldTrialParameter<double> dominant_nearend_detection_enr_exit_threshold( 524 "dominant_nearend_detection_enr_exit_threshold", 525 adjusted_cfg.suppressor.dominant_nearend_detection.enr_exit_threshold); 526 FieldTrialParameter<double> dominant_nearend_detection_snr_threshold( 527 "dominant_nearend_detection_snr_threshold", 528 adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold); 529 FieldTrialParameter<int> dominant_nearend_detection_hold_duration( 530 "dominant_nearend_detection_hold_duration", 531 adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration); 532 FieldTrialParameter<int> dominant_nearend_detection_trigger_threshold( 533 "dominant_nearend_detection_trigger_threshold", 534 adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold); 535 536 ParseFieldTrial( 537 {&nearend_tuning_mask_lf_enr_transparent, 538 &nearend_tuning_mask_lf_enr_suppress, 539 &nearend_tuning_mask_hf_enr_transparent, 540 &nearend_tuning_mask_hf_enr_suppress, &nearend_tuning_max_inc_factor, 541 &nearend_tuning_max_dec_factor_lf, 542 &normal_tuning_mask_lf_enr_transparent, 543 &normal_tuning_mask_lf_enr_suppress, 544 &normal_tuning_mask_hf_enr_transparent, 545 &normal_tuning_mask_hf_enr_suppress, &normal_tuning_max_inc_factor, 546 &normal_tuning_max_dec_factor_lf, 547 &dominant_nearend_detection_enr_threshold, 548 &dominant_nearend_detection_enr_exit_threshold, 549 &dominant_nearend_detection_snr_threshold, 550 &dominant_nearend_detection_hold_duration, 551 &dominant_nearend_detection_trigger_threshold}, 552 suppressor_tuning_override_trial_name); 553 554 adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent = 555 static_cast<float>(nearend_tuning_mask_lf_enr_transparent.Get()); 556 adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress = 557 static_cast<float>(nearend_tuning_mask_lf_enr_suppress.Get()); 558 adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent = 559 static_cast<float>(nearend_tuning_mask_hf_enr_transparent.Get()); 560 adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress = 561 static_cast<float>(nearend_tuning_mask_hf_enr_suppress.Get()); 562 adjusted_cfg.suppressor.nearend_tuning.max_inc_factor = 563 static_cast<float>(nearend_tuning_max_inc_factor.Get()); 564 adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf = 565 static_cast<float>(nearend_tuning_max_dec_factor_lf.Get()); 566 adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent = 567 static_cast<float>(normal_tuning_mask_lf_enr_transparent.Get()); 568 adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress = 569 static_cast<float>(normal_tuning_mask_lf_enr_suppress.Get()); 570 adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent = 571 static_cast<float>(normal_tuning_mask_hf_enr_transparent.Get()); 572 adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress = 573 static_cast<float>(normal_tuning_mask_hf_enr_suppress.Get()); 574 adjusted_cfg.suppressor.normal_tuning.max_inc_factor = 575 static_cast<float>(normal_tuning_max_inc_factor.Get()); 576 adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf = 577 static_cast<float>(normal_tuning_max_dec_factor_lf.Get()); 578 adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold = 579 static_cast<float>(dominant_nearend_detection_enr_threshold.Get()); 580 adjusted_cfg.suppressor.dominant_nearend_detection.enr_exit_threshold = 581 static_cast<float>(dominant_nearend_detection_enr_exit_threshold.Get()); 582 adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold = 583 static_cast<float>(dominant_nearend_detection_snr_threshold.Get()); 584 adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration = 585 dominant_nearend_detection_hold_duration.Get(); 586 adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold = 587 dominant_nearend_detection_trigger_threshold.Get(); 588 589 // Field trial-based overrides of individual suppressor parameters. 590 RetrieveFieldTrialValue( 591 field_trials, "WebRTC-Aec3SuppressorNearendLfMaskTransparentOverride", 592 0.f, 10.f, 593 &adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent); 594 RetrieveFieldTrialValue( 595 field_trials, "WebRTC-Aec3SuppressorNearendLfMaskSuppressOverride", 0.f, 596 10.f, &adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress); 597 RetrieveFieldTrialValue( 598 field_trials, "WebRTC-Aec3SuppressorNearendHfMaskTransparentOverride", 599 0.f, 10.f, 600 &adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent); 601 RetrieveFieldTrialValue( 602 field_trials, "WebRTC-Aec3SuppressorNearendHfMaskSuppressOverride", 0.f, 603 10.f, &adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress); 604 RetrieveFieldTrialValue( 605 field_trials, "WebRTC-Aec3SuppressorNearendMaxIncFactorOverride", 0.f, 606 10.f, &adjusted_cfg.suppressor.nearend_tuning.max_inc_factor); 607 RetrieveFieldTrialValue( 608 field_trials, "WebRTC-Aec3SuppressorNearendMaxDecFactorLfOverride", 0.f, 609 10.f, &adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf); 610 611 RetrieveFieldTrialValue( 612 field_trials, "WebRTC-Aec3SuppressorNormalLfMaskTransparentOverride", 0.f, 613 10.f, &adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent); 614 RetrieveFieldTrialValue( 615 field_trials, "WebRTC-Aec3SuppressorNormalLfMaskSuppressOverride", 0.f, 616 10.f, &adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress); 617 RetrieveFieldTrialValue( 618 field_trials, "WebRTC-Aec3SuppressorNormalHfMaskTransparentOverride", 0.f, 619 10.f, &adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent); 620 RetrieveFieldTrialValue( 621 field_trials, "WebRTC-Aec3SuppressorNormalHfMaskSuppressOverride", 0.f, 622 10.f, &adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress); 623 RetrieveFieldTrialValue( 624 field_trials, "WebRTC-Aec3SuppressorNormalMaxIncFactorOverride", 0.f, 625 10.f, &adjusted_cfg.suppressor.normal_tuning.max_inc_factor); 626 RetrieveFieldTrialValue( 627 field_trials, "WebRTC-Aec3SuppressorNormalMaxDecFactorLfOverride", 0.f, 628 10.f, &adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf); 629 630 RetrieveFieldTrialValue( 631 field_trials, "WebRTC-Aec3SuppressorDominantNearendEnrThresholdOverride", 632 0.f, 100.f, 633 &adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold); 634 RetrieveFieldTrialValue( 635 field_trials, 636 "WebRTC-Aec3SuppressorDominantNearendEnrExitThresholdOverride", 0.f, 637 100.f, 638 &adjusted_cfg.suppressor.dominant_nearend_detection.enr_exit_threshold); 639 RetrieveFieldTrialValue( 640 field_trials, "WebRTC-Aec3SuppressorDominantNearendSnrThresholdOverride", 641 0.f, 100.f, 642 &adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold); 643 RetrieveFieldTrialValue( 644 field_trials, "WebRTC-Aec3SuppressorDominantNearendHoldDurationOverride", 645 0, 1000, 646 &adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration); 647 RetrieveFieldTrialValue( 648 field_trials, 649 "WebRTC-Aec3SuppressorDominantNearendTriggerThresholdOverride", 0, 1000, 650 &adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold); 651 652 RetrieveFieldTrialValue( 653 field_trials, "WebRTC-Aec3SuppressorAntiHowlingGainOverride", 0.f, 10.f, 654 &adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain); 655 656 // Field trial-based overrides of individual delay estimator parameters. 657 RetrieveFieldTrialValue(field_trials, 658 "WebRTC-Aec3DelayEstimateSmoothingOverride", 0.f, 1.f, 659 &adjusted_cfg.delay.delay_estimate_smoothing); 660 RetrieveFieldTrialValue( 661 field_trials, "WebRTC-Aec3DelayEstimateSmoothingDelayFoundOverride", 0.f, 662 1.f, &adjusted_cfg.delay.delay_estimate_smoothing_delay_found); 663 664 int max_allowed_excess_render_blocks_override = 665 adjusted_cfg.buffering.max_allowed_excess_render_blocks; 666 RetrieveFieldTrialValue( 667 field_trials, "WebRTC-Aec3BufferingMaxAllowedExcessRenderBlocksOverride", 668 0, 20, &max_allowed_excess_render_blocks_override); 669 adjusted_cfg.buffering.max_allowed_excess_render_blocks = 670 max_allowed_excess_render_blocks_override; 671 return adjusted_cfg; 672 } 673 674 class EchoCanceller3::RenderWriter { 675 public: 676 RenderWriter(ApmDataDumper* data_dumper, 677 const EchoCanceller3Config& config, 678 SwapQueue<std::vector<std::vector<std::vector<float>>>, 679 Aec3RenderQueueItemVerifier>* render_transfer_queue, 680 size_t num_bands, 681 size_t num_channels); 682 683 RenderWriter() = delete; 684 RenderWriter(const RenderWriter&) = delete; 685 RenderWriter& operator=(const RenderWriter&) = delete; 686 687 ~RenderWriter(); 688 void Insert(const AudioBuffer& input); 689 690 private: 691 ApmDataDumper* data_dumper_; 692 const size_t num_bands_; 693 const size_t num_channels_; 694 std::unique_ptr<HighPassFilter> high_pass_filter_; 695 std::vector<std::vector<std::vector<float>>> render_queue_input_frame_; 696 SwapQueue<std::vector<std::vector<std::vector<float>>>, 697 Aec3RenderQueueItemVerifier>* render_transfer_queue_; 698 }; 699 700 EchoCanceller3::RenderWriter::RenderWriter( 701 ApmDataDumper* data_dumper, 702 const EchoCanceller3Config& config, 703 SwapQueue<std::vector<std::vector<std::vector<float>>>, 704 Aec3RenderQueueItemVerifier>* render_transfer_queue, 705 size_t num_bands, 706 size_t num_channels) 707 : data_dumper_(data_dumper), 708 num_bands_(num_bands), 709 num_channels_(num_channels), 710 render_queue_input_frame_( 711 num_bands_, 712 std::vector<std::vector<float>>( 713 num_channels_, 714 std::vector<float>(AudioBuffer::kSplitBandSize, 0.f))), 715 render_transfer_queue_(render_transfer_queue) { 716 RTC_DCHECK(data_dumper); 717 if (config.filter.high_pass_filter_echo_reference) { 718 high_pass_filter_ = std::make_unique<HighPassFilter>(16000, num_channels); 719 } 720 } 721 722 EchoCanceller3::RenderWriter::~RenderWriter() = default; 723 724 void EchoCanceller3::RenderWriter::Insert(const AudioBuffer& input) { 725 RTC_DCHECK_EQ(AudioBuffer::kSplitBandSize, input.num_frames_per_band()); 726 RTC_DCHECK_EQ(num_bands_, input.num_bands()); 727 RTC_DCHECK_EQ(num_channels_, input.num_channels()); 728 729 // TODO(bugs.webrtc.org/8759) Temporary work-around. 730 if (num_bands_ != input.num_bands()) 731 return; 732 733 data_dumper_->DumpWav("aec3_render_input", AudioBuffer::kSplitBandSize, 734 &input.split_bands_const(0)[0][0], 16000, 1); 735 736 CopyBufferIntoFrame(input, num_bands_, num_channels_, 737 &render_queue_input_frame_); 738 if (high_pass_filter_) { 739 high_pass_filter_->Process(&render_queue_input_frame_[0]); 740 } 741 742 static_cast<void>(render_transfer_queue_->Insert(&render_queue_input_frame_)); 743 } 744 745 std::atomic<int> EchoCanceller3::instance_count_(0); 746 747 EchoCanceller3::EchoCanceller3( 748 const Environment& env, 749 const EchoCanceller3Config& config, 750 const std::optional<EchoCanceller3Config>& multichannel_config, 751 NeuralResidualEchoEstimator* neural_residual_echo_estimator, 752 int sample_rate_hz, 753 size_t num_render_channels, 754 size_t num_capture_channels) 755 : env_(env), 756 data_dumper_(new ApmDataDumper(instance_count_.fetch_add(1) + 1)), 757 config_(AdjustConfig(config, env.field_trials())), 758 sample_rate_hz_(sample_rate_hz), 759 num_bands_(NumBandsForRate(sample_rate_hz_)), 760 num_render_input_channels_(num_render_channels), 761 num_capture_channels_(num_capture_channels), 762 config_selector_(config_, 763 multichannel_config, 764 num_render_input_channels_), 765 multichannel_content_detector_( 766 config_selector_.active_config().multi_channel.detect_stereo_content, 767 num_render_input_channels_, 768 config_selector_.active_config() 769 .multi_channel.stereo_detection_threshold, 770 config_selector_.active_config() 771 .multi_channel.stereo_detection_timeout_threshold_seconds, 772 config_selector_.active_config() 773 .multi_channel.stereo_detection_hysteresis_seconds), 774 neural_residual_echo_estimator_(neural_residual_echo_estimator), 775 output_framer_(num_bands_, num_capture_channels_), 776 capture_blocker_(num_bands_, num_capture_channels_), 777 render_transfer_queue_( 778 kRenderTransferQueueSizeFrames, 779 std::vector<std::vector<std::vector<float>>>( 780 num_bands_, 781 std::vector<std::vector<float>>( 782 num_render_input_channels_, 783 std::vector<float>(AudioBuffer::kSplitBandSize, 0.f))), 784 Aec3RenderQueueItemVerifier(num_bands_, 785 num_render_input_channels_, 786 AudioBuffer::kSplitBandSize)), 787 render_queue_output_frame_( 788 num_bands_, 789 std::vector<std::vector<float>>( 790 num_render_input_channels_, 791 std::vector<float>(AudioBuffer::kSplitBandSize, 0.f))), 792 render_block_(num_bands_, num_render_input_channels_), 793 capture_block_(num_bands_, num_capture_channels_), 794 capture_sub_frame_view_( 795 num_bands_, 796 std::vector<ArrayView<float>>(num_capture_channels_)) { 797 RTC_DCHECK(ValidFullBandRate(sample_rate_hz_)); 798 799 if (config_selector_.active_config().delay.fixed_capture_delay_samples > 0) { 800 block_delay_buffer_.reset(new BlockDelayBuffer( 801 num_capture_channels_, num_bands_, AudioBuffer::kSplitBandSize, 802 config_.delay.fixed_capture_delay_samples)); 803 } 804 805 render_writer_.reset(new RenderWriter( 806 data_dumper_.get(), config_selector_.active_config(), 807 &render_transfer_queue_, num_bands_, num_render_input_channels_)); 808 809 RTC_DCHECK_EQ(num_bands_, std::max(sample_rate_hz_, 16000) / 16000); 810 RTC_DCHECK_GE(kMaxNumBands, num_bands_); 811 812 if (config_selector_.active_config().filter.export_linear_aec_output) { 813 linear_output_framer_.reset( 814 new BlockFramer(/*num_bands=*/1, num_capture_channels_)); 815 linear_output_block_ = 816 std::make_unique<Block>(/*num_bands=*/1, num_capture_channels_); 817 linear_output_sub_frame_view_ = std::vector<std::vector<ArrayView<float>>>( 818 1, std::vector<ArrayView<float>>(num_capture_channels_)); 819 } 820 821 Initialize(); 822 823 RTC_LOG(LS_INFO) << "AEC3 created with sample rate: " << sample_rate_hz_ 824 << " Hz, num render channels: " << num_render_input_channels_ 825 << ", num capture channels: " << num_capture_channels_; 826 } 827 828 EchoCanceller3::~EchoCanceller3() = default; 829 830 void EchoCanceller3::Initialize() { 831 RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); 832 833 num_render_channels_to_aec_ = 834 multichannel_content_detector_.IsProperMultiChannelContentDetected() 835 ? num_render_input_channels_ 836 : 1; 837 838 config_selector_.Update( 839 multichannel_content_detector_.IsProperMultiChannelContentDetected()); 840 841 render_block_.SetNumChannels(num_render_channels_to_aec_); 842 843 render_blocker_.reset( 844 new FrameBlocker(num_bands_, num_render_channels_to_aec_)); 845 846 block_processor_ = BlockProcessor::Create( 847 env_, config_selector_.active_config(), sample_rate_hz_, 848 num_render_channels_to_aec_, num_capture_channels_, 849 neural_residual_echo_estimator_); 850 851 render_sub_frame_view_ = std::vector<std::vector<ArrayView<float>>>( 852 num_bands_, std::vector<ArrayView<float>>(num_render_channels_to_aec_)); 853 } 854 855 void EchoCanceller3::AnalyzeRender(const AudioBuffer& render) { 856 RTC_DCHECK_RUNS_SERIALIZED(&render_race_checker_); 857 858 RTC_DCHECK_EQ(render.num_channels(), num_render_input_channels_); 859 data_dumper_->DumpRaw("aec3_call_order", 860 static_cast<int>(EchoCanceller3ApiCall::kRender)); 861 862 return render_writer_->Insert(render); 863 } 864 865 void EchoCanceller3::AnalyzeCapture(const AudioBuffer& capture) { 866 RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); 867 data_dumper_->DumpWav("aec3_capture_analyze_input", capture.num_frames(), 868 capture.channels_const()[0], sample_rate_hz_, 1); 869 saturated_microphone_signal_ = false; 870 for (size_t channel = 0; channel < capture.num_channels(); ++channel) { 871 saturated_microphone_signal_ |= DetectSaturation(ArrayView<const float>( 872 capture.channels_const()[channel], capture.num_frames())); 873 if (saturated_microphone_signal_) { 874 break; 875 } 876 } 877 } 878 879 void EchoCanceller3::ProcessCapture(AudioBuffer* capture, bool level_change) { 880 ProcessCapture(capture, nullptr, level_change); 881 } 882 883 void EchoCanceller3::ProcessCapture(AudioBuffer* capture, 884 AudioBuffer* linear_output, 885 bool level_change) { 886 RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); 887 RTC_DCHECK(capture); 888 RTC_DCHECK_EQ(num_bands_, capture->num_bands()); 889 RTC_DCHECK_EQ(AudioBuffer::kSplitBandSize, capture->num_frames_per_band()); 890 RTC_DCHECK_EQ(capture->num_channels(), num_capture_channels_); 891 data_dumper_->DumpRaw("aec3_call_order", 892 static_cast<int>(EchoCanceller3ApiCall::kCapture)); 893 894 if (linear_output && !linear_output_framer_) { 895 RTC_LOG(LS_ERROR) << "Trying to retrieve the linear AEC output without " 896 "properly configuring AEC3."; 897 RTC_DCHECK_NOTREACHED(); 898 } 899 900 // Report capture call in the metrics and periodically update API call 901 // metrics. 902 api_call_metrics_.ReportCaptureCall(); 903 904 // Optionally delay the capture signal. 905 if (config_selector_.active_config().delay.fixed_capture_delay_samples > 0) { 906 RTC_DCHECK(block_delay_buffer_); 907 block_delay_buffer_->DelaySignal(capture); 908 } 909 910 ArrayView<float> capture_lower_band = ArrayView<float>( 911 &capture->split_bands(0)[0][0], AudioBuffer::kSplitBandSize); 912 913 data_dumper_->DumpWav("aec3_capture_input", capture_lower_band, 16000, 1); 914 915 EmptyRenderQueue(); 916 917 ProcessCaptureFrameContent( 918 linear_output, capture, level_change, 919 multichannel_content_detector_.IsTemporaryMultiChannelContentDetected(), 920 saturated_microphone_signal_, 0, &capture_blocker_, 921 linear_output_framer_.get(), &output_framer_, block_processor_.get(), 922 linear_output_block_.get(), &linear_output_sub_frame_view_, 923 &capture_block_, &capture_sub_frame_view_); 924 925 ProcessCaptureFrameContent( 926 linear_output, capture, level_change, 927 multichannel_content_detector_.IsTemporaryMultiChannelContentDetected(), 928 saturated_microphone_signal_, 1, &capture_blocker_, 929 linear_output_framer_.get(), &output_framer_, block_processor_.get(), 930 linear_output_block_.get(), &linear_output_sub_frame_view_, 931 &capture_block_, &capture_sub_frame_view_); 932 933 ProcessRemainingCaptureFrameContent( 934 level_change, 935 multichannel_content_detector_.IsTemporaryMultiChannelContentDetected(), 936 saturated_microphone_signal_, &capture_blocker_, 937 linear_output_framer_.get(), &output_framer_, block_processor_.get(), 938 linear_output_block_.get(), &capture_block_); 939 940 data_dumper_->DumpWav("aec3_capture_output", AudioBuffer::kSplitBandSize, 941 &capture->split_bands(0)[0][0], 16000, 1); 942 } 943 944 EchoControl::Metrics EchoCanceller3::GetMetrics() const { 945 RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); 946 Metrics metrics; 947 block_processor_->GetMetrics(&metrics); 948 return metrics; 949 } 950 951 void EchoCanceller3::SetAudioBufferDelay(int delay_ms) { 952 RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); 953 block_processor_->SetAudioBufferDelay(delay_ms); 954 } 955 956 void EchoCanceller3::SetCaptureOutputUsage(bool capture_output_used) { 957 RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); 958 block_processor_->SetCaptureOutputUsage(capture_output_used); 959 } 960 961 bool EchoCanceller3::ActiveProcessing() const { 962 return true; 963 } 964 965 void EchoCanceller3::SetBlockProcessorForTesting( 966 std::unique_ptr<BlockProcessor> block_processor) { 967 RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); 968 RTC_DCHECK(block_processor); 969 block_processor_ = std::move(block_processor); 970 } 971 972 void EchoCanceller3::EmptyRenderQueue() { 973 RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); 974 bool frame_to_buffer = 975 render_transfer_queue_.Remove(&render_queue_output_frame_); 976 while (frame_to_buffer) { 977 // Report render call in the metrics. 978 api_call_metrics_.ReportRenderCall(); 979 980 if (multichannel_content_detector_.UpdateDetection( 981 render_queue_output_frame_)) { 982 // Reinitialize the AEC when proper stereo is detected. 983 Initialize(); 984 } 985 986 // Buffer frame content. 987 BufferRenderFrameContent( 988 /*proper_downmix_needed=*/multichannel_content_detector_ 989 .IsTemporaryMultiChannelContentDetected(), 990 &render_queue_output_frame_, 0, render_blocker_.get(), 991 block_processor_.get(), &render_block_, &render_sub_frame_view_); 992 993 BufferRenderFrameContent( 994 /*proper_downmix_needed=*/multichannel_content_detector_ 995 .IsTemporaryMultiChannelContentDetected(), 996 &render_queue_output_frame_, 1, render_blocker_.get(), 997 block_processor_.get(), &render_block_, &render_sub_frame_view_); 998 999 BufferRemainingRenderFrameContent(render_blocker_.get(), 1000 block_processor_.get(), &render_block_); 1001 1002 frame_to_buffer = 1003 render_transfer_queue_.Remove(&render_queue_output_frame_); 1004 } 1005 } 1006 } // namespace webrtc