OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
hlundin-webrtc
2017/01/18 13:08:50
2017
peah-webrtc
2017/01/19 15:33:07
Done.
| |
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 "webrtc/modules/audio_processing/aec3/render_delay_controller.h" | |
11 | |
12 #include <algorithm> | |
13 #include <string> | |
14 #include <vector> | |
15 | |
16 #include "webrtc/base/constructormagic.h" | |
17 #include "webrtc/modules/audio_processing/aec3/aec3_constants.h" | |
18 #include "webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.h" | |
19 #include "webrtc/system_wrappers/include/logging.h" | |
20 | |
21 namespace webrtc { | |
22 | |
23 namespace { | |
24 | |
25 class RenderBuffer { | |
26 public: | |
27 explicit RenderBuffer(size_t size); | |
hlundin-webrtc
2017/01/18 13:08:50
I think you should move all the ctor and method de
peah-webrtc
2017/01/19 15:33:06
Done.
| |
28 ~RenderBuffer(); | |
29 | |
30 bool Insert(rtc::ArrayView<const float> v); | |
31 rtc::ArrayView<const float> Get(); | |
32 | |
33 size_t Size() { return size_; } | |
34 | |
35 private: | |
36 std::vector<std::vector<float>> buffer_; | |
37 size_t size_ = 0; | |
38 int last_insert_index_ = 0; | |
39 }; | |
40 | |
41 class RenderDelayControllerImpl final : public RenderDelayController { | |
42 public: | |
43 RenderDelayControllerImpl(ApmDataDumper* data_dumper, | |
44 int sample_rate_hz, | |
45 const RenderDelayBuffer& render_delay_buffer); | |
46 ~RenderDelayControllerImpl() override; | |
47 size_t SelectDelay(rtc::ArrayView<const float> capture) override; | |
48 bool AnalyzeRender(rtc::ArrayView<const float> render) override; | |
49 rtc::Optional<size_t> AlignmentHeadroom() const override { | |
50 return headroom_samples_; | |
51 } | |
52 | |
53 private: | |
54 ApmDataDumper* const data_dumper_; | |
55 const size_t max_delay_; | |
56 size_t delay_; | |
57 RenderBuffer render_buffer_; | |
58 EchoPathDelayEstimator delay_estimator_; | |
59 size_t blocks_since_last_delay_estimate_ = 300000; | |
60 int echo_path_delay_samples_ = 0; | |
61 size_t align_call_counter_ = 0; | |
62 rtc::Optional<size_t> headroom_samples_; | |
63 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderDelayControllerImpl); | |
64 }; | |
65 | |
66 size_t ComputeNewBufferDelay(size_t current_delay, | |
67 size_t max_delay, | |
68 size_t echo_path_delay_samples) { | |
69 const int echo_path_delay_blocks = echo_path_delay_samples / kBlockSize; | |
hlundin-webrtc
2017/01/18 13:08:50
Is this division supposed to be exact, or is trunc
peah-webrtc
2017/01/19 15:33:07
It is not supposed to be exact, and truncation is
| |
70 constexpr int kDelayHeadroomBlocks = 1; | |
71 | |
72 // Compute the buffer delay increase required to achieve the desired latency. | |
73 size_t new_delay = std::max(echo_path_delay_blocks - kDelayHeadroomBlocks, 0); | |
74 | |
75 // Add hysteresis. | |
76 if (new_delay == current_delay + 1 || new_delay + 1 == current_delay) { | |
77 new_delay = current_delay; | |
78 } | |
79 | |
80 // Limit the delay to what is possible. | |
81 new_delay = std::min(new_delay, max_delay); | |
82 | |
83 return new_delay; | |
84 } | |
85 | |
86 RenderDelayControllerImpl::RenderDelayControllerImpl( | |
87 ApmDataDumper* data_dumper, | |
88 int sample_rate_hz, | |
89 const RenderDelayBuffer& render_delay_buffer) | |
90 : data_dumper_(data_dumper), | |
91 max_delay_(render_delay_buffer.MaxDelay()), | |
92 delay_(render_delay_buffer.Delay()), | |
93 render_buffer_(render_delay_buffer.MaxApiJitter() + 1), | |
94 delay_estimator_(data_dumper_, sample_rate_hz) { | |
95 RTC_DCHECK(data_dumper); | |
96 RTC_DCHECK(sample_rate_hz == 8000 || sample_rate_hz == 16000 || | |
97 sample_rate_hz == 32000 || sample_rate_hz == 48000); | |
98 } | |
99 | |
100 RenderDelayControllerImpl::~RenderDelayControllerImpl() = default; | |
101 | |
102 size_t RenderDelayControllerImpl::SelectDelay( | |
103 rtc::ArrayView<const float> capture) { | |
104 RTC_DCHECK_EQ(kBlockSize, capture.size()); | |
105 if (render_buffer_.Size() == 0) { | |
106 return false; | |
hlundin-webrtc
2017/01/18 13:08:50
Eh, this must be a mistake. The return type is siz
peah-webrtc
2017/01/19 15:33:06
Good find!
Done.
| |
107 } | |
108 | |
109 ++align_call_counter_; | |
110 rtc::ArrayView<const float> render = render_buffer_.Get(); | |
111 rtc::Optional<size_t> echo_path_delay_samples = | |
112 delay_estimator_.EstimateDelay(render, capture); | |
113 if (echo_path_delay_samples) { | |
114 echo_path_delay_samples_ = *echo_path_delay_samples; | |
115 | |
116 // Compute and set new render delay buffer delay. | |
117 const size_t new_delay = | |
118 ComputeNewBufferDelay(delay_, max_delay_, echo_path_delay_samples_); | |
119 if (new_delay != delay_ && align_call_counter_ > 250) { | |
120 delay_ = new_delay; | |
121 } | |
122 | |
123 // Update render delay buffer headroom. | |
124 blocks_since_last_delay_estimate_ = 0; | |
125 const int headroom = echo_path_delay_samples_ - delay_ * kBlockSize; | |
126 RTC_DCHECK_LE(0, headroom); | |
127 headroom_samples_ = rtc::Optional<size_t>(headroom); | |
128 } else if (++blocks_since_last_delay_estimate_ > 25000) { | |
129 headroom_samples_ = rtc::Optional<size_t>(); | |
130 } | |
131 | |
132 data_dumper_->DumpRaw("aec3_render_delay_controller_delay", 1, | |
133 &echo_path_delay_samples_); | |
134 data_dumper_->DumpRaw("aec3_render_delay_controller_buffer_delay", delay_); | |
135 | |
136 return delay_; | |
137 } | |
138 | |
139 bool RenderDelayControllerImpl::AnalyzeRender( | |
140 rtc::ArrayView<const float> render) { | |
141 return render_buffer_.Insert(render); | |
142 } | |
143 | |
144 RenderBuffer::RenderBuffer(size_t size) | |
145 : buffer_(size, std::vector<float>(kBlockSize, 0.f)) {} | |
146 | |
147 RenderBuffer::~RenderBuffer() = default; | |
148 | |
149 bool RenderBuffer::Insert(rtc::ArrayView<const float> v) { | |
150 if (size_ == buffer_.size() - 1) { | |
hlundin-webrtc
2017/01/18 13:08:50
Why not err on the side of caution, and compare si
peah-webrtc
2017/01/19 15:33:06
Done.
| |
151 return false; | |
152 } | |
153 | |
154 last_insert_index_ = (last_insert_index_ + 1) % buffer_.size(); | |
155 RTC_DCHECK_EQ(buffer_[last_insert_index_].size(), v.size()); | |
156 | |
157 buffer_[last_insert_index_].clear(); | |
158 buffer_[last_insert_index_].insert(buffer_[last_insert_index_].begin(), | |
159 v.begin(), v.end()); | |
160 ++size_; | |
161 return true; | |
162 } | |
163 | |
164 rtc::ArrayView<const float> RenderBuffer::Get() { | |
165 RTC_DCHECK_LT(0, size_); | |
166 --size_; | |
167 return buffer_[(last_insert_index_ - size_ + buffer_.size()) % | |
168 buffer_.size()]; | |
169 } | |
170 | |
171 } // namespace | |
172 | |
173 RenderDelayController* RenderDelayController::Create( | |
174 ApmDataDumper* data_dumper, | |
175 int sample_rate_hz, | |
176 const RenderDelayBuffer& render_delay_buffer) { | |
177 return new RenderDelayControllerImpl(data_dumper, sample_rate_hz, | |
178 render_delay_buffer); | |
179 } | |
180 | |
181 } // namespace webrtc | |
OLD | NEW |