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

Side by Side Diff: media/audio/audio_debug_file_writer_unittest.cc

Issue 2702323002: Move AudioDebugFileWriter from content/ to media/. (Closed)
Patch Set: Code review, unit test fix and rebase. Created 3 years, 10 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 | « media/audio/audio_debug_file_writer.cc ('k') | media/audio/audio_file_writer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stdint.h> 5 #include <stdint.h>
6 6
7 #include "base/bind.h"
7 #include "base/files/file_util.h" 8 #include "base/files/file_util.h"
8 #include "base/memory/ptr_util.h" 9 #include "base/memory/ptr_util.h"
10 #include "base/message_loop/message_loop.h"
9 #include "base/synchronization/waitable_event.h" 11 #include "base/synchronization/waitable_event.h"
10 #include "base/sys_byteorder.h" 12 #include "base/sys_byteorder.h"
11 #include "content/browser/renderer_host/media/audio_debug_file_writer.h" 13 #include "base/threading/thread.h"
12 #include "content/public/browser/browser_thread.h" 14 #include "media/audio/audio_debug_file_writer.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "media/base/audio_bus.h" 15 #include "media/base/audio_bus.h"
15 #include "media/base/test_helpers.h" 16 #include "media/base/test_helpers.h"
16 #include "testing/gtest/include/gtest/gtest.h" 17 #include "testing/gtest/include/gtest/gtest.h"
17 18
18 namespace content { 19 namespace media {
19 20
20 namespace { 21 namespace {
21 22
22 static const uint16_t kBytesPerSample = sizeof(uint16_t); 23 static const uint16_t kBytesPerSample = sizeof(uint16_t);
23 static const uint16_t kPcmEncoding = 1; 24 static const uint16_t kPcmEncoding = 1;
24 static const size_t kWavHeaderSize = 44; 25 static const size_t kWavHeaderSize = 44;
25 26
26 uint16_t ReadLE2(const char* buf) { 27 uint16_t ReadLE2(const char* buf) {
27 return static_cast<uint8_t>(buf[0]) | (static_cast<uint8_t>(buf[1]) << 8); 28 return static_cast<uint8_t>(buf[0]) | (static_cast<uint8_t>(buf[1]) << 8);
28 } 29 }
29 30
30 uint32_t ReadLE4(const char* buf) { 31 uint32_t ReadLE4(const char* buf) {
31 return static_cast<uint8_t>(buf[0]) | (static_cast<uint8_t>(buf[1]) << 8) | 32 return static_cast<uint8_t>(buf[0]) | (static_cast<uint8_t>(buf[1]) << 8) |
32 (static_cast<uint8_t>(buf[2]) << 16) | 33 (static_cast<uint8_t>(buf[2]) << 16) |
33 (static_cast<uint8_t>(buf[3]) << 24); 34 (static_cast<uint8_t>(buf[3]) << 24);
34 } 35 }
35 36
36 } // namespace 37 } // namespace
37 38
38 // <channel layout, sample rate, frames per buffer, number of buffer writes 39 // <channel layout, sample rate, frames per buffer, number of buffer writes
39 typedef std::tr1::tuple<media::ChannelLayout, int, int, int> 40 typedef std::tr1::tuple<ChannelLayout, int, int, int>
40 AudioDebugFileWriterTestData; 41 AudioDebugFileWriterTestData;
41 42
42 class AudioDebugFileWriterTest 43 class AudioDebugFileWriterTest
43 : public testing::TestWithParam<AudioDebugFileWriterTestData> { 44 : public testing::TestWithParam<AudioDebugFileWriterTestData> {
44 public: 45 public:
45 AudioDebugFileWriterTest() 46 AudioDebugFileWriterTest()
46 : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD), 47 : file_thread_("FileThread"),
47 params_(media::AudioParameters::Format::AUDIO_PCM_LINEAR, 48 params_(AudioParameters::Format::AUDIO_PCM_LINEAR,
48 std::tr1::get<0>(GetParam()), 49 std::tr1::get<0>(GetParam()),
49 std::tr1::get<1>(GetParam()), 50 std::tr1::get<1>(GetParam()),
50 kBytesPerSample * 8, 51 kBytesPerSample * 8,
51 std::tr1::get<2>(GetParam())), 52 std::tr1::get<2>(GetParam())),
52 writes_(std::tr1::get<3>(GetParam())), 53 writes_(std::tr1::get<3>(GetParam())),
53 source_samples_(params_.frames_per_buffer() * params_.channels() * 54 source_samples_(params_.frames_per_buffer() * params_.channels() *
54 writes_), 55 writes_),
55 source_interleaved_(source_samples_ ? new int16_t[source_samples_] 56 source_interleaved_(source_samples_ ? new int16_t[source_samples_]
56 : nullptr) { 57 : nullptr) {
58 file_thread_.StartAndWaitForTesting();
57 InitSourceInterleaved(source_interleaved_.get(), source_samples_); 59 InitSourceInterleaved(source_interleaved_.get(), source_samples_);
58 } 60 }
59 61
60 protected: 62 protected:
61 virtual ~AudioDebugFileWriterTest() {} 63 virtual ~AudioDebugFileWriterTest() {}
62 64
63 static void InitSourceInterleaved(int16_t* source_interleaved, 65 static void InitSourceInterleaved(int16_t* source_interleaved,
64 int source_samples) { 66 int source_samples) {
65 if (source_samples) { 67 if (source_samples) {
66 // equal steps to cover int16_t range of values 68 // equal steps to cover int16_t range of values
67 int16_t step = 0xffff / source_samples; 69 int16_t step = 0xffff / source_samples;
68 int16_t val = std::numeric_limits<int16_t>::min(); 70 int16_t val = std::numeric_limits<int16_t>::min();
69 for (int i = 0; i < source_samples; ++i, val += step) 71 for (int i = 0; i < source_samples; ++i, val += step)
70 source_interleaved[i] = val; 72 source_interleaved[i] = val;
71 } 73 }
72 } 74 }
73 75
74 static void VerifyHeader(const char(&wav_header)[kWavHeaderSize], 76 static void VerifyHeader(const char (&wav_header)[kWavHeaderSize],
75 const media::AudioParameters& params, 77 const AudioParameters& params,
76 int writes, 78 int writes,
77 int64_t file_length) { 79 int64_t file_length) {
78 uint32_t block_align = params.channels() * kBytesPerSample; 80 uint32_t block_align = params.channels() * kBytesPerSample;
79 uint32_t data_size = 81 uint32_t data_size =
80 static_cast<uint32_t>(params.frames_per_buffer() * params.channels() * 82 static_cast<uint32_t>(params.frames_per_buffer() * params.channels() *
81 writes * kBytesPerSample); 83 writes * kBytesPerSample);
82 // Offset Length Content 84 // Offset Length Content
83 // 0 4 "RIFF" 85 // 0 4 "RIFF"
84 EXPECT_EQ(0, strncmp(wav_header, "RIFF", 4)); 86 EXPECT_EQ(0, strncmp(wav_header, "RIFF", 4));
85 // 4 4 <file length - 8> 87 // 4 4 <file length - 8>
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 reinterpret_cast<char*>(result_interleaved.get()), 149 reinterpret_cast<char*>(result_interleaved.get()),
148 source_samples_ * kBytesPerSample); 150 source_samples_ * kBytesPerSample);
149 EXPECT_EQ(static_cast<int>(file.GetLength() - kWavHeaderSize), read); 151 EXPECT_EQ(static_cast<int>(file.GetLength() - kWavHeaderSize), read);
150 152
151 VerifyDataRecording(source_interleaved_.get(), result_interleaved.get(), 153 VerifyDataRecording(source_interleaved_.get(), result_interleaved.get(),
152 source_samples_); 154 source_samples_);
153 } 155 }
154 } 156 }
155 157
156 void TestDoneOnFileThread(const base::Closure& callback) { 158 void TestDoneOnFileThread(const base::Closure& callback) {
157 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 159 DCHECK(file_thread_.task_runner()->BelongsToCurrentThread());
158 160
159 callback.Run(); 161 callback.Run();
160 } 162 }
161 163
162 void DoDebugRecording() { 164 void DoDebugRecording() {
163 // Write tasks are posted to BrowserThread::FILE. 165 // Write tasks are posted to |file_thread_|.
164 for (int i = 0; i < writes_; ++i) { 166 for (int i = 0; i < writes_; ++i) {
165 std::unique_ptr<media::AudioBus> bus = media::AudioBus::Create( 167 std::unique_ptr<AudioBus> bus =
166 params_.channels(), params_.frames_per_buffer()); 168 AudioBus::Create(params_.channels(), params_.frames_per_buffer());
167 169
168 bus->FromInterleaved( 170 bus->FromInterleaved(
169 source_interleaved_.get() + 171 source_interleaved_.get() +
170 i * params_.channels() * params_.frames_per_buffer(), 172 i * params_.channels() * params_.frames_per_buffer(),
171 params_.frames_per_buffer(), kBytesPerSample); 173 params_.frames_per_buffer(), kBytesPerSample);
172 174
173 input_debug_writer_->Write(std::move(bus)); 175 debug_writer_->Write(std::move(bus));
174 } 176 }
175 } 177 }
176 178
177 void WaitForRecordingCompletion() { 179 void WaitForRecordingCompletion() {
178 media::WaitableMessageLoopEvent event; 180 WaitableMessageLoopEvent event;
179 181
180 // Post a task to BrowserThread::FILE indicating that all the writes are 182 // Post a task to the file thread indicating that all the writes are done.
181 // done. 183 file_thread_.task_runner()->PostTask(
182 BrowserThread::PostTask( 184 FROM_HERE,
183 BrowserThread::FILE, FROM_HERE,
184 base::Bind(&AudioDebugFileWriterTest::TestDoneOnFileThread, 185 base::Bind(&AudioDebugFileWriterTest::TestDoneOnFileThread,
185 base::Unretained(this), event.GetClosure())); 186 base::Unretained(this), event.GetClosure()));
186 187
187 // Wait for TestDoneOnFileThread() to call event's closure. 188 // Wait for TestDoneOnFileThread() to call event's closure.
188 event.RunAndWait(); 189 event.RunAndWait();
189 } 190 }
190 191
191 void RecordAndVerifyOnce() { 192 void RecordAndVerifyOnce() {
192 base::FilePath file_path; 193 base::FilePath file_path;
193 EXPECT_TRUE(base::CreateTemporaryFile(&file_path)); 194 EXPECT_TRUE(base::CreateTemporaryFile(&file_path));
194 195
195 input_debug_writer_->Start(file_path); 196 debug_writer_->Start(file_path);
196 197
197 DoDebugRecording(); 198 DoDebugRecording();
198 199
199 input_debug_writer_->Stop(); 200 debug_writer_->Stop();
200 201
201 WaitForRecordingCompletion(); 202 WaitForRecordingCompletion();
202 203
203 VerifyRecording(file_path); 204 VerifyRecording(file_path);
204 205
205 if (::testing::Test::HasFailure()) { 206 if (::testing::Test::HasFailure()) {
206 LOG(ERROR) << "Test failed; keeping recording(s) at [" 207 LOG(ERROR) << "Test failed; keeping recording(s) at ["
207 << file_path.value().c_str() << "]."; 208 << file_path.value().c_str() << "].";
208 } else { 209 } else {
209 EXPECT_TRUE(base::DeleteFile(file_path, false)); 210 EXPECT_TRUE(base::DeleteFile(file_path, false));
210 } 211 }
211 } 212 }
212 213
213 protected: 214 protected:
214 TestBrowserThreadBundle thread_bundle_; 215 // |file_thread_| must to be declared before |debug_writer_| so that it's
216 // destroyed after. This ensures all tasks posted in |debug_writer_| to the
217 // file thread are run before exiting the test.
218 base::Thread file_thread_;
219
220 // Message loop for the test main thread.
221 base::MessageLoop message_loop_;
215 222
216 // Writer under test. 223 // Writer under test.
217 std::unique_ptr<AudioDebugFileWriter> input_debug_writer_; 224 std::unique_ptr<AudioDebugFileWriter> debug_writer_;
218 225
219 // AudioBus parameters. 226 // AudioBus parameters.
220 media::AudioParameters params_; 227 AudioParameters params_;
221 228
222 // Number of times to write AudioBus to the file. 229 // Number of times to write AudioBus to the file.
223 int writes_; 230 int writes_;
224 231
225 // Number of samples in the source data. 232 // Number of samples in the source data.
226 int source_samples_; 233 int source_samples_;
227 234
228 // Source data. 235 // Source data.
229 std::unique_ptr<int16_t[]> source_interleaved_; 236 std::unique_ptr<int16_t[]> source_interleaved_;
230 237
231 private: 238 private:
232 DISALLOW_COPY_AND_ASSIGN(AudioDebugFileWriterTest); 239 DISALLOW_COPY_AND_ASSIGN(AudioDebugFileWriterTest);
233 }; 240 };
234 241
235 class AudioDebugFileWriterBehavioralTest : public AudioDebugFileWriterTest {}; 242 class AudioDebugFileWriterBehavioralTest : public AudioDebugFileWriterTest {};
236 243
237 TEST_P(AudioDebugFileWriterTest, WaveRecordingTest) { 244 TEST_P(AudioDebugFileWriterTest, WaveRecordingTest) {
238 input_debug_writer_.reset(new AudioDebugFileWriter(params_)); 245 debug_writer_.reset(
246 new AudioDebugFileWriter(params_, file_thread_.task_runner()));
239 247
240 RecordAndVerifyOnce(); 248 RecordAndVerifyOnce();
241 } 249 }
242 250
243 TEST_P(AudioDebugFileWriterBehavioralTest, 251 TEST_P(AudioDebugFileWriterBehavioralTest,
244 DeletedBeforeRecordingFinishedOnFileThread) { 252 DeletedBeforeRecordingFinishedOnFileThread) {
245 input_debug_writer_.reset(new AudioDebugFileWriter(params_)); 253 debug_writer_.reset(
254 new AudioDebugFileWriter(params_, file_thread_.task_runner()));
246 255
247 base::FilePath file_path; 256 base::FilePath file_path;
248 EXPECT_TRUE(base::CreateTemporaryFile(&file_path)); 257 EXPECT_TRUE(base::CreateTemporaryFile(&file_path));
249 258
250 base::WaitableEvent* wait_for_deletion = 259 base::WaitableEvent* wait_for_deletion =
251 new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL, 260 new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
252 base::WaitableEvent::InitialState::NOT_SIGNALED); 261 base::WaitableEvent::InitialState::NOT_SIGNALED);
253 262
254 BrowserThread::PostTask( 263 file_thread_.task_runner()->PostTask(
255 BrowserThread::FILE, FROM_HERE, 264 FROM_HERE,
256 base::Bind(&base::WaitableEvent::Wait, base::Owned(wait_for_deletion))); 265 base::Bind(&base::WaitableEvent::Wait, base::Owned(wait_for_deletion)));
257 266
258 input_debug_writer_->Start(file_path); 267 debug_writer_->Start(file_path);
259 268
260 DoDebugRecording(); 269 DoDebugRecording();
261 270
262 input_debug_writer_.reset(); 271 debug_writer_.reset();
263 wait_for_deletion->Signal(); 272 wait_for_deletion->Signal();
264 273
265 WaitForRecordingCompletion(); 274 WaitForRecordingCompletion();
266 275
267 VerifyRecording(file_path); 276 VerifyRecording(file_path);
268 277
269 if (::testing::Test::HasFailure()) { 278 if (::testing::Test::HasFailure()) {
270 LOG(ERROR) << "Test failed; keeping recording(s) at [" 279 LOG(ERROR) << "Test failed; keeping recording(s) at ["
271 << file_path.value().c_str() << "]."; 280 << file_path.value().c_str() << "].";
272 } else { 281 } else {
273 EXPECT_TRUE(base::DeleteFile(file_path, false)); 282 EXPECT_TRUE(base::DeleteFile(file_path, false));
274 } 283 }
275 } 284 }
276 285
277 TEST_P(AudioDebugFileWriterBehavioralTest, FileCreationError) { 286 TEST_P(AudioDebugFileWriterBehavioralTest, FileCreationError) {
278 input_debug_writer_.reset(new AudioDebugFileWriter(params_)); 287 debug_writer_.reset(
288 new AudioDebugFileWriter(params_, file_thread_.task_runner()));
279 base::FilePath file_path; // Empty file name. 289 base::FilePath file_path; // Empty file name.
280 input_debug_writer_->Start(file_path); 290 debug_writer_->Start(file_path);
281 DoDebugRecording(); 291 DoDebugRecording();
282 } 292 }
283 293
284 TEST_P(AudioDebugFileWriterBehavioralTest, StartStopStartStop) { 294 TEST_P(AudioDebugFileWriterBehavioralTest, StartStopStartStop) {
285 input_debug_writer_.reset(new AudioDebugFileWriter(params_)); 295 debug_writer_.reset(
296 new AudioDebugFileWriter(params_, file_thread_.task_runner()));
286 RecordAndVerifyOnce(); 297 RecordAndVerifyOnce();
287 RecordAndVerifyOnce(); 298 RecordAndVerifyOnce();
288 } 299 }
289 300
290 TEST_P(AudioDebugFileWriterBehavioralTest, DestroyNotStarted) { 301 TEST_P(AudioDebugFileWriterBehavioralTest, DestroyNotStarted) {
291 input_debug_writer_.reset(new AudioDebugFileWriter(params_)); 302 debug_writer_.reset(
292 input_debug_writer_.reset(); 303 new AudioDebugFileWriter(params_, file_thread_.task_runner()));
304 debug_writer_.reset();
293 } 305 }
294 306
295 TEST_P(AudioDebugFileWriterBehavioralTest, DestroyStarted) { 307 TEST_P(AudioDebugFileWriterBehavioralTest, DestroyStarted) {
296 input_debug_writer_.reset(new AudioDebugFileWriter(params_)); 308 debug_writer_.reset(
309 new AudioDebugFileWriter(params_, file_thread_.task_runner()));
297 base::FilePath file_path; 310 base::FilePath file_path;
298 EXPECT_TRUE(base::CreateTemporaryFile(&file_path)); 311 EXPECT_TRUE(base::CreateTemporaryFile(&file_path));
299 input_debug_writer_->Start(file_path); 312 debug_writer_->Start(file_path);
300 input_debug_writer_.reset(); 313 debug_writer_.reset();
301 } 314 }
302 315
303 INSTANTIATE_TEST_CASE_P( 316 INSTANTIATE_TEST_CASE_P(
304 AudioDebugFileWriterTest, 317 AudioDebugFileWriterTest,
305 AudioDebugFileWriterTest, 318 AudioDebugFileWriterTest,
306 // Using 10ms frames per buffer everywhere. 319 // Using 10ms frames per buffer everywhere.
307 testing::Values( 320 testing::Values(
308 // No writes. 321 // No writes.
309 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, 322 std::tr1::make_tuple(ChannelLayout::CHANNEL_LAYOUT_MONO,
310 44100, 323 44100,
311 44100 / 100, 324 44100 / 100,
312 0), 325 0),
313 // 1 write of mono. 326 // 1 write of mono.
314 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, 327 std::tr1::make_tuple(ChannelLayout::CHANNEL_LAYOUT_MONO,
315 44100, 328 44100,
316 44100 / 100, 329 44100 / 100,
317 1), 330 1),
318 // 1 second of mono. 331 // 1 second of mono.
319 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, 332 std::tr1::make_tuple(ChannelLayout::CHANNEL_LAYOUT_MONO,
320 44100, 333 44100,
321 44100 / 100, 334 44100 / 100,
322 100), 335 100),
323 // 1 second of mono, higher rate. 336 // 1 second of mono, higher rate.
324 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, 337 std::tr1::make_tuple(ChannelLayout::CHANNEL_LAYOUT_MONO,
325 48000, 338 48000,
326 48000 / 100, 339 48000 / 100,
327 100), 340 100),
328 // 1 second of stereo. 341 // 1 second of stereo.
329 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_STEREO, 342 std::tr1::make_tuple(ChannelLayout::CHANNEL_LAYOUT_STEREO,
330 44100, 343 44100,
331 44100 / 100, 344 44100 / 100,
332 100), 345 100),
333 // 15 seconds of stereo, higher rate. 346 // 15 seconds of stereo, higher rate.
334 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_STEREO, 347 std::tr1::make_tuple(ChannelLayout::CHANNEL_LAYOUT_STEREO,
335 48000, 348 48000,
336 48000 / 100, 349 48000 / 100,
337 1500))); 350 1500)));
338 351
339 INSTANTIATE_TEST_CASE_P( 352 INSTANTIATE_TEST_CASE_P(
340 AudioDebugFileWriterBehavioralTest, 353 AudioDebugFileWriterBehavioralTest,
341 AudioDebugFileWriterBehavioralTest, 354 AudioDebugFileWriterBehavioralTest,
342 // Using 10ms frames per buffer everywhere. 355 // Using 10ms frames per buffer everywhere.
343 testing::Values( 356 testing::Values(
344 // No writes. 357 // No writes.
345 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, 358 std::tr1::make_tuple(ChannelLayout::CHANNEL_LAYOUT_MONO,
346 44100, 359 44100,
347 44100 / 100, 360 44100 / 100,
348 100))); 361 100)));
349 362
350 } // namespace content 363 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_debug_file_writer.cc ('k') | media/audio/audio_file_writer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698