Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 10 matching lines...) Expand all Loading... | |
| 21 #include "media/audio/win/core_audio_util_win.h" | 21 #include "media/audio/win/core_audio_util_win.h" |
| 22 #include "media/base/decoder_buffer.h" | 22 #include "media/base/decoder_buffer.h" |
| 23 #include "media/base/seekable_buffer.h" | 23 #include "media/base/seekable_buffer.h" |
| 24 #include "media/base/test_data_util.h" | 24 #include "media/base/test_data_util.h" |
| 25 #include "testing/gmock_mutant.h" | 25 #include "testing/gmock_mutant.h" |
| 26 #include "testing/gmock/include/gmock/gmock.h" | 26 #include "testing/gmock/include/gmock/gmock.h" |
| 27 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
| 28 | 28 |
| 29 using ::testing::_; | 29 using ::testing::_; |
| 30 using ::testing::AnyNumber; | 30 using ::testing::AnyNumber; |
| 31 using ::testing::AtLeast; | |
| 31 using ::testing::Between; | 32 using ::testing::Between; |
| 32 using ::testing::CreateFunctor; | 33 using ::testing::CreateFunctor; |
| 33 using ::testing::DoAll; | 34 using ::testing::DoAll; |
| 34 using ::testing::Gt; | 35 using ::testing::Gt; |
| 35 using ::testing::InvokeWithoutArgs; | 36 using ::testing::InvokeWithoutArgs; |
| 36 using ::testing::NotNull; | 37 using ::testing::NotNull; |
| 37 using ::testing::Return; | 38 using ::testing::Return; |
| 38 using base::win::ScopedCOMInitializer; | 39 using base::win::ScopedCOMInitializer; |
| 39 | 40 |
| 40 namespace media { | 41 namespace media { |
| 41 | 42 |
| 42 static const char kSpeechFile_16b_s_48k[] = "speech_16b_stereo_48kHz.raw"; | 43 static const char kSpeechFile_16b_s_48k[] = "speech_16b_stereo_48kHz.raw"; |
| 43 static const char kSpeechFile_16b_s_44k[] = "speech_16b_stereo_44kHz.raw"; | 44 static const char kSpeechFile_16b_s_44k[] = "speech_16b_stereo_44kHz.raw"; |
| 44 static const size_t kFileDurationMs = 20000; | 45 static const size_t kFileDurationMs = 20000; |
| 45 static const size_t kNumFileSegments = 2; | 46 static const size_t kNumFileSegments = 2; |
| 46 static const int kBitsPerSample = 16; | 47 static const int kBitsPerSample = 16; |
| 47 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; | |
| 48 static const size_t kMaxDeltaSamples = 1000; | 48 static const size_t kMaxDeltaSamples = 1000; |
| 49 static const char* kDeltaTimeMsFileName = "delta_times_ms.txt"; | 49 static const char* kDeltaTimeMsFileName = "delta_times_ms.txt"; |
| 50 | 50 |
| 51 MATCHER_P(HasValidDelay, value, "") { | 51 MATCHER_P(HasValidDelay, value, "") { |
| 52 // It is difficult to come up with a perfect test condition for the delay | 52 // It is difficult to come up with a perfect test condition for the delay |
| 53 // estimation. For now, verify that the produced output delay is always | 53 // estimation. For now, verify that the produced output delay is always |
| 54 // larger than the selected buffer size. | 54 // larger than the selected buffer size. |
| 55 return arg.hardware_delay_bytes > value.hardware_delay_bytes; | 55 return arg.hardware_delay_bytes >= value.hardware_delay_bytes; |
| 56 } | 56 } |
| 57 | 57 |
| 58 // Used to terminate a loop from a different thread than the loop belongs to. | 58 // Used to terminate a loop from a different thread than the loop belongs to. |
| 59 // |loop| should be a MessageLoopProxy. | 59 // |loop| should be a MessageLoopProxy. |
| 60 ACTION_P(QuitLoop, loop) { | 60 ACTION_P(QuitLoop, loop) { |
| 61 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | 61 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
| 62 } | 62 } |
| 63 | 63 |
| 64 class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { | 64 class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { |
| 65 public: | 65 public: |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 174 return false; | 174 return false; |
| 175 } | 175 } |
| 176 | 176 |
| 177 // TODO(henrika): note that we use Wave today to query the number of | 177 // TODO(henrika): note that we use Wave today to query the number of |
| 178 // existing output devices. | 178 // existing output devices. |
| 179 if (!audio_man->HasAudioOutputDevices()) { | 179 if (!audio_man->HasAudioOutputDevices()) { |
| 180 LOG(WARNING) << "No output devices detected."; | 180 LOG(WARNING) << "No output devices detected."; |
| 181 return false; | 181 return false; |
| 182 } | 182 } |
| 183 | 183 |
| 184 if (WASAPIAudioOutputStream::HardwareChannelLayout() != kChannelLayout) { | |
| 185 LOG(WARNING) << "This test requires stereo audio output."; | |
| 186 return false; | |
| 187 } | |
| 188 | |
| 189 return true; | 184 return true; |
| 190 } | 185 } |
| 191 | 186 |
| 192 // Convenience method which creates a default AudioOutputStream object but | 187 // Convenience method which creates a default AudioOutputStream object but |
| 193 // also allows the user to modify the default settings. | 188 // also allows the user to modify the default settings. |
| 194 class AudioOutputStreamWrapper { | 189 class AudioOutputStreamWrapper { |
| 195 public: | 190 public: |
| 196 explicit AudioOutputStreamWrapper(AudioManager* audio_manager) | 191 explicit AudioOutputStreamWrapper(AudioManager* audio_manager) |
| 197 : com_init_(ScopedCOMInitializer::kMTA), | 192 : audio_man_(audio_manager), |
| 198 audio_man_(audio_manager), | |
| 199 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY), | 193 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY), |
| 200 channel_layout_(kChannelLayout), | |
| 201 bits_per_sample_(kBitsPerSample) { | 194 bits_per_sample_(kBitsPerSample) { |
| 202 // Use native/mixing sample rate and 10ms frame size as default. | 195 AudioParameters preferred_params; |
| 203 sample_rate_ = static_cast<int>( | 196 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( |
| 204 WASAPIAudioOutputStream::HardwareSampleRate(eConsole)); | 197 eRender, eConsole, &preferred_params))); |
| 205 samples_per_packet_ = sample_rate_ / 100; | 198 channel_layout_ = preferred_params.channel_layout(); |
| 206 DCHECK(sample_rate_); | 199 sample_rate_ = preferred_params.sample_rate(); |
| 200 samples_per_packet_ = preferred_params.frames_per_buffer(); | |
| 207 } | 201 } |
| 208 | 202 |
| 209 ~AudioOutputStreamWrapper() {} | 203 ~AudioOutputStreamWrapper() {} |
| 210 | 204 |
| 211 // Creates AudioOutputStream object using default parameters. | 205 // Creates AudioOutputStream object using default parameters. |
| 212 AudioOutputStream* Create() { | 206 AudioOutputStream* Create() { |
| 213 return CreateOutputStream(); | 207 return CreateOutputStream(); |
| 214 } | 208 } |
| 215 | 209 |
| 216 // Creates AudioOutputStream object using non-default parameters where the | 210 // Creates AudioOutputStream object using non-default parameters where the |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 236 | 230 |
| 237 private: | 231 private: |
| 238 AudioOutputStream* CreateOutputStream() { | 232 AudioOutputStream* CreateOutputStream() { |
| 239 AudioOutputStream* aos = audio_man_->MakeAudioOutputStream( | 233 AudioOutputStream* aos = audio_man_->MakeAudioOutputStream( |
| 240 AudioParameters(format_, channel_layout_, sample_rate_, | 234 AudioParameters(format_, channel_layout_, sample_rate_, |
| 241 bits_per_sample_, samples_per_packet_)); | 235 bits_per_sample_, samples_per_packet_)); |
| 242 EXPECT_TRUE(aos); | 236 EXPECT_TRUE(aos); |
| 243 return aos; | 237 return aos; |
| 244 } | 238 } |
| 245 | 239 |
| 246 ScopedCOMInitializer com_init_; | |
|
tommi (sloooow) - chröme
2013/01/31 13:42:08
where is COM now initialized?
henrika (OOO until Aug 14)
2013/01/31 14:29:38
AudioManagerBase::AudioManagerBase() does that for
| |
| 247 AudioManager* audio_man_; | 240 AudioManager* audio_man_; |
| 248 AudioParameters::Format format_; | 241 AudioParameters::Format format_; |
| 249 ChannelLayout channel_layout_; | 242 ChannelLayout channel_layout_; |
| 250 int bits_per_sample_; | 243 int bits_per_sample_; |
| 251 int sample_rate_; | 244 int sample_rate_; |
| 252 int samples_per_packet_; | 245 int samples_per_packet_; |
| 253 }; | 246 }; |
| 254 | 247 |
| 255 // Convenience method which creates a default AudioOutputStream object. | 248 // Convenience method which creates a default AudioOutputStream object. |
| 256 static AudioOutputStream* CreateDefaultAudioOutputStream( | 249 static AudioOutputStream* CreateDefaultAudioOutputStream( |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 432 aos->Stop(); | 425 aos->Stop(); |
| 433 EXPECT_FALSE(waos->started()); | 426 EXPECT_FALSE(waos->started()); |
| 434 aos->Start(&source); | 427 aos->Start(&source); |
| 435 EXPECT_TRUE(waos->started()); | 428 EXPECT_TRUE(waos->started()); |
| 436 aos->Stop(); | 429 aos->Stop(); |
| 437 EXPECT_FALSE(waos->started()); | 430 EXPECT_FALSE(waos->started()); |
| 438 | 431 |
| 439 aos->Close(); | 432 aos->Close(); |
| 440 } | 433 } |
| 441 | 434 |
| 442 // Use default packet size (10ms) and verify that rendering starts. | 435 // Use preferred packet size and verify that rendering starts. |
| 443 TEST(WASAPIAudioOutputStreamTest, PacketSizeInMilliseconds) { | 436 TEST(WASAPIAudioOutputStreamTest, ValidPacketSize) { |
| 444 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | 437 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); |
| 445 if (!CanRunAudioTests(audio_manager.get())) | 438 if (!CanRunAudioTests(audio_manager.get())) |
| 446 return; | 439 return; |
| 447 | 440 |
| 448 MessageLoopForUI loop; | 441 MessageLoopForUI loop; |
| 449 MockAudioSourceCallback source; | 442 MockAudioSourceCallback source; |
| 450 | 443 |
| 451 // Create default WASAPI output stream which plays out in stereo using | 444 // Create default WASAPI output stream which plays out in stereo using |
| 452 // the shared mixing rate. The default buffer size is 10ms. | 445 // the shared mixing rate. The default buffer size is 10ms. |
| 453 AudioOutputStreamWrapper aosw(audio_manager.get()); | 446 AudioOutputStreamWrapper aosw(audio_manager.get()); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 468 Return(aosw.samples_per_packet()))); | 461 Return(aosw.samples_per_packet()))); |
| 469 | 462 |
| 470 aos->Start(&source); | 463 aos->Start(&source); |
| 471 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 464 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
| 472 TestTimeouts::action_timeout()); | 465 TestTimeouts::action_timeout()); |
| 473 loop.Run(); | 466 loop.Run(); |
| 474 aos->Stop(); | 467 aos->Stop(); |
| 475 aos->Close(); | 468 aos->Close(); |
| 476 } | 469 } |
| 477 | 470 |
| 478 // Use a fixed packets size (independent of sample rate) and verify | 471 // Use a non-preferred packet size and verify that Open() fails. |
| 479 // that rendering starts. | 472 TEST(WASAPIAudioOutputStreamTest, InvalidPacketSize) { |
| 480 TEST(WASAPIAudioOutputStreamTest, PacketSizeInSamples) { | |
| 481 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | 473 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); |
| 482 if (!CanRunAudioTests(audio_manager.get())) | 474 if (!CanRunAudioTests(audio_manager.get())) |
| 483 return; | 475 return; |
| 484 | 476 |
| 485 MessageLoopForUI loop; | 477 if (ExclusiveModeIsEnabled()) |
| 486 MockAudioSourceCallback source; | 478 return; |
| 487 | 479 |
| 488 // Create default WASAPI output stream which reads data in stereo using | 480 AudioParameters preferred_params; |
| 489 // the native mixing rate and channel count. The buffer size is set to | 481 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( |
| 490 // 1024 samples. | 482 eRender, eConsole, &preferred_params))); |
| 483 int too_large_packet_size = 2 * preferred_params.frames_per_buffer(); | |
| 484 | |
| 491 AudioOutputStreamWrapper aosw(audio_manager.get()); | 485 AudioOutputStreamWrapper aosw(audio_manager.get()); |
| 492 AudioOutputStream* aos = aosw.Create(1024); | 486 AudioOutputStream* aos = aosw.Create(too_large_packet_size); |
| 493 EXPECT_TRUE(aos->Open()); | 487 EXPECT_FALSE(aos->Open()); |
| 494 | 488 |
| 495 // Derive the expected size in bytes of each packet. | |
| 496 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | |
| 497 (aosw.bits_per_sample() / 8); | |
| 498 | |
| 499 // Set up expected minimum delay estimation. | |
| 500 AudioBuffersState state(0, bytes_per_packet); | |
| 501 | |
| 502 // Ensure that callbacks start correctly. | |
| 503 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state))) | |
| 504 .WillOnce(DoAll( | |
| 505 QuitLoop(loop.message_loop_proxy()), | |
| 506 Return(aosw.samples_per_packet()))) | |
| 507 .WillRepeatedly(Return(aosw.samples_per_packet())); | |
| 508 | |
| 509 aos->Start(&source); | |
| 510 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | |
| 511 TestTimeouts::action_timeout()); | |
| 512 loop.Run(); | |
| 513 aos->Stop(); | |
| 514 aos->Close(); | 489 aos->Close(); |
| 515 } | 490 } |
| 516 | 491 |
| 517 // This test is intended for manual tests and should only be enabled | 492 // This test is intended for manual tests and should only be enabled |
| 518 // when it is required to play out data from a local PCM file. | 493 // when it is required to play out data from a local PCM file. |
| 519 // By default, GTest will print out YOU HAVE 1 DISABLED TEST. | 494 // By default, GTest will print out YOU HAVE 1 DISABLED TEST. |
| 520 // To include disabled tests in test execution, just invoke the test program | 495 // To include disabled tests in test execution, just invoke the test program |
| 521 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS | 496 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS |
| 522 // environment variable to a value greater than 0. | 497 // environment variable to a value greater than 0. |
| 523 // The test files are approximately 20 seconds long. | 498 // The test files are approximately 20 seconds long. |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 697 AudioOutputStream* aos = aosw.Create(48000, 160); | 672 AudioOutputStream* aos = aosw.Create(48000, 160); |
| 698 EXPECT_TRUE(aos->Open()); | 673 EXPECT_TRUE(aos->Open()); |
| 699 | 674 |
| 700 // Derive the expected size in bytes of each packet. | 675 // Derive the expected size in bytes of each packet. |
| 701 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | 676 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * |
| 702 (aosw.bits_per_sample() / 8); | 677 (aosw.bits_per_sample() / 8); |
| 703 | 678 |
| 704 // Set up expected minimum delay estimation. | 679 // Set up expected minimum delay estimation. |
| 705 AudioBuffersState state(0, bytes_per_packet); | 680 AudioBuffersState state(0, bytes_per_packet); |
| 706 | 681 |
| 707 // Wait for the first callback and verify its parameters. | 682 // Wait for the first callback and verify its parameters. |
| 708 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state))) | 683 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state))) |
| 709 .WillOnce(DoAll( | 684 .WillOnce(DoAll( |
| 710 QuitLoop(loop.message_loop_proxy()), | 685 QuitLoop(loop.message_loop_proxy()), |
| 711 Return(aosw.samples_per_packet()))) | 686 Return(aosw.samples_per_packet()))) |
| 712 .WillRepeatedly(Return(aosw.samples_per_packet())); | 687 .WillRepeatedly(Return(aosw.samples_per_packet())); |
| 713 | 688 |
| 714 aos->Start(&source); | 689 aos->Start(&source); |
| 715 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 690 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
| 716 TestTimeouts::action_timeout()); | 691 TestTimeouts::action_timeout()); |
| 717 loop.Run(); | 692 loop.Run(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 754 | 729 |
| 755 aos->Start(&source); | 730 aos->Start(&source); |
| 756 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 731 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
| 757 TestTimeouts::action_timeout()); | 732 TestTimeouts::action_timeout()); |
| 758 loop.Run(); | 733 loop.Run(); |
| 759 aos->Stop(); | 734 aos->Stop(); |
| 760 aos->Close(); | 735 aos->Close(); |
| 761 } | 736 } |
| 762 | 737 |
| 763 } // namespace media | 738 } // namespace media |
| OLD | NEW |