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