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