1 /*
2 * Copyright (c) 2018 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
11 #include "modules/audio_processing/aec3/echo_audibility.h"
12
13 #include <algorithm>
14 #include <cmath>
15 #include <utility>
16 #include <vector>
17
18 #include "api/array_view.h"
19 #include "modules/audio_processing/aec3/block_buffer.h"
20 #include "modules/audio_processing/aec3/spectrum_buffer.h"
21 #include "modules/audio_processing/aec3/stationarity_estimator.h"
22
23 namespace webrtc {
24
EchoAudibility(bool use_render_stationarity_at_init)25 EchoAudibility::EchoAudibility(bool use_render_stationarity_at_init)
26 : use_render_stationarity_at_init_(use_render_stationarity_at_init) {
27 Reset();
28 }
29
30 EchoAudibility::~EchoAudibility() = default;
31
Update(const RenderBuffer & render_buffer,rtc::ArrayView<const float> average_reverb,int delay_blocks,bool external_delay_seen)32 void EchoAudibility::Update(const RenderBuffer& render_buffer,
33 rtc::ArrayView<const float> average_reverb,
34 int delay_blocks,
35 bool external_delay_seen) {
36 UpdateRenderNoiseEstimator(render_buffer.GetSpectrumBuffer(),
37 render_buffer.GetBlockBuffer(),
38 external_delay_seen);
39
40 if (external_delay_seen || use_render_stationarity_at_init_) {
41 UpdateRenderStationarityFlags(render_buffer, average_reverb, delay_blocks);
42 }
43 }
44
Reset()45 void EchoAudibility::Reset() {
46 render_stationarity_.Reset();
47 non_zero_render_seen_ = false;
48 render_spectrum_write_prev_ = absl::nullopt;
49 }
50
UpdateRenderStationarityFlags(const RenderBuffer & render_buffer,rtc::ArrayView<const float> average_reverb,int min_channel_delay_blocks)51 void EchoAudibility::UpdateRenderStationarityFlags(
52 const RenderBuffer& render_buffer,
53 rtc::ArrayView<const float> average_reverb,
54 int min_channel_delay_blocks) {
55 const SpectrumBuffer& spectrum_buffer = render_buffer.GetSpectrumBuffer();
56 int idx_at_delay = spectrum_buffer.OffsetIndex(spectrum_buffer.read,
57 min_channel_delay_blocks);
58
59 int num_lookahead = render_buffer.Headroom() - min_channel_delay_blocks + 1;
60 num_lookahead = std::max(0, num_lookahead);
61
62 render_stationarity_.UpdateStationarityFlags(spectrum_buffer, average_reverb,
63 idx_at_delay, num_lookahead);
64 }
65
UpdateRenderNoiseEstimator(const SpectrumBuffer & spectrum_buffer,const BlockBuffer & block_buffer,bool external_delay_seen)66 void EchoAudibility::UpdateRenderNoiseEstimator(
67 const SpectrumBuffer& spectrum_buffer,
68 const BlockBuffer& block_buffer,
69 bool external_delay_seen) {
70 if (!render_spectrum_write_prev_) {
71 render_spectrum_write_prev_ = spectrum_buffer.write;
72 render_block_write_prev_ = block_buffer.write;
73 return;
74 }
75 int render_spectrum_write_current = spectrum_buffer.write;
76 if (!non_zero_render_seen_ && !external_delay_seen) {
77 non_zero_render_seen_ = !IsRenderTooLow(block_buffer);
78 }
79 if (non_zero_render_seen_) {
80 for (int idx = render_spectrum_write_prev_.value();
81 idx != render_spectrum_write_current;
82 idx = spectrum_buffer.DecIndex(idx)) {
83 render_stationarity_.UpdateNoiseEstimator(spectrum_buffer.buffer[idx]);
84 }
85 }
86 render_spectrum_write_prev_ = render_spectrum_write_current;
87 }
88
IsRenderTooLow(const BlockBuffer & block_buffer)89 bool EchoAudibility::IsRenderTooLow(const BlockBuffer& block_buffer) {
90 const int num_render_channels =
91 static_cast<int>(block_buffer.buffer[0][0].size());
92 bool too_low = false;
93 const int render_block_write_current = block_buffer.write;
94 if (render_block_write_current == render_block_write_prev_) {
95 too_low = true;
96 } else {
97 for (int idx = render_block_write_prev_; idx != render_block_write_current;
98 idx = block_buffer.IncIndex(idx)) {
99 float max_abs_over_channels = 0.f;
100 for (int ch = 0; ch < num_render_channels; ++ch) {
101 auto block = block_buffer.buffer[idx][0][ch];
102 auto r = std::minmax_element(block.cbegin(), block.cend());
103 float max_abs_channel =
104 std::max(std::fabs(*r.first), std::fabs(*r.second));
105 max_abs_over_channels =
106 std::max(max_abs_over_channels, max_abs_channel);
107 }
108 if (max_abs_over_channels < 10.f) {
109 too_low = true; // Discards all blocks if one of them is too low.
110 break;
111 }
112 }
113 }
114 render_block_write_prev_ = render_block_write_current;
115 return too_low;
116 }
117
118 } // namespace webrtc
119