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

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: Prevent nested CritScope to fix 'use of an invalid mutex' 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
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
27 } // namespace
28 namespace test {
29
30 // Assuming 10ms audio packets.. 28 // Assuming 10ms audio packets..
31 class FakeAudioDevice::PulsedNoiseCapturer { 29 class PulsedNoiseCapturer final : public test::FakeAudioDevice::Capturer {
32 public: 30 public:
33 PulsedNoiseCapturer(size_t num_samples_per_frame, int16_t max_amplitude) 31 PulsedNoiseCapturer(int16_t max_amplitude, int sampling_frequency_in_hz)
34 : fill_with_zero_(false), 32 : Capturer(sampling_frequency_in_hz),
33 fill_with_zero_(false),
35 random_generator_(1), 34 random_generator_(1),
36 max_amplitude_(max_amplitude), 35 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); 36 RTC_DCHECK_GT(max_amplitude, 0);
40 } 37 }
41 38
42 rtc::ArrayView<const int16_t> Capture() { 39 bool Capture(rtc::BufferT<int16_t>* buffer) override {
43 fill_with_zero_ = !fill_with_zero_; 40 fill_with_zero_ = !fill_with_zero_;
44 if (!fill_with_zero_) { 41 buffer->SetData(SamplesPerFrame(), [&](rtc::ArrayView<int16_t> data) {
45 std::generate(random_audio_.begin(), random_audio_.end(), [&]() { 42 if (fill_with_zero_) {
46 return random_generator_.Rand(-max_amplitude_, max_amplitude_); 43 std::fill(data.begin(), data.end(), 0);
47 }); 44 } else {
48 } 45 std::generate(data.begin(), data.end(), [&]() {
49 return fill_with_zero_ ? silent_audio_ : random_audio_; 46 return random_generator_.Rand(-max_amplitude_, max_amplitude_);
47 });
48 }
49 return data.size();
50 });
kwiberg-webrtc 2017/03/13 10:18:22 Excellent use of SetData with a lambda!
51 return true;
50 } 52 }
51 53
52 private: 54 private:
53 bool fill_with_zero_; 55 bool fill_with_zero_;
54 Random random_generator_; 56 Random random_generator_;
55 const int16_t max_amplitude_; 57 const int16_t max_amplitude_;
56 std::vector<int16_t> random_audio_;
57 std::vector<int16_t> silent_audio_;
58 }; 58 };
59 59
60 FakeAudioDevice::FakeAudioDevice(float speed, 60 class WavFileReader final : public test::FakeAudioDevice::Capturer {
61 int sampling_frequency_in_hz, 61 public:
62 int16_t max_amplitude) 62 WavFileReader(std::string filename, int sampling_frequency_in_hz)
63 : test::FakeAudioDevice::Capturer(sampling_frequency_in_hz),
64 wav_reader_(filename) {
65 RTC_CHECK_EQ(wav_reader_.sample_rate(), sampling_frequency_in_hz);
66 RTC_CHECK_EQ(wav_reader_.num_channels(), 1);
67 }
68
69 bool Capture(rtc::BufferT<int16_t>* buffer) override {
70 buffer->SetData(SamplesPerFrame(), [&](rtc::ArrayView<int16_t> data) {
71 return wav_reader_.ReadSamples(data.size(), data.data());
72 });
73 return buffer->size() > 0;
74 }
75
76 private:
77 WavReader wav_reader_;
78 };
79
80 class WavFileWriter final : public test::FakeAudioDevice::Renderer {
81 public:
82 WavFileWriter(std::string filename, int sampling_frequency_in_hz)
83 : test::FakeAudioDevice::Renderer(sampling_frequency_in_hz),
84 wav_writer_(filename, sampling_frequency_in_hz, 1) {}
85
86 bool Render(rtc::ArrayView<const int16_t> data) override {
87 wav_writer_.WriteSamples(data.data(), data.size());
88 return true;
89 }
90
91 private:
92 WavWriter wav_writer_;
93 };
94
95 class Discarder final : public test::FakeAudioDevice::Renderer {
96 public:
97 using Renderer::Renderer;
98
99 bool Render(rtc::ArrayView<const int16_t> data) override {
100 return true;
101 }
102 };
103
104 } // namespace
105 namespace test {
106
107 FakeAudioDevice::Streamer::Streamer(int sampling_frequency_in_hz)
63 : sampling_frequency_in_hz_(sampling_frequency_in_hz), 108 : sampling_frequency_in_hz_(sampling_frequency_in_hz),
64 num_samples_per_frame_( 109 num_samples_per_frame_(
65 rtc::CheckedDivExact(sampling_frequency_in_hz_, kFramesPerSecond)), 110 rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond)) {
111 RTC_CHECK(
112 sampling_frequency_in_hz == 8000 || sampling_frequency_in_hz == 16000 ||
113 sampling_frequency_in_hz == 32000 || sampling_frequency_in_hz == 44100 ||
114 sampling_frequency_in_hz == 48000);
115 }
116
117 std::unique_ptr<FakeAudioDevice::Capturer>
118 FakeAudioDevice::CreatePulsedNoiseCapturer(
119 int16_t max_amplitude, int sampling_frequency_in_hz) {
120 return std::unique_ptr<FakeAudioDevice::Capturer>(
121 new PulsedNoiseCapturer(max_amplitude, sampling_frequency_in_hz));
122 }
123
124 std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader(
125 std::string filename, int sampling_frequency_in_hz) {
126 return std::unique_ptr<FakeAudioDevice::Capturer>(
127 new WavFileReader(filename, sampling_frequency_in_hz));
128 }
129
130 std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader(
131 std::string filename) {
132 int sampling_frequency_in_hz = WavReader(filename).sample_rate();
133 return std::unique_ptr<FakeAudioDevice::Capturer>(
134 new WavFileReader(filename, sampling_frequency_in_hz));
135 }
136
137 std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateWavFileWriter(
138 std::string filename, int sampling_frequency_in_hz) {
139 return std::unique_ptr<FakeAudioDevice::Renderer>(
140 new WavFileWriter(filename, sampling_frequency_in_hz));
141 }
142
143 std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateDiscarder(
144 int sampling_frequency_in_hz) {
145 return std::unique_ptr<FakeAudioDevice::Renderer>(
146 new Discarder(sampling_frequency_in_hz));
147 }
148
149
150 FakeAudioDevice::FakeAudioDevice(std::unique_ptr<Capturer> capturer,
151 std::unique_ptr<Renderer> renderer,
152 float speed)
153 : capturer_(std::move(capturer)),
154 renderer_(std::move(renderer)),
66 speed_(speed), 155 speed_(speed),
67 audio_callback_(nullptr), 156 audio_callback_(nullptr),
68 rendering_(false), 157 rendering_(false),
69 capturing_(false), 158 capturing_(false),
70 capturer_(new FakeAudioDevice::PulsedNoiseCapturer(num_samples_per_frame_, 159 done_rendering_(true, true),
71 max_amplitude)), 160 done_capturing_(true, true),
72 playout_buffer_(num_samples_per_frame_, 0),
73 tick_(EventTimerWrapper::Create()), 161 tick_(EventTimerWrapper::Create()),
74 thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") { 162 thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") {
75 RTC_DCHECK( 163 if (renderer_) {
76 sampling_frequency_in_hz == 8000 || sampling_frequency_in_hz == 16000 || 164 playout_buffer_.resize(renderer_->SamplesPerFrame(), 0);
77 sampling_frequency_in_hz == 32000 || sampling_frequency_in_hz == 44100 || 165 }
78 sampling_frequency_in_hz == 48000);
79 } 166 }
80 167
81 FakeAudioDevice::~FakeAudioDevice() { 168 FakeAudioDevice::~FakeAudioDevice() {
82 StopPlayout(); 169 StopPlayout();
83 StopRecording(); 170 StopRecording();
84 thread_.Stop(); 171 thread_.Stop();
85 } 172 }
86 173
87 int32_t FakeAudioDevice::StartPlayout() { 174 int32_t FakeAudioDevice::StartPlayout() {
88 rtc::CritScope cs(&lock_); 175 rtc::CritScope cs(&lock_);
176 RTC_CHECK(renderer_);
89 rendering_ = true; 177 rendering_ = true;
178 done_rendering_.Reset();
90 return 0; 179 return 0;
91 } 180 }
92 181
93 int32_t FakeAudioDevice::StopPlayout() { 182 int32_t FakeAudioDevice::StopPlayout() {
94 rtc::CritScope cs(&lock_); 183 rtc::CritScope cs(&lock_);
95 rendering_ = false; 184 rendering_ = false;
185 done_rendering_.Set();
96 return 0; 186 return 0;
97 } 187 }
98 188
99 int32_t FakeAudioDevice::StartRecording() { 189 int32_t FakeAudioDevice::StartRecording() {
100 rtc::CritScope cs(&lock_); 190 rtc::CritScope cs(&lock_);
191 RTC_CHECK(capturer_);
101 capturing_ = true; 192 capturing_ = true;
193 done_capturing_.Reset();
102 return 0; 194 return 0;
103 } 195 }
104 196
105 int32_t FakeAudioDevice::StopRecording() { 197 int32_t FakeAudioDevice::StopRecording() {
106 rtc::CritScope cs(&lock_); 198 rtc::CritScope cs(&lock_);
107 capturing_ = false; 199 capturing_ = false;
200 done_capturing_.Set();
108 return 0; 201 return 0;
109 } 202 }
110 203
111 int32_t FakeAudioDevice::Init() { 204 int32_t FakeAudioDevice::Init() {
112 RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_)); 205 RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_));
113 thread_.Start(); 206 thread_.Start();
114 thread_.SetPriority(rtc::kHighPriority); 207 thread_.SetPriority(rtc::kHighPriority);
115 return 0; 208 return 0;
116 } 209 }
117 210
118 int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { 211 int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) {
119 rtc::CritScope cs(&lock_); 212 rtc::CritScope cs(&lock_);
120 RTC_DCHECK(callback || audio_callback_ != nullptr); 213 RTC_DCHECK(callback || audio_callback_);
121 audio_callback_ = callback; 214 audio_callback_ = callback;
122 return 0; 215 return 0;
123 } 216 }
124 217
125 bool FakeAudioDevice::Playing() const { 218 bool FakeAudioDevice::Playing() const {
126 rtc::CritScope cs(&lock_); 219 rtc::CritScope cs(&lock_);
127 return rendering_; 220 return rendering_;
128 } 221 }
129 222
130 bool FakeAudioDevice::Recording() const { 223 bool FakeAudioDevice::Recording() const {
131 rtc::CritScope cs(&lock_); 224 rtc::CritScope cs(&lock_);
132 return capturing_; 225 return capturing_;
133 } 226 }
134 227
228 bool FakeAudioDevice::WaitForPlayoutEnd(int timeout_ms) {
229 return done_rendering_.Wait(timeout_ms);
230 }
231
232 bool FakeAudioDevice::WaitForRecordingEnd(int timeout_ms) {
233 return done_capturing_.Wait(timeout_ms);
234 }
235
135 bool FakeAudioDevice::Run(void* obj) { 236 bool FakeAudioDevice::Run(void* obj) {
136 static_cast<FakeAudioDevice*>(obj)->ProcessAudio(); 237 static_cast<FakeAudioDevice*>(obj)->ProcessAudio();
137 return true; 238 return true;
138 } 239 }
139 240
140 void FakeAudioDevice::ProcessAudio() { 241 void FakeAudioDevice::ProcessAudio() {
141 { 242 {
142 rtc::CritScope cs(&lock_); 243 rtc::CritScope cs(&lock_);
143 if (capturing_) { 244 if (capturing_) {
144 // Capture 10ms of audio. 2 bytes per sample. 245 // Capture 10ms of audio. 2 bytes per sample.
145 rtc::ArrayView<const int16_t> audio_data = capturer_->Capture(); 246 const bool keep_recording = capturer_->Capture(&recording_buffer_);
146 uint32_t new_mic_level = 0; 247 uint32_t new_mic_level;
147 audio_callback_->RecordedDataIsAvailable( 248 if (recording_buffer_.size() > 0) {
148 audio_data.data(), audio_data.size(), 2, 1, sampling_frequency_in_hz_, 249 audio_callback_->RecordedDataIsAvailable(
149 0, 0, 0, false, new_mic_level); 250 recording_buffer_.data(), recording_buffer_.size(), 2, 1,
251 capturer_->SamplingFrequency(), 0, 0, 0, false, new_mic_level);
252 }
253 if (!keep_recording) {
254 capturing_ = false;
255 done_capturing_.Set();
kwiberg-webrtc 2017/03/13 10:18:21 Nit: It looks like keep_recording could be named k
oprypin_webrtc 2017/03/13 13:55:14 Done.
256 }
150 } 257 }
151 if (rendering_) { 258 if (rendering_) {
152 size_t samples_out = 0; 259 size_t samples_out;
153 int64_t elapsed_time_ms = -1; 260 int64_t elapsed_time_ms;
154 int64_t ntp_time_ms = -1; 261 int64_t ntp_time_ms;
155 audio_callback_->NeedMorePlayData( 262 audio_callback_->NeedMorePlayData(
156 num_samples_per_frame_, 2, 1, sampling_frequency_in_hz_, 263 renderer_->SamplesPerFrame(), 2, 1, renderer_->SamplingFrequency(),
157 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms); 264 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms);
265 const bool keep_rendering = renderer_->Render(
266 rtc::ArrayView<const int16_t>(playout_buffer_.data(), samples_out));
267 if (!keep_rendering) {
268 rendering_ = false;
269 done_rendering_.Set();
270 }
158 } 271 }
159 } 272 }
160 tick_->Wait(WEBRTC_EVENT_INFINITE); 273 tick_->Wait(WEBRTC_EVENT_INFINITE);
161 } 274 }
162 275
163 276
164 } // namespace test 277 } // namespace test
165 } // namespace webrtc 278 } // namespace webrtc
OLDNEW
« webrtc/test/fake_audio_device.h ('K') | « webrtc/test/fake_audio_device.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698