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

Side by Side Diff: media/audio/win/audio_low_latency_input_win_unittest.cc

Issue 344583002: Modifies AudioInputCallback::OnData and use media::AudioBus instead of plain byte vector (Relanding) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added extra non-pure OnData API Created 6 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « media/audio/win/audio_low_latency_input_win.cc ('k') | media/audio/win/wavein_input_win.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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 <windows.h> 5 #include <windows.h>
6 #include <mmsystem.h> 6 #include <mmsystem.h>
7 7
8 #include "base/basictypes.h" 8 #include "base/basictypes.h"
9 #include "base/environment.h" 9 #include "base/environment.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
(...skipping 20 matching lines...) Expand all
31 namespace media { 31 namespace media {
32 32
33 ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop) { 33 ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop) {
34 if (++*count >= limit) { 34 if (++*count >= limit) {
35 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 35 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
36 } 36 }
37 } 37 }
38 38
39 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback { 39 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
40 public: 40 public:
41 MOCK_METHOD5(OnData, void(AudioInputStream* stream, 41 MOCK_METHOD4(OnData,
42 const uint8* src, uint32 size, 42 void(AudioInputStream* stream,
43 uint32 hardware_delay_bytes, double volume)); 43 const AudioBus* src,
44 uint32 hardware_delay_bytes,
45 double volume));
44 MOCK_METHOD1(OnError, void(AudioInputStream* stream)); 46 MOCK_METHOD1(OnError, void(AudioInputStream* stream));
45 }; 47 };
46 48
47 class FakeAudioInputCallback : public AudioInputStream::AudioInputCallback { 49 class FakeAudioInputCallback : public AudioInputStream::AudioInputCallback {
48 public: 50 public:
49 FakeAudioInputCallback() 51 FakeAudioInputCallback()
50 : error_(false), 52 : error_(false),
51 data_event_(false, false) { 53 data_event_(false, false),
52 } 54 num_received_audio_frames_(0) {}
53 55
54 const std::vector<uint8>& received_data() const { return received_data_; }
55 bool error() const { return error_; } 56 bool error() const { return error_; }
57 int num_received_audio_frames() const { return num_received_audio_frames_; }
56 58
57 // Waits until OnData() is called on another thread. 59 // Waits until OnData() is called on another thread.
58 void WaitForData() { 60 void WaitForData() {
59 data_event_.Wait(); 61 data_event_.Wait();
60 } 62 }
61 63
62 virtual void OnData(AudioInputStream* stream, 64 virtual void OnData(AudioInputStream* stream,
63 const uint8* src, uint32 size, 65 const AudioBus* src,
64 uint32 hardware_delay_bytes, double volume) OVERRIDE { 66 uint32 hardware_delay_bytes,
65 received_data_.insert(received_data_.end(), src, src + size); 67 double volume) OVERRIDE {
68 EXPECT_NE(hardware_delay_bytes, 0u);
69 num_received_audio_frames_ += src->frames();
66 data_event_.Signal(); 70 data_event_.Signal();
67 } 71 }
68 72
69 virtual void OnError(AudioInputStream* stream) OVERRIDE { 73 virtual void OnError(AudioInputStream* stream) OVERRIDE {
70 error_ = true; 74 error_ = true;
71 } 75 }
72 76
73 private: 77 private:
74 std::vector<uint8> received_data_; 78 int num_received_audio_frames_;
75 base::WaitableEvent data_event_; 79 base::WaitableEvent data_event_;
76 bool error_; 80 bool error_;
77 81
78 DISALLOW_COPY_AND_ASSIGN(FakeAudioInputCallback); 82 DISALLOW_COPY_AND_ASSIGN(FakeAudioInputCallback);
79 }; 83 };
80 84
81 // This audio sink implementation should be used for manual tests only since 85 // This audio sink implementation should be used for manual tests only since
82 // the recorded data is stored on a raw binary data file. 86 // the recorded data is stored on a raw binary data file.
83 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback { 87 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
84 public: 88 public:
85 // Allocate space for ~10 seconds of data @ 48kHz in stereo: 89 // Allocate space for ~10 seconds of data @ 48kHz in stereo:
86 // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes. 90 // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes.
87 static const size_t kMaxBufferSize = 2 * 2 * 480 * 100 * 10; 91 static const size_t kMaxBufferSize = 2 * 2 * 480 * 100 * 10;
88 92
89 explicit WriteToFileAudioSink(const char* file_name) 93 explicit WriteToFileAudioSink(const char* file_name, int bits_per_sample)
90 : buffer_(0, kMaxBufferSize), 94 : bits_per_sample_(bits_per_sample),
95 buffer_(0, kMaxBufferSize),
91 bytes_to_write_(0) { 96 bytes_to_write_(0) {
92 base::FilePath file_path; 97 base::FilePath file_path;
93 EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_path)); 98 EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_path));
94 file_path = file_path.AppendASCII(file_name); 99 file_path = file_path.AppendASCII(file_name);
95 binary_file_ = base::OpenFile(file_path, "wb"); 100 binary_file_ = base::OpenFile(file_path, "wb");
96 DLOG_IF(ERROR, !binary_file_) << "Failed to open binary PCM data file."; 101 DLOG_IF(ERROR, !binary_file_) << "Failed to open binary PCM data file.";
97 VLOG(0) << ">> Output file: " << file_path.value() << " has been created."; 102 VLOG(0) << ">> Output file: " << file_path.value() << " has been created.";
103 VLOG(0) << "bits_per_sample_:" << bits_per_sample_;
98 } 104 }
99 105
100 virtual ~WriteToFileAudioSink() { 106 virtual ~WriteToFileAudioSink() {
101 size_t bytes_written = 0; 107 size_t bytes_written = 0;
102 while (bytes_written < bytes_to_write_) { 108 while (bytes_written < bytes_to_write_) {
103 const uint8* chunk; 109 const uint8* chunk;
104 int chunk_size; 110 int chunk_size;
105 111
106 // Stop writing if no more data is available. 112 // Stop writing if no more data is available.
107 if (!buffer_.GetCurrentChunk(&chunk, &chunk_size)) 113 if (!buffer_.GetCurrentChunk(&chunk, &chunk_size))
108 break; 114 break;
109 115
110 // Write recorded data chunk to the file and prepare for next chunk. 116 // Write recorded data chunk to the file and prepare for next chunk.
111 fwrite(chunk, 1, chunk_size, binary_file_); 117 fwrite(chunk, 1, chunk_size, binary_file_);
112 buffer_.Seek(chunk_size); 118 buffer_.Seek(chunk_size);
113 bytes_written += chunk_size; 119 bytes_written += chunk_size;
114 } 120 }
115 base::CloseFile(binary_file_); 121 base::CloseFile(binary_file_);
116 } 122 }
117 123
118 // AudioInputStream::AudioInputCallback implementation. 124 // AudioInputStream::AudioInputCallback implementation.
119 virtual void OnData(AudioInputStream* stream, 125 virtual void OnData(AudioInputStream* stream,
120 const uint8* src, 126 const AudioBus* src,
121 uint32 size,
122 uint32 hardware_delay_bytes, 127 uint32 hardware_delay_bytes,
123 double volume) { 128 double volume) {
129 EXPECT_EQ(bits_per_sample_, 16);
130 const int num_samples = src->frames() * src->channels();
131 scoped_ptr<int16> interleaved(new int16[num_samples]);
132 const int bytes_per_sample = sizeof(*interleaved);
133 src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get());
134
124 // Store data data in a temporary buffer to avoid making blocking 135 // Store data data in a temporary buffer to avoid making blocking
125 // fwrite() calls in the audio callback. The complete buffer will be 136 // fwrite() calls in the audio callback. The complete buffer will be
126 // written to file in the destructor. 137 // written to file in the destructor.
127 if (buffer_.Append(src, size)) { 138 const int size = bytes_per_sample * num_samples;
139 if (buffer_.Append((const uint8*)interleaved.get(), size)) {
128 bytes_to_write_ += size; 140 bytes_to_write_ += size;
129 } 141 }
130 } 142 }
131 143
132 virtual void OnError(AudioInputStream* stream) {} 144 virtual void OnError(AudioInputStream* stream) {}
133 145
134 private: 146 private:
147 int bits_per_sample_;
135 media::SeekableBuffer buffer_; 148 media::SeekableBuffer buffer_;
136 FILE* binary_file_; 149 FILE* binary_file_;
137 size_t bytes_to_write_; 150 size_t bytes_to_write_;
138 }; 151 };
139 152
140 // Convenience method which ensures that we are not running on the build 153 // Convenience method which ensures that we are not running on the build
141 // bots and that at least one valid input device can be found. We also 154 // bots and that at least one valid input device can be found. We also
142 // verify that we are not running on XP since the low-latency (WASAPI- 155 // verify that we are not running on XP since the low-latency (WASAPI-
143 // based) version requires Windows Vista or higher. 156 // based) version requires Windows Vista or higher.
144 static bool CanRunAudioTests(AudioManager* audio_man) { 157 static bool CanRunAudioTests(AudioManager* audio_man) {
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 382
370 MockAudioInputCallback sink; 383 MockAudioInputCallback sink;
371 384
372 // Derive the expected size in bytes of each recorded packet. 385 // Derive the expected size in bytes of each recorded packet.
373 uint32 bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() * 386 uint32 bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() *
374 (aisw.bits_per_sample() / 8); 387 (aisw.bits_per_sample() / 8);
375 388
376 // We use 10ms packets and will run the test until ten packets are received. 389 // We use 10ms packets and will run the test until ten packets are received.
377 // All should contain valid packets of the same size and a valid delay 390 // All should contain valid packets of the same size and a valid delay
378 // estimate. 391 // estimate.
379 EXPECT_CALL(sink, OnData( 392 EXPECT_CALL(sink, OnData(ais.get(), NotNull(), Gt(bytes_per_packet), _))
380 ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
381 .Times(AtLeast(10)) 393 .Times(AtLeast(10))
382 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop)); 394 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
383 ais->Start(&sink); 395 ais->Start(&sink);
384 loop.Run(); 396 loop.Run();
385 ais->Stop(); 397 ais->Stop();
386 398
387 // Store current packet size (to be used in the subsequent tests). 399 // Store current packet size (to be used in the subsequent tests).
388 int frames_per_buffer_10ms = aisw.frames_per_buffer(); 400 int frames_per_buffer_10ms = aisw.frames_per_buffer();
389 401
390 ais.Close(); 402 ais.Close();
391 403
392 // 20 ms packet size. 404 // 20 ms packet size.
393 405
394 count = 0; 406 count = 0;
395 ais.Reset(aisw.Create(2 * frames_per_buffer_10ms)); 407 ais.Reset(aisw.Create(2 * frames_per_buffer_10ms));
396 EXPECT_TRUE(ais->Open()); 408 EXPECT_TRUE(ais->Open());
397 bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() * 409 bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() *
398 (aisw.bits_per_sample() / 8); 410 (aisw.bits_per_sample() / 8);
399 411
400 EXPECT_CALL(sink, OnData( 412 EXPECT_CALL(sink, OnData(ais.get(), NotNull(), Gt(bytes_per_packet), _))
401 ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
402 .Times(AtLeast(10)) 413 .Times(AtLeast(10))
403 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop)); 414 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
404 ais->Start(&sink); 415 ais->Start(&sink);
405 loop.Run(); 416 loop.Run();
406 ais->Stop(); 417 ais->Stop();
407 ais.Close(); 418 ais.Close();
408 419
409 // 5 ms packet size. 420 // 5 ms packet size.
410 421
411 count = 0; 422 count = 0;
412 ais.Reset(aisw.Create(frames_per_buffer_10ms / 2)); 423 ais.Reset(aisw.Create(frames_per_buffer_10ms / 2));
413 EXPECT_TRUE(ais->Open()); 424 EXPECT_TRUE(ais->Open());
414 bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() * 425 bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() *
415 (aisw.bits_per_sample() / 8); 426 (aisw.bits_per_sample() / 8);
416 427
417 EXPECT_CALL(sink, OnData( 428 EXPECT_CALL(sink, OnData(ais.get(), NotNull(), Gt(bytes_per_packet), _))
418 ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
419 .Times(AtLeast(10)) 429 .Times(AtLeast(10))
420 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop)); 430 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
421 ais->Start(&sink); 431 ais->Start(&sink);
422 loop.Run(); 432 loop.Run();
423 ais->Stop(); 433 ais->Stop();
424 ais.Close(); 434 ais.Close();
425 } 435 }
426 436
427 // Test that we can capture loopback stream. 437 // Test that we can capture a stream in loopback.
428 TEST(WinAudioInputTest, WASAPIAudioInputStreamLoopback) { 438 TEST(WinAudioInputTest, WASAPIAudioInputStreamLoopback) {
429 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); 439 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
430 if (!audio_manager->HasAudioOutputDevices() || !CoreAudioUtil::IsSupported()) 440 if (!audio_manager->HasAudioOutputDevices() || !CoreAudioUtil::IsSupported())
431 return; 441 return;
432 442
433 AudioParameters params = audio_manager->GetInputStreamParameters( 443 AudioParameters params = audio_manager->GetInputStreamParameters(
434 AudioManagerBase::kLoopbackInputDeviceId); 444 AudioManagerBase::kLoopbackInputDeviceId);
435 EXPECT_EQ(params.effects(), 0); 445 EXPECT_EQ(params.effects(), 0);
436 446
437 AudioParameters output_params = 447 AudioParameters output_params =
438 audio_manager->GetOutputStreamParameters(std::string()); 448 audio_manager->GetOutputStreamParameters(std::string());
439 EXPECT_EQ(params.sample_rate(), output_params.sample_rate()); 449 EXPECT_EQ(params.sample_rate(), output_params.sample_rate());
440 EXPECT_EQ(params.channel_layout(), output_params.channel_layout()); 450 EXPECT_EQ(params.channel_layout(), output_params.channel_layout());
441 451
442 ScopedAudioInputStream stream(audio_manager->MakeAudioInputStream( 452 ScopedAudioInputStream stream(audio_manager->MakeAudioInputStream(
443 params, AudioManagerBase::kLoopbackInputDeviceId)); 453 params, AudioManagerBase::kLoopbackInputDeviceId));
444 ASSERT_TRUE(stream->Open()); 454 ASSERT_TRUE(stream->Open());
445 FakeAudioInputCallback sink; 455 FakeAudioInputCallback sink;
446 stream->Start(&sink); 456 stream->Start(&sink);
447 ASSERT_FALSE(sink.error()); 457 ASSERT_FALSE(sink.error());
448 458
449 sink.WaitForData(); 459 sink.WaitForData();
450 stream.Close(); 460 stream.Close();
451 461
452 EXPECT_FALSE(sink.received_data().empty()); 462 EXPECT_GT(sink.num_received_audio_frames(), 0);
453 EXPECT_FALSE(sink.error()); 463 EXPECT_FALSE(sink.error());
454 } 464 }
455 465
456 // This test is intended for manual tests and should only be enabled 466 // This test is intended for manual tests and should only be enabled
457 // when it is required to store the captured data on a local file. 467 // when it is required to store the captured data on a local file.
458 // By default, GTest will print out YOU HAVE 1 DISABLED TEST. 468 // By default, GTest will print out YOU HAVE 1 DISABLED TEST.
459 // To include disabled tests in test execution, just invoke the test program 469 // To include disabled tests in test execution, just invoke the test program
460 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS 470 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
461 // environment variable to a value greater than 0. 471 // environment variable to a value greater than 0.
462 TEST(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { 472 TEST(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) {
463 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); 473 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
464 if (!CanRunAudioTests(audio_manager.get())) 474 if (!CanRunAudioTests(audio_manager.get()))
465 return; 475 return;
466 476
467 // Name of the output PCM file containing captured data. The output file 477 // Name of the output PCM file containing captured data. The output file
468 // will be stored in the directory containing 'media_unittests.exe'. 478 // will be stored in the directory containing 'media_unittests.exe'.
469 // Example of full name: \src\build\Debug\out_stereo_10sec.pcm. 479 // Example of full name: \src\build\Debug\out_stereo_10sec.pcm.
470 const char* file_name = "out_stereo_10sec.pcm"; 480 const char* file_name = "out_stereo_10sec.pcm";
471 481
472 AudioInputStreamWrapper aisw(audio_manager.get()); 482 AudioInputStreamWrapper aisw(audio_manager.get());
473 ScopedAudioInputStream ais(aisw.Create()); 483 ScopedAudioInputStream ais(aisw.Create());
474 EXPECT_TRUE(ais->Open()); 484 EXPECT_TRUE(ais->Open());
475 485
476 VLOG(0) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]"; 486 VLOG(0) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]";
477 WriteToFileAudioSink file_sink(file_name); 487 WriteToFileAudioSink file_sink(file_name, aisw.bits_per_sample());
478 VLOG(0) << ">> Speak into the default microphone while recording."; 488 VLOG(0) << ">> Speak into the default microphone while recording.";
479 ais->Start(&file_sink); 489 ais->Start(&file_sink);
480 base::PlatformThread::Sleep(TestTimeouts::action_timeout()); 490 base::PlatformThread::Sleep(TestTimeouts::action_timeout());
481 ais->Stop(); 491 ais->Stop();
482 VLOG(0) << ">> Recording has stopped."; 492 VLOG(0) << ">> Recording has stopped.";
483 ais.Close(); 493 ais.Close();
484 } 494 }
485 495
486 } // namespace media 496 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/win/audio_low_latency_input_win.cc ('k') | media/audio/win/wavein_input_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698