• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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