blob: f1d1f4de881170a034a1f82374d1159ce55af4b3 [file] [log] [blame]
Gustaf Ullberg11539f02018-10-15 13:40:29 +02001/*
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#include "modules/audio_processing/aec3/render_delay_controller.h"
11
12#include <algorithm>
13#include <memory>
14#include <numeric>
15#include <string>
16#include <vector>
17
18#include "api/audio/echo_canceller3_config.h"
19#include "modules/audio_processing/aec3/aec3_common.h"
20#include "modules/audio_processing/aec3/echo_path_delay_estimator.h"
21#include "modules/audio_processing/aec3/render_delay_controller_metrics.h"
22#include "rtc_base/atomicops.h"
23#include "rtc_base/constructormagic.h"
24#include "rtc_base/logging.h"
25#include "system_wrappers/include/field_trial.h"
26
27namespace webrtc {
28
29namespace {
30
31class RenderDelayControllerImpl2 final : public RenderDelayController {
32 public:
33 RenderDelayControllerImpl2(const EchoCanceller3Config& config,
34 int sample_rate_hz);
35 ~RenderDelayControllerImpl2() override;
36 void Reset() override;
37 void LogRenderCall() override;
38 absl::optional<DelayEstimate> GetDelay(
39 const DownsampledRenderBuffer& render_buffer,
40 size_t render_delay_buffer_delay,
41 const absl::optional<int>& echo_remover_delay,
42 rtc::ArrayView<const float> capture) override;
43
44 private:
45 static int instance_count_;
46 std::unique_ptr<ApmDataDumper> data_dumper_;
47 const int delay_headroom_blocks_;
48 const int hysteresis_limit_1_blocks_;
49 const int hysteresis_limit_2_blocks_;
50 absl::optional<DelayEstimate> delay_;
51 EchoPathDelayEstimator delay_estimator_;
52 RenderDelayControllerMetrics metrics_;
53 absl::optional<DelayEstimate> delay_samples_;
54 size_t capture_call_counter_ = 0;
55 int delay_change_counter_ = 0;
56 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderDelayControllerImpl2);
57};
58
59DelayEstimate ComputeBufferDelay(
60 const absl::optional<DelayEstimate>& current_delay,
61 int delay_headroom_blocks,
62 int hysteresis_limit_1_blocks,
63 int hysteresis_limit_2_blocks,
64 DelayEstimate estimated_delay) {
65 // The below division is not exact and the truncation is intended.
66 const int echo_path_delay_blocks = estimated_delay.delay >> kBlockSizeLog2;
67
68 // Compute the buffer delay increase required to achieve the desired latency.
69 size_t new_delay_blocks =
70 std::max(echo_path_delay_blocks - delay_headroom_blocks, 0);
71
72 // Add hysteresis.
73 if (current_delay) {
74 size_t current_delay_blocks = current_delay->delay;
75 if (new_delay_blocks > current_delay_blocks) {
76 if (new_delay_blocks <=
77 current_delay_blocks + hysteresis_limit_1_blocks) {
78 new_delay_blocks = current_delay_blocks;
79 }
80 } else if (new_delay_blocks < current_delay_blocks) {
81 size_t hysteresis_limit = std::max(
82 static_cast<int>(current_delay_blocks) - hysteresis_limit_2_blocks,
83 0);
84 if (new_delay_blocks >= hysteresis_limit) {
85 new_delay_blocks = current_delay_blocks;
86 }
87 }
88 }
89
90 DelayEstimate new_delay = estimated_delay;
91 new_delay.delay = new_delay_blocks;
92 return new_delay;
93}
94
95int RenderDelayControllerImpl2::instance_count_ = 0;
96
97RenderDelayControllerImpl2::RenderDelayControllerImpl2(
98 const EchoCanceller3Config& config,
99 int sample_rate_hz)
100 : data_dumper_(
101 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
102 delay_headroom_blocks_(
103 static_cast<int>(config.delay.delay_headroom_blocks)),
104 hysteresis_limit_1_blocks_(
105 static_cast<int>(config.delay.hysteresis_limit_1_blocks)),
106 hysteresis_limit_2_blocks_(
107 static_cast<int>(config.delay.hysteresis_limit_2_blocks)),
108 delay_estimator_(data_dumper_.get(), config) {
109 RTC_DCHECK(ValidFullBandRate(sample_rate_hz));
110 delay_estimator_.LogDelayEstimationProperties(sample_rate_hz, 0);
111}
112
113RenderDelayControllerImpl2::~RenderDelayControllerImpl2() = default;
114
115void RenderDelayControllerImpl2::Reset() {
116 delay_ = absl::nullopt;
117 delay_samples_ = absl::nullopt;
118 delay_estimator_.Reset(false);
119 delay_change_counter_ = 0;
120}
121
122void RenderDelayControllerImpl2::LogRenderCall() {}
123
124absl::optional<DelayEstimate> RenderDelayControllerImpl2::GetDelay(
125 const DownsampledRenderBuffer& render_buffer,
126 size_t render_delay_buffer_delay,
127 const absl::optional<int>& echo_remover_delay,
128 rtc::ArrayView<const float> capture) {
129 RTC_DCHECK_EQ(kBlockSize, capture.size());
130 ++capture_call_counter_;
131
132 auto delay_samples = delay_estimator_.EstimateDelay(render_buffer, capture);
133
134 // Overrule the delay estimator delay if the echo remover reports a delay.
135 if (echo_remover_delay) {
136 int total_echo_remover_delay_samples =
137 (render_delay_buffer_delay + *echo_remover_delay) * kBlockSize;
138 delay_samples = DelayEstimate(DelayEstimate::Quality::kRefined,
139 total_echo_remover_delay_samples);
140 }
141
142 if (delay_samples) {
143 // TODO(peah): Refactor the rest of the code to assume a kRefined estimate
144 // quality.
145 RTC_DCHECK(DelayEstimate::Quality::kRefined == delay_samples->quality);
146 if (!delay_samples_ || delay_samples->delay != delay_samples_->delay) {
147 delay_change_counter_ = 0;
148 }
149 if (delay_samples_) {
150 delay_samples_->blocks_since_last_change =
151 delay_samples_->delay == delay_samples->delay
152 ? delay_samples_->blocks_since_last_change + 1
153 : 0;
154 delay_samples_->blocks_since_last_update = 0;
155 delay_samples_->delay = delay_samples->delay;
156 delay_samples_->quality = delay_samples->quality;
157 } else {
158 delay_samples_ = delay_samples;
159 }
160 } else {
161 if (delay_samples_) {
162 ++delay_samples_->blocks_since_last_change;
163 ++delay_samples_->blocks_since_last_update;
164 }
165 }
166
167 if (delay_change_counter_ < 2 * kNumBlocksPerSecond) {
168 ++delay_change_counter_;
169 }
170
171 if (delay_samples_) {
172 // Compute the render delay buffer delay.
173 delay_ = ComputeBufferDelay(delay_, delay_headroom_blocks_,
174 hysteresis_limit_1_blocks_,
175 hysteresis_limit_2_blocks_, *delay_samples_);
176 }
177
178 metrics_.Update(delay_samples_ ? absl::optional<size_t>(delay_samples_->delay)
179 : absl::nullopt,
180 delay_ ? delay_->delay : 0, 0);
181
182 data_dumper_->DumpRaw("aec3_render_delay_controller_delay",
183 delay_samples ? delay_samples->delay : 0);
184 data_dumper_->DumpRaw("aec3_render_delay_controller_buffer_delay",
185 delay_ ? delay_->delay : 0);
186
187 return delay_;
188}
189
190} // namespace
191
192RenderDelayController* RenderDelayController::Create2(
193 const EchoCanceller3Config& config,
194 int sample_rate_hz) {
195 return new RenderDelayControllerImpl2(config, sample_rate_hz);
196}
197
198} // namespace webrtc