Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: webrtc/test/fake_audio_device.cc

Issue 2717623003: Add the ability to read/write to WAV files in FakeAudioDevice (Closed)
Patch Set: Avoid repetition when checking sample rate Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/test/fake_audio_device.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/test/fake_audio_device.h" 11 #include "webrtc/test/fake_audio_device.h"
12 12
13 #include <algorithm> 13 #include <algorithm>
14 #include <utility>
14 15
15 #include "webrtc/base/array_view.h"
16 #include "webrtc/base/checks.h" 16 #include "webrtc/base/checks.h"
17 #include "webrtc/base/random.h" 17 #include "webrtc/base/random.h"
18 #include "webrtc/common_audio/wav_file.h"
18 #include "webrtc/system_wrappers/include/event_wrapper.h" 19 #include "webrtc/system_wrappers/include/event_wrapper.h"
19 20
20 namespace webrtc { 21 namespace webrtc {
21 22
22 namespace { 23 namespace {
23 24
24 constexpr int kFrameLengthMs = 10; 25 constexpr int kFrameLengthMs = 10;
25 constexpr int kFramesPerSecond = 1000 / kFrameLengthMs; 26 constexpr int kFramesPerSecond = 1000 / kFrameLengthMs;
26 27
28 // Assuming 10ms audio packets..
29 class PulsedNoiseCapturer final : public test::FakeAudioDevice::Capturer {
30 public:
31 PulsedNoiseCapturer(int16_t max_amplitude, int sampling_frequency_in_hz)
32 : sampling_frequency_in_hz_(sampling_frequency_in_hz),
33 fill_with_zero_(false),
34 random_generator_(1),
35 max_amplitude_(max_amplitude) {
36 RTC_DCHECK_GT(max_amplitude, 0);
37 }
38
39 int SamplingFrequency() const override {
40 return sampling_frequency_in_hz_;
41 }
42
43 bool Capture(rtc::BufferT<int16_t>* buffer) override {
44 fill_with_zero_ = !fill_with_zero_;
45 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;
58 }
59
60 private:
61 int sampling_frequency_in_hz_;
62 bool fill_with_zero_;
63 Random random_generator_;
64 const int16_t max_amplitude_;
65 };
66
67 class 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
94 class 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
114 class DiscardRenderer final : public test::FakeAudioDevice::Renderer {
115 public:
116 explicit DiscardRenderer(int sampling_frequency_in_hz)
117 : sampling_frequency_in_hz_(sampling_frequency_in_hz) {}
118
119 int SamplingFrequency() const override {
120 return sampling_frequency_in_hz_;
121 }
122
123 bool Render(rtc::ArrayView<const int16_t> data) override {
124 return true;
125 }
126
127 private:
128 int sampling_frequency_in_hz_;
129 };
130
27 } // namespace 131 } // namespace
28 namespace test { 132 namespace test {
29 133
30 // Assuming 10ms audio packets.. 134 size_t FakeAudioDevice::SamplesPerFrame(int sampling_frequency_in_hz) {
31 class FakeAudioDevice::PulsedNoiseCapturer { 135 return rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond);
32 public: 136 }
33 PulsedNoiseCapturer(size_t num_samples_per_frame, int16_t max_amplitude)
34 : fill_with_zero_(false),
35 random_generator_(1),
36 max_amplitude_(max_amplitude),
37 random_audio_(num_samples_per_frame),
38 silent_audio_(num_samples_per_frame, 0) {
39 RTC_DCHECK_GT(max_amplitude, 0);
40 }
41 137
42 rtc::ArrayView<const int16_t> Capture() { 138 std::unique_ptr<FakeAudioDevice::Capturer>
43 fill_with_zero_ = !fill_with_zero_; 139 FakeAudioDevice::CreatePulsedNoiseCapturer(
44 if (!fill_with_zero_) { 140 int16_t max_amplitude, int sampling_frequency_in_hz) {
45 std::generate(random_audio_.begin(), random_audio_.end(), [&]() { 141 return std::unique_ptr<FakeAudioDevice::Capturer>(
46 return random_generator_.Rand(-max_amplitude_, max_amplitude_); 142 new PulsedNoiseCapturer(max_amplitude, sampling_frequency_in_hz));
47 }); 143 }
48 }
49 return fill_with_zero_ ? silent_audio_ : random_audio_;
50 }
51 144
52 private: 145 std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader(
53 bool fill_with_zero_; 146 std::string filename, int sampling_frequency_in_hz) {
54 Random random_generator_; 147 return std::unique_ptr<FakeAudioDevice::Capturer>(
55 const int16_t max_amplitude_; 148 new WavFileReader(filename, sampling_frequency_in_hz));
56 std::vector<int16_t> random_audio_; 149 }
57 std::vector<int16_t> silent_audio_;
58 };
59 150
60 FakeAudioDevice::FakeAudioDevice(float speed, 151 std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader(
61 int sampling_frequency_in_hz, 152 std::string filename) {
62 int16_t max_amplitude) 153 int sampling_frequency_in_hz = WavReader(filename).sample_rate();
63 : sampling_frequency_in_hz_(sampling_frequency_in_hz), 154 return std::unique_ptr<FakeAudioDevice::Capturer>(
64 num_samples_per_frame_( 155 new WavFileReader(filename, sampling_frequency_in_hz));
65 rtc::CheckedDivExact(sampling_frequency_in_hz_, kFramesPerSecond)), 156 }
157
158 std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateWavFileWriter(
159 std::string filename, int sampling_frequency_in_hz) {
160 return std::unique_ptr<FakeAudioDevice::Renderer>(
161 new WavFileWriter(filename, sampling_frequency_in_hz));
162 }
163
164 std::unique_ptr<FakeAudioDevice::Renderer>
165 FakeAudioDevice::CreateDiscardRenderer(int sampling_frequency_in_hz) {
166 return std::unique_ptr<FakeAudioDevice::Renderer>(
167 new DiscardRenderer(sampling_frequency_in_hz));
168 }
169
170
171 FakeAudioDevice::FakeAudioDevice(std::unique_ptr<Capturer> capturer,
172 std::unique_ptr<Renderer> renderer,
173 float speed)
174 : capturer_(std::move(capturer)),
175 renderer_(std::move(renderer)),
66 speed_(speed), 176 speed_(speed),
67 audio_callback_(nullptr), 177 audio_callback_(nullptr),
68 rendering_(false), 178 rendering_(false),
69 capturing_(false), 179 capturing_(false),
70 capturer_(new FakeAudioDevice::PulsedNoiseCapturer(num_samples_per_frame_, 180 done_rendering_(true, true),
71 max_amplitude)), 181 done_capturing_(true, true),
72 playout_buffer_(num_samples_per_frame_, 0),
73 tick_(EventTimerWrapper::Create()), 182 tick_(EventTimerWrapper::Create()),
74 thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") { 183 thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") {
75 RTC_DCHECK( 184 auto good_sample_rate = [](int sr) {
76 sampling_frequency_in_hz == 8000 || sampling_frequency_in_hz == 16000 || 185 return sr == 8000 || sr == 16000 || sr == 32000
77 sampling_frequency_in_hz == 32000 || sampling_frequency_in_hz == 44100 || 186 || sr == 44100 || sr == 48000;
78 sampling_frequency_in_hz == 48000); 187 };
188
189 if (renderer_) {
190 const int sample_rate = renderer_->SamplingFrequency();
191 playout_buffer_.resize(SamplesPerFrame(sample_rate), 0);
192 RTC_CHECK(good_sample_rate(sample_rate));
193 }
194 if (capturer_) {
195 RTC_CHECK(good_sample_rate(capturer_->SamplingFrequency()));
196 }
79 } 197 }
80 198
81 FakeAudioDevice::~FakeAudioDevice() { 199 FakeAudioDevice::~FakeAudioDevice() {
82 StopPlayout(); 200 StopPlayout();
83 StopRecording(); 201 StopRecording();
84 thread_.Stop(); 202 thread_.Stop();
85 } 203 }
86 204
87 int32_t FakeAudioDevice::StartPlayout() { 205 int32_t FakeAudioDevice::StartPlayout() {
88 rtc::CritScope cs(&lock_); 206 rtc::CritScope cs(&lock_);
207 RTC_CHECK(renderer_);
89 rendering_ = true; 208 rendering_ = true;
209 done_rendering_.Reset();
90 return 0; 210 return 0;
91 } 211 }
92 212
93 int32_t FakeAudioDevice::StopPlayout() { 213 int32_t FakeAudioDevice::StopPlayout() {
94 rtc::CritScope cs(&lock_); 214 rtc::CritScope cs(&lock_);
95 rendering_ = false; 215 rendering_ = false;
216 done_rendering_.Set();
96 return 0; 217 return 0;
97 } 218 }
98 219
99 int32_t FakeAudioDevice::StartRecording() { 220 int32_t FakeAudioDevice::StartRecording() {
100 rtc::CritScope cs(&lock_); 221 rtc::CritScope cs(&lock_);
222 RTC_CHECK(capturer_);
101 capturing_ = true; 223 capturing_ = true;
224 done_capturing_.Reset();
102 return 0; 225 return 0;
103 } 226 }
104 227
105 int32_t FakeAudioDevice::StopRecording() { 228 int32_t FakeAudioDevice::StopRecording() {
106 rtc::CritScope cs(&lock_); 229 rtc::CritScope cs(&lock_);
107 capturing_ = false; 230 capturing_ = false;
231 done_capturing_.Set();
108 return 0; 232 return 0;
109 } 233 }
110 234
111 int32_t FakeAudioDevice::Init() { 235 int32_t FakeAudioDevice::Init() {
112 RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_)); 236 RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_));
113 thread_.Start(); 237 thread_.Start();
114 thread_.SetPriority(rtc::kHighPriority); 238 thread_.SetPriority(rtc::kHighPriority);
115 return 0; 239 return 0;
116 } 240 }
117 241
118 int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { 242 int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) {
119 rtc::CritScope cs(&lock_); 243 rtc::CritScope cs(&lock_);
120 RTC_DCHECK(callback || audio_callback_ != nullptr); 244 RTC_DCHECK(callback || audio_callback_);
121 audio_callback_ = callback; 245 audio_callback_ = callback;
122 return 0; 246 return 0;
123 } 247 }
124 248
125 bool FakeAudioDevice::Playing() const { 249 bool FakeAudioDevice::Playing() const {
126 rtc::CritScope cs(&lock_); 250 rtc::CritScope cs(&lock_);
127 return rendering_; 251 return rendering_;
128 } 252 }
129 253
130 bool FakeAudioDevice::Recording() const { 254 bool FakeAudioDevice::Recording() const {
131 rtc::CritScope cs(&lock_); 255 rtc::CritScope cs(&lock_);
132 return capturing_; 256 return capturing_;
133 } 257 }
134 258
259 bool FakeAudioDevice::WaitForPlayoutEnd(int timeout_ms) {
260 return done_rendering_.Wait(timeout_ms);
261 }
262
263 bool FakeAudioDevice::WaitForRecordingEnd(int timeout_ms) {
264 return done_capturing_.Wait(timeout_ms);
265 }
266
135 bool FakeAudioDevice::Run(void* obj) { 267 bool FakeAudioDevice::Run(void* obj) {
136 static_cast<FakeAudioDevice*>(obj)->ProcessAudio(); 268 static_cast<FakeAudioDevice*>(obj)->ProcessAudio();
137 return true; 269 return true;
138 } 270 }
139 271
140 void FakeAudioDevice::ProcessAudio() { 272 void FakeAudioDevice::ProcessAudio() {
141 { 273 {
142 rtc::CritScope cs(&lock_); 274 rtc::CritScope cs(&lock_);
143 if (capturing_) { 275 if (capturing_) {
144 // Capture 10ms of audio. 2 bytes per sample. 276 // Capture 10ms of audio. 2 bytes per sample.
145 rtc::ArrayView<const int16_t> audio_data = capturer_->Capture(); 277 const bool keep_capturing = capturer_->Capture(&recording_buffer_);
146 uint32_t new_mic_level = 0; 278 uint32_t new_mic_level;
147 audio_callback_->RecordedDataIsAvailable( 279 if (recording_buffer_.size() > 0) {
148 audio_data.data(), audio_data.size(), 2, 1, sampling_frequency_in_hz_, 280 audio_callback_->RecordedDataIsAvailable(
149 0, 0, 0, false, new_mic_level); 281 recording_buffer_.data(), recording_buffer_.size(), 2, 1,
282 capturer_->SamplingFrequency(), 0, 0, 0, false, new_mic_level);
283 }
284 if (!keep_capturing) {
285 capturing_ = false;
286 done_capturing_.Set();
287 }
150 } 288 }
151 if (rendering_) { 289 if (rendering_) {
152 size_t samples_out = 0; 290 size_t samples_out;
153 int64_t elapsed_time_ms = -1; 291 int64_t elapsed_time_ms;
154 int64_t ntp_time_ms = -1; 292 int64_t ntp_time_ms;
293 const int sampling_frequency = renderer_->SamplingFrequency();
155 audio_callback_->NeedMorePlayData( 294 audio_callback_->NeedMorePlayData(
156 num_samples_per_frame_, 2, 1, sampling_frequency_in_hz_, 295 SamplesPerFrame(sampling_frequency), 2, 1, sampling_frequency,
157 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms); 296 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms);
297 const bool keep_rendering = renderer_->Render(
298 rtc::ArrayView<const int16_t>(playout_buffer_.data(), samples_out));
299 if (!keep_rendering) {
300 rendering_ = false;
301 done_rendering_.Set();
302 }
158 } 303 }
159 } 304 }
160 tick_->Wait(WEBRTC_EVENT_INFINITE); 305 tick_->Wait(WEBRTC_EVENT_INFINITE);
161 } 306 }
162 307
163 308
164 } // namespace test 309 } // namespace test
165 } // namespace webrtc 310 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/test/fake_audio_device.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698