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

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

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

Powered by Google App Engine
This is Rietveld 408576698