• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2019 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 "test/pc/e2e/echo/echo_emulation.h"
11 
12 #include <limits>
13 #include <utility>
14 
15 namespace webrtc {
16 namespace webrtc_pc_e2e {
17 namespace {
18 
19 constexpr int kSingleBufferDurationMs = 10;
20 
21 }  // namespace
22 
EchoEmulatingCapturer(std::unique_ptr<TestAudioDeviceModule::Capturer> capturer,PeerConnectionE2EQualityTestFixture::EchoEmulationConfig config)23 EchoEmulatingCapturer::EchoEmulatingCapturer(
24     std::unique_ptr<TestAudioDeviceModule::Capturer> capturer,
25     PeerConnectionE2EQualityTestFixture::EchoEmulationConfig config)
26     : delegate_(std::move(capturer)),
27       config_(config),
28       renderer_queue_(2 * config_.echo_delay.ms() / kSingleBufferDurationMs),
29       queue_input_(TestAudioDeviceModule::SamplesPerFrame(
30                        delegate_->SamplingFrequency()) *
31                    delegate_->NumChannels()),
32       queue_output_(TestAudioDeviceModule::SamplesPerFrame(
33                         delegate_->SamplingFrequency()) *
34                     delegate_->NumChannels()) {
35   renderer_thread_.Detach();
36   capturer_thread_.Detach();
37 }
38 
OnAudioRendered(rtc::ArrayView<const int16_t> data)39 void EchoEmulatingCapturer::OnAudioRendered(
40     rtc::ArrayView<const int16_t> data) {
41   RTC_DCHECK_RUN_ON(&renderer_thread_);
42   if (!recording_started_) {
43     // Because rendering can start before capturing in the beginning we can have
44     // a set of empty audio data frames. So we will skip them and will start
45     // fill the queue only after 1st non-empty audio data frame will arrive.
46     bool is_empty = true;
47     for (auto d : data) {
48       if (d != 0) {
49         is_empty = false;
50         break;
51       }
52     }
53     if (is_empty) {
54       return;
55     }
56     recording_started_ = true;
57   }
58   queue_input_.assign(data.begin(), data.end());
59   if (!renderer_queue_.Insert(&queue_input_)) {
60     RTC_LOG(WARNING) << "Echo queue is full";
61   }
62 }
63 
Capture(rtc::BufferT<int16_t> * buffer)64 bool EchoEmulatingCapturer::Capture(rtc::BufferT<int16_t>* buffer) {
65   RTC_DCHECK_RUN_ON(&capturer_thread_);
66   bool result = delegate_->Capture(buffer);
67   // Now we have to reduce input signal to avoid saturation when mixing in the
68   // fake echo.
69   for (size_t i = 0; i < buffer->size(); ++i) {
70     (*buffer)[i] /= 2;
71   }
72 
73   // When we accumulated enough delay in the echo buffer we will pop from
74   // that buffer on each ::Capture(...) call. If the buffer become empty it
75   // will mean some bug, so we will crash during removing item from the queue.
76   if (!delay_accumulated_) {
77     delay_accumulated_ =
78         renderer_queue_.SizeAtLeast() >=
79         static_cast<size_t>(config_.echo_delay.ms() / kSingleBufferDurationMs);
80   }
81 
82   if (delay_accumulated_) {
83     RTC_CHECK(renderer_queue_.Remove(&queue_output_));
84     for (size_t i = 0; i < buffer->size() && i < queue_output_.size(); ++i) {
85       int32_t res = (*buffer)[i] + queue_output_[i];
86       if (res < std::numeric_limits<int16_t>::min()) {
87         res = std::numeric_limits<int16_t>::min();
88       }
89       if (res > std::numeric_limits<int16_t>::max()) {
90         res = std::numeric_limits<int16_t>::max();
91       }
92       (*buffer)[i] = static_cast<int16_t>(res);
93     }
94   }
95 
96   return result;
97 }
98 
EchoEmulatingRenderer(std::unique_ptr<TestAudioDeviceModule::Renderer> renderer,EchoEmulatingCapturer * echo_emulating_capturer)99 EchoEmulatingRenderer::EchoEmulatingRenderer(
100     std::unique_ptr<TestAudioDeviceModule::Renderer> renderer,
101     EchoEmulatingCapturer* echo_emulating_capturer)
102     : delegate_(std::move(renderer)),
103       echo_emulating_capturer_(echo_emulating_capturer) {
104   RTC_DCHECK(echo_emulating_capturer_);
105 }
106 
Render(rtc::ArrayView<const int16_t> data)107 bool EchoEmulatingRenderer::Render(rtc::ArrayView<const int16_t> data) {
108   if (data.size() > 0) {
109     echo_emulating_capturer_->OnAudioRendered(data);
110   }
111   return delegate_->Render(data);
112 }
113 
114 }  // namespace webrtc_pc_e2e
115 }  // namespace webrtc
116