diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/libwebrtc/test/pc/e2e/echo/echo_emulation.cc | 117 | ||||
-rw-r--r-- | third_party/libwebrtc/test/pc/e2e/echo/echo_emulation.h | 79 |
2 files changed, 196 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/pc/e2e/echo/echo_emulation.cc b/third_party/libwebrtc/test/pc/e2e/echo/echo_emulation.cc new file mode 100644 index 0000000000..8fdabeb16f --- /dev/null +++ b/third_party/libwebrtc/test/pc/e2e/echo/echo_emulation.cc @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/pc/e2e/echo/echo_emulation.h" + +#include <limits> +#include <utility> + +#include "api/test/pclf/media_configuration.h" + +namespace webrtc { +namespace webrtc_pc_e2e { +namespace { + +constexpr int kSingleBufferDurationMs = 10; + +} // namespace + +EchoEmulatingCapturer::EchoEmulatingCapturer( + std::unique_ptr<TestAudioDeviceModule::Capturer> capturer, + EchoEmulationConfig config) + : delegate_(std::move(capturer)), + config_(config), + renderer_queue_(2 * config_.echo_delay.ms() / kSingleBufferDurationMs), + queue_input_(TestAudioDeviceModule::SamplesPerFrame( + delegate_->SamplingFrequency()) * + delegate_->NumChannels()), + queue_output_(TestAudioDeviceModule::SamplesPerFrame( + delegate_->SamplingFrequency()) * + delegate_->NumChannels()) { + renderer_thread_.Detach(); + capturer_thread_.Detach(); +} + +void EchoEmulatingCapturer::OnAudioRendered( + rtc::ArrayView<const int16_t> data) { + RTC_DCHECK_RUN_ON(&renderer_thread_); + if (!recording_started_) { + // Because rendering can start before capturing in the beginning we can have + // a set of empty audio data frames. So we will skip them and will start + // fill the queue only after 1st non-empty audio data frame will arrive. + bool is_empty = true; + for (auto d : data) { + if (d != 0) { + is_empty = false; + break; + } + } + if (is_empty) { + return; + } + recording_started_ = true; + } + queue_input_.assign(data.begin(), data.end()); + if (!renderer_queue_.Insert(&queue_input_)) { + RTC_LOG(LS_WARNING) << "Echo queue is full"; + } +} + +bool EchoEmulatingCapturer::Capture(rtc::BufferT<int16_t>* buffer) { + RTC_DCHECK_RUN_ON(&capturer_thread_); + bool result = delegate_->Capture(buffer); + // Now we have to reduce input signal to avoid saturation when mixing in the + // fake echo. + for (size_t i = 0; i < buffer->size(); ++i) { + (*buffer)[i] /= 2; + } + + // When we accumulated enough delay in the echo buffer we will pop from + // that buffer on each ::Capture(...) call. If the buffer become empty it + // will mean some bug, so we will crash during removing item from the queue. + if (!delay_accumulated_) { + delay_accumulated_ = + renderer_queue_.SizeAtLeast() >= + static_cast<size_t>(config_.echo_delay.ms() / kSingleBufferDurationMs); + } + + if (delay_accumulated_) { + RTC_CHECK(renderer_queue_.Remove(&queue_output_)); + for (size_t i = 0; i < buffer->size() && i < queue_output_.size(); ++i) { + int32_t res = (*buffer)[i] + queue_output_[i]; + if (res < std::numeric_limits<int16_t>::min()) { + res = std::numeric_limits<int16_t>::min(); + } + if (res > std::numeric_limits<int16_t>::max()) { + res = std::numeric_limits<int16_t>::max(); + } + (*buffer)[i] = static_cast<int16_t>(res); + } + } + + return result; +} + +EchoEmulatingRenderer::EchoEmulatingRenderer( + std::unique_ptr<TestAudioDeviceModule::Renderer> renderer, + EchoEmulatingCapturer* echo_emulating_capturer) + : delegate_(std::move(renderer)), + echo_emulating_capturer_(echo_emulating_capturer) { + RTC_DCHECK(echo_emulating_capturer_); +} + +bool EchoEmulatingRenderer::Render(rtc::ArrayView<const int16_t> data) { + if (data.size() > 0) { + echo_emulating_capturer_->OnAudioRendered(data); + } + return delegate_->Render(data); +} + +} // namespace webrtc_pc_e2e +} // namespace webrtc diff --git a/third_party/libwebrtc/test/pc/e2e/echo/echo_emulation.h b/third_party/libwebrtc/test/pc/e2e/echo/echo_emulation.h new file mode 100644 index 0000000000..359a481e46 --- /dev/null +++ b/third_party/libwebrtc/test/pc/e2e/echo/echo_emulation.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_PC_E2E_ECHO_ECHO_EMULATION_H_ +#define TEST_PC_E2E_ECHO_ECHO_EMULATION_H_ + +#include <atomic> +#include <deque> +#include <memory> +#include <vector> + +#include "api/test/pclf/media_configuration.h" +#include "modules/audio_device/include/test_audio_device.h" +#include "rtc_base/swap_queue.h" + +namespace webrtc { +namespace webrtc_pc_e2e { + +// Reduces audio input strength from provided capturer twice and adds input +// provided into EchoEmulatingCapturer::OnAudioRendered(...). +class EchoEmulatingCapturer : public TestAudioDeviceModule::Capturer { + public: + EchoEmulatingCapturer( + std::unique_ptr<TestAudioDeviceModule::Capturer> capturer, + EchoEmulationConfig config); + + void OnAudioRendered(rtc::ArrayView<const int16_t> data); + + int SamplingFrequency() const override { + return delegate_->SamplingFrequency(); + } + int NumChannels() const override { return delegate_->NumChannels(); } + bool Capture(rtc::BufferT<int16_t>* buffer) override; + + private: + std::unique_ptr<TestAudioDeviceModule::Capturer> delegate_; + const EchoEmulationConfig config_; + + SwapQueue<std::vector<int16_t>> renderer_queue_; + + SequenceChecker renderer_thread_; + std::vector<int16_t> queue_input_ RTC_GUARDED_BY(renderer_thread_); + bool recording_started_ RTC_GUARDED_BY(renderer_thread_) = false; + + SequenceChecker capturer_thread_; + std::vector<int16_t> queue_output_ RTC_GUARDED_BY(capturer_thread_); + bool delay_accumulated_ RTC_GUARDED_BY(capturer_thread_) = false; +}; + +// Renders output into provided renderer and also copy output into provided +// EchoEmulationCapturer. +class EchoEmulatingRenderer : public TestAudioDeviceModule::Renderer { + public: + EchoEmulatingRenderer( + std::unique_ptr<TestAudioDeviceModule::Renderer> renderer, + EchoEmulatingCapturer* echo_emulating_capturer); + + int SamplingFrequency() const override { + return delegate_->SamplingFrequency(); + } + int NumChannels() const override { return delegate_->NumChannels(); } + bool Render(rtc::ArrayView<const int16_t> data) override; + + private: + std::unique_ptr<TestAudioDeviceModule::Renderer> delegate_; + EchoEmulatingCapturer* echo_emulating_capturer_; +}; + +} // namespace webrtc_pc_e2e +} // namespace webrtc + +#endif // TEST_PC_E2E_ECHO_ECHO_EMULATION_H_ |