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