blob: eef8bfd015963ca05ae564c603d8f9891f31d2b7 [file] [log] [blame]
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +00001/*
2 * Copyright (c) 2013 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "test/fake_audio_device.h"
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +000012
13#include <algorithm>
oprypina5145842017-03-14 09:01:47 -070014#include <utility>
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +000015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "common_audio/wav_file.h"
17#include "rtc_base/checks.h"
18#include "rtc_base/random.h"
19#include "system_wrappers/include/event_wrapper.h"
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +000020
21namespace webrtc {
perkjac61b742017-01-31 13:32:49 -080022
23namespace {
24
25constexpr int kFrameLengthMs = 10;
26constexpr int kFramesPerSecond = 1000 / kFrameLengthMs;
27
perkjac61b742017-01-31 13:32:49 -080028// Assuming 10ms audio packets..
oprypina5145842017-03-14 09:01:47 -070029class PulsedNoiseCapturer final : public test::FakeAudioDevice::Capturer {
perkjac61b742017-01-31 13:32:49 -080030 public:
oprypina5145842017-03-14 09:01:47 -070031 PulsedNoiseCapturer(int16_t max_amplitude, int sampling_frequency_in_hz)
32 : sampling_frequency_in_hz_(sampling_frequency_in_hz),
33 fill_with_zero_(false),
perkjac61b742017-01-31 13:32:49 -080034 random_generator_(1),
oprypina5145842017-03-14 09:01:47 -070035 max_amplitude_(max_amplitude) {
perkjac61b742017-01-31 13:32:49 -080036 RTC_DCHECK_GT(max_amplitude, 0);
37 }
38
oprypina5145842017-03-14 09:01:47 -070039 int SamplingFrequency() const override {
40 return sampling_frequency_in_hz_;
41 }
42
43 bool Capture(rtc::BufferT<int16_t>* buffer) override {
perkjac61b742017-01-31 13:32:49 -080044 fill_with_zero_ = !fill_with_zero_;
oprypina5145842017-03-14 09:01:47 -070045 buffer->SetData(
46 test::FakeAudioDevice::SamplesPerFrame(sampling_frequency_in_hz_),
47 [&](rtc::ArrayView<int16_t> data) {
48 if (fill_with_zero_) {
49 std::fill(data.begin(), data.end(), 0);
50 } else {
51 std::generate(data.begin(), data.end(), [&]() {
52 return random_generator_.Rand(-max_amplitude_, max_amplitude_);
53 });
54 }
55 return data.size();
56 });
57 return true;
perkjac61b742017-01-31 13:32:49 -080058 }
59
60 private:
oprypina5145842017-03-14 09:01:47 -070061 int sampling_frequency_in_hz_;
perkjac61b742017-01-31 13:32:49 -080062 bool fill_with_zero_;
63 Random random_generator_;
64 const int16_t max_amplitude_;
perkjac61b742017-01-31 13:32:49 -080065};
66
oprypina5145842017-03-14 09:01:47 -070067class WavFileReader final : public test::FakeAudioDevice::Capturer {
68 public:
69 WavFileReader(std::string filename, int sampling_frequency_in_hz)
70 : sampling_frequency_in_hz_(sampling_frequency_in_hz),
71 wav_reader_(filename) {
72 RTC_CHECK_EQ(wav_reader_.sample_rate(), sampling_frequency_in_hz);
73 RTC_CHECK_EQ(wav_reader_.num_channels(), 1);
74 }
75
76 int SamplingFrequency() const override {
77 return sampling_frequency_in_hz_;
78 }
79
80 bool Capture(rtc::BufferT<int16_t>* buffer) override {
81 buffer->SetData(
82 test::FakeAudioDevice::SamplesPerFrame(sampling_frequency_in_hz_),
83 [&](rtc::ArrayView<int16_t> data) {
84 return wav_reader_.ReadSamples(data.size(), data.data());
85 });
86 return buffer->size() > 0;
87 }
88
89 private:
90 int sampling_frequency_in_hz_;
91 WavReader wav_reader_;
92};
93
94class WavFileWriter final : public test::FakeAudioDevice::Renderer {
95 public:
96 WavFileWriter(std::string filename, int sampling_frequency_in_hz)
97 : sampling_frequency_in_hz_(sampling_frequency_in_hz),
98 wav_writer_(filename, sampling_frequency_in_hz, 1) {}
99
100 int SamplingFrequency() const override {
101 return sampling_frequency_in_hz_;
102 }
103
104 bool Render(rtc::ArrayView<const int16_t> data) override {
105 wav_writer_.WriteSamples(data.data(), data.size());
106 return true;
107 }
108
109 private:
110 int sampling_frequency_in_hz_;
111 WavWriter wav_writer_;
112};
113
oprypin92220ff2017-03-23 03:40:03 -0700114class BoundedWavFileWriter : public test::FakeAudioDevice::Renderer {
115 public:
116 BoundedWavFileWriter(std::string filename, int sampling_frequency_in_hz)
117 : sampling_frequency_in_hz_(sampling_frequency_in_hz),
118 wav_writer_(filename, sampling_frequency_in_hz, 1),
119 silent_audio_(test::FakeAudioDevice::SamplesPerFrame(
120 sampling_frequency_in_hz), 0),
121 started_writing_(false),
122 trailing_zeros_(0) {}
123
124 int SamplingFrequency() const override {
125 return sampling_frequency_in_hz_;
126 }
127
128 bool Render(rtc::ArrayView<const int16_t> data) override {
129 const int16_t kAmplitudeThreshold = 5;
130
131 const int16_t* begin = data.begin();
132 const int16_t* end = data.end();
133 if (!started_writing_) {
134 // Cut off silence at the beginning.
135 while (begin < end) {
136 if (std::abs(*begin) > kAmplitudeThreshold) {
137 started_writing_ = true;
138 break;
139 }
140 ++begin;
141 }
142 }
143 if (started_writing_) {
144 // Cut off silence at the end.
145 while (begin < end) {
146 if (*(end - 1) != 0) {
147 break;
148 }
149 --end;
150 }
151 if (begin < end) {
152 // If it turns out that the silence was not final, need to write all the
153 // skipped zeros and continue writing audio.
154 while (trailing_zeros_ > 0) {
155 const size_t zeros_to_write = std::min(trailing_zeros_,
156 silent_audio_.size());
157 wav_writer_.WriteSamples(silent_audio_.data(), zeros_to_write);
158 trailing_zeros_ -= zeros_to_write;
159 }
160 wav_writer_.WriteSamples(begin, end - begin);
161 }
162 // Save the number of zeros we skipped in case this needs to be restored.
163 trailing_zeros_ += data.end() - end;
164 }
165 return true;
166 }
167
168 private:
169 int sampling_frequency_in_hz_;
170 WavWriter wav_writer_;
171 std::vector<int16_t> silent_audio_;
172 bool started_writing_;
173 size_t trailing_zeros_;
174};
175
176
oprypina5145842017-03-14 09:01:47 -0700177class DiscardRenderer final : public test::FakeAudioDevice::Renderer {
178 public:
179 explicit DiscardRenderer(int sampling_frequency_in_hz)
180 : sampling_frequency_in_hz_(sampling_frequency_in_hz) {}
181
182 int SamplingFrequency() const override {
183 return sampling_frequency_in_hz_;
184 }
185
186 bool Render(rtc::ArrayView<const int16_t> data) override {
187 return true;
188 }
189
190 private:
191 int sampling_frequency_in_hz_;
192};
193
194} // namespace
195namespace test {
196
197size_t FakeAudioDevice::SamplesPerFrame(int sampling_frequency_in_hz) {
198 return rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond);
199}
200
201std::unique_ptr<FakeAudioDevice::Capturer>
202 FakeAudioDevice::CreatePulsedNoiseCapturer(
203 int16_t max_amplitude, int sampling_frequency_in_hz) {
204 return std::unique_ptr<FakeAudioDevice::Capturer>(
205 new PulsedNoiseCapturer(max_amplitude, sampling_frequency_in_hz));
206}
207
208std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader(
209 std::string filename, int sampling_frequency_in_hz) {
210 return std::unique_ptr<FakeAudioDevice::Capturer>(
211 new WavFileReader(filename, sampling_frequency_in_hz));
212}
213
214std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader(
215 std::string filename) {
216 int sampling_frequency_in_hz = WavReader(filename).sample_rate();
217 return std::unique_ptr<FakeAudioDevice::Capturer>(
218 new WavFileReader(filename, sampling_frequency_in_hz));
219}
220
221std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateWavFileWriter(
222 std::string filename, int sampling_frequency_in_hz) {
223 return std::unique_ptr<FakeAudioDevice::Renderer>(
224 new WavFileWriter(filename, sampling_frequency_in_hz));
225}
226
227std::unique_ptr<FakeAudioDevice::Renderer>
oprypin92220ff2017-03-23 03:40:03 -0700228 FakeAudioDevice::CreateBoundedWavFileWriter(
229 std::string filename, int sampling_frequency_in_hz) {
230 return std::unique_ptr<FakeAudioDevice::Renderer>(
231 new BoundedWavFileWriter(filename, sampling_frequency_in_hz));
232}
233
234std::unique_ptr<FakeAudioDevice::Renderer>
oprypina5145842017-03-14 09:01:47 -0700235 FakeAudioDevice::CreateDiscardRenderer(int sampling_frequency_in_hz) {
236 return std::unique_ptr<FakeAudioDevice::Renderer>(
237 new DiscardRenderer(sampling_frequency_in_hz));
238}
239
240
241FakeAudioDevice::FakeAudioDevice(std::unique_ptr<Capturer> capturer,
242 std::unique_ptr<Renderer> renderer,
243 float speed)
244 : capturer_(std::move(capturer)),
245 renderer_(std::move(renderer)),
danilchap9c6a0c72016-02-10 10:54:47 -0800246 speed_(speed),
perkjac61b742017-01-31 13:32:49 -0800247 audio_callback_(nullptr),
248 rendering_(false),
249 capturing_(false),
oprypina5145842017-03-14 09:01:47 -0700250 done_rendering_(true, true),
251 done_capturing_(true, true),
Peter Boström64c03662015-04-08 11:24:19 +0200252 tick_(EventTimerWrapper::Create()),
perkjac61b742017-01-31 13:32:49 -0800253 thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") {
oprypina5145842017-03-14 09:01:47 -0700254 auto good_sample_rate = [](int sr) {
255 return sr == 8000 || sr == 16000 || sr == 32000
256 || sr == 44100 || sr == 48000;
257 };
258
259 if (renderer_) {
260 const int sample_rate = renderer_->SamplingFrequency();
261 playout_buffer_.resize(SamplesPerFrame(sample_rate), 0);
262 RTC_CHECK(good_sample_rate(sample_rate));
263 }
264 if (capturer_) {
265 RTC_CHECK(good_sample_rate(capturer_->SamplingFrequency()));
266 }
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000267}
268
269FakeAudioDevice::~FakeAudioDevice() {
perkjac61b742017-01-31 13:32:49 -0800270 StopPlayout();
271 StopRecording();
Peter Boström8c38e8b2015-11-26 17:45:47 +0100272 thread_.Stop();
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000273}
274
perkjac61b742017-01-31 13:32:49 -0800275int32_t FakeAudioDevice::StartPlayout() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200276 rtc::CritScope cs(&lock_);
oprypina5145842017-03-14 09:01:47 -0700277 RTC_CHECK(renderer_);
perkjac61b742017-01-31 13:32:49 -0800278 rendering_ = true;
oprypina5145842017-03-14 09:01:47 -0700279 done_rendering_.Reset();
perkjac61b742017-01-31 13:32:49 -0800280 return 0;
281}
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000282
perkjac61b742017-01-31 13:32:49 -0800283int32_t FakeAudioDevice::StopPlayout() {
284 rtc::CritScope cs(&lock_);
285 rendering_ = false;
oprypina5145842017-03-14 09:01:47 -0700286 done_rendering_.Set();
perkjac61b742017-01-31 13:32:49 -0800287 return 0;
288}
289
290int32_t FakeAudioDevice::StartRecording() {
291 rtc::CritScope cs(&lock_);
oprypina5145842017-03-14 09:01:47 -0700292 RTC_CHECK(capturer_);
perkjac61b742017-01-31 13:32:49 -0800293 capturing_ = true;
oprypina5145842017-03-14 09:01:47 -0700294 done_capturing_.Reset();
perkjac61b742017-01-31 13:32:49 -0800295 return 0;
296}
297
298int32_t FakeAudioDevice::StopRecording() {
299 rtc::CritScope cs(&lock_);
300 capturing_ = false;
oprypina5145842017-03-14 09:01:47 -0700301 done_capturing_.Set();
perkjac61b742017-01-31 13:32:49 -0800302 return 0;
303}
304
305int32_t FakeAudioDevice::Init() {
306 RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_));
Peter Boström8c38e8b2015-11-26 17:45:47 +0100307 thread_.Start();
308 thread_.SetPriority(rtc::kHighPriority);
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000309 return 0;
310}
311
312int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200313 rtc::CritScope cs(&lock_);
oprypina5145842017-03-14 09:01:47 -0700314 RTC_DCHECK(callback || audio_callback_);
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000315 audio_callback_ = callback;
316 return 0;
317}
318
319bool FakeAudioDevice::Playing() const {
Peter Boströmf2f82832015-05-01 13:00:41 +0200320 rtc::CritScope cs(&lock_);
perkjac61b742017-01-31 13:32:49 -0800321 return rendering_;
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000322}
323
324bool FakeAudioDevice::Recording() const {
Peter Boströmf2f82832015-05-01 13:00:41 +0200325 rtc::CritScope cs(&lock_);
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000326 return capturing_;
327}
328
oprypina5145842017-03-14 09:01:47 -0700329bool FakeAudioDevice::WaitForPlayoutEnd(int timeout_ms) {
330 return done_rendering_.Wait(timeout_ms);
331}
332
333bool FakeAudioDevice::WaitForRecordingEnd(int timeout_ms) {
334 return done_capturing_.Wait(timeout_ms);
335}
336
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000337bool FakeAudioDevice::Run(void* obj) {
perkjac61b742017-01-31 13:32:49 -0800338 static_cast<FakeAudioDevice*>(obj)->ProcessAudio();
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000339 return true;
340}
341
perkjac61b742017-01-31 13:32:49 -0800342void FakeAudioDevice::ProcessAudio() {
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000343 {
Peter Boströmf2f82832015-05-01 13:00:41 +0200344 rtc::CritScope cs(&lock_);
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000345 if (capturing_) {
perkjac61b742017-01-31 13:32:49 -0800346 // Capture 10ms of audio. 2 bytes per sample.
oprypina5145842017-03-14 09:01:47 -0700347 const bool keep_capturing = capturer_->Capture(&recording_buffer_);
348 uint32_t new_mic_level;
349 if (recording_buffer_.size() > 0) {
350 audio_callback_->RecordedDataIsAvailable(
351 recording_buffer_.data(), recording_buffer_.size(), 2, 1,
352 capturer_->SamplingFrequency(), 0, 0, 0, false, new_mic_level);
353 }
354 if (!keep_capturing) {
355 capturing_ = false;
356 done_capturing_.Set();
357 }
perkjac61b742017-01-31 13:32:49 -0800358 }
359 if (rendering_) {
oprypina5145842017-03-14 09:01:47 -0700360 size_t samples_out;
361 int64_t elapsed_time_ms;
362 int64_t ntp_time_ms;
363 const int sampling_frequency = renderer_->SamplingFrequency();
perkjac61b742017-01-31 13:32:49 -0800364 audio_callback_->NeedMorePlayData(
oprypina5145842017-03-14 09:01:47 -0700365 SamplesPerFrame(sampling_frequency), 2, 1, sampling_frequency,
perkjac61b742017-01-31 13:32:49 -0800366 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms);
oprypina5145842017-03-14 09:01:47 -0700367 const bool keep_rendering = renderer_->Render(
368 rtc::ArrayView<const int16_t>(playout_buffer_.data(), samples_out));
369 if (!keep_rendering) {
370 rendering_ = false;
371 done_rendering_.Set();
372 }
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000373 }
374 }
375 tick_->Wait(WEBRTC_EVENT_INFINITE);
376}
377
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000378
stefan@webrtc.orgb082ade2013-11-18 11:45:11 +0000379} // namespace test
380} // namespace webrtc