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/command_line.h" | |
| 9 #include "base/environment.h" | 10 #include "base/environment.h" |
| 10 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "media/base/media_switches.h" | |
| 11 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 13 #include "base/test/test_timeouts.h" | 15 #include "base/test/test_timeouts.h" |
| 14 #include "base/time.h" | 16 #include "base/time.h" |
| 15 #include "base/path_service.h" | 17 #include "base/path_service.h" |
| 16 #include "base/win/scoped_com_initializer.h" | 18 #include "base/win/scoped_com_initializer.h" |
| 17 #include "media/audio/audio_io.h" | 19 #include "media/audio/audio_io.h" |
| 18 #include "media/audio/audio_manager.h" | 20 #include "media/audio/audio_manager.h" |
| 19 #include "media/audio/audio_util.h" | 21 #include "media/audio/audio_util.h" |
| 20 #include "media/audio/win/audio_low_latency_output_win.h" | 22 #include "media/audio/win/audio_low_latency_output_win.h" |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 34 using ::testing::InvokeWithoutArgs; | 36 using ::testing::InvokeWithoutArgs; |
| 35 using ::testing::NotNull; | 37 using ::testing::NotNull; |
| 36 using ::testing::Return; | 38 using ::testing::Return; |
| 37 using base::win::ScopedCOMInitializer; | 39 using base::win::ScopedCOMInitializer; |
| 38 | 40 |
| 39 namespace media { | 41 namespace media { |
| 40 | 42 |
| 41 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"; |
| 42 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"; |
| 43 static const size_t kFileDurationMs = 20000; | 45 static const size_t kFileDurationMs = 20000; |
| 44 static const size_t kNumFileSegments = 1; | 46 static const size_t kNumFileSegments = 2; |
| 45 | 47 |
| 46 static const size_t kMaxDeltaSamples = 1000; | 48 static const size_t kMaxDeltaSamples = 1000; |
| 47 static const char* kDeltaTimeMsFileName = "delta_times_ms.txt"; | 49 static const char* kDeltaTimeMsFileName = "delta_times_ms.txt"; |
| 48 | 50 |
| 49 MATCHER_P(HasValidDelay, value, "") { | 51 MATCHER_P(HasValidDelay, value, "") { |
| 50 // 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 |
| 51 // estimation. For now, verify that the produced output delay is always | 53 // estimation. For now, verify that the produced output delay is always |
| 52 // larger than the selected buffer size. | 54 // larger than the selected buffer size. |
| 53 return arg.hardware_delay_bytes > value.hardware_delay_bytes; | 55 return arg.hardware_delay_bytes > value.hardware_delay_bytes; |
| 54 } | 56 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 | 133 |
| 132 private: | 134 private: |
| 133 scoped_refptr<DecoderBuffer> file_; | 135 scoped_refptr<DecoderBuffer> file_; |
| 134 scoped_array<int> delta_times_; | 136 scoped_array<int> delta_times_; |
| 135 int pos_; | 137 int pos_; |
| 136 base::Time previous_call_time_; | 138 base::Time previous_call_time_; |
| 137 FILE* text_file_; | 139 FILE* text_file_; |
| 138 size_t elements_to_write_; | 140 size_t elements_to_write_; |
| 139 }; | 141 }; |
| 140 | 142 |
| 143 static bool ExclusiveModeIsEnabled() { | |
| 144 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | |
| 145 return (cmd_line->HasSwitch(switches::kEnableExclusiveMode)); | |
| 146 } | |
| 147 | |
| 141 // Convenience method which ensures that we are not running on the build | 148 // Convenience method which ensures that we are not running on the build |
| 142 // bots and that at least one valid output device can be found. We also | 149 // bots and that at least one valid output device can be found. We also |
| 143 // verify that we are not running on XP since the low-latency (WASAPI- | 150 // verify that we are not running on XP since the low-latency (WASAPI- |
| 144 // based) version requires Windows Vista or higher. | 151 // based) version requires Windows Vista or higher. |
| 145 static bool CanRunAudioTests(AudioManager* audio_man) { | 152 static bool CanRunAudioTests(AudioManager* audio_man) { |
| 146 if (!media::IsWASAPISupported()) { | 153 if (!media::IsWASAPISupported()) { |
| 147 LOG(WARNING) << "This tests requires Windows Vista or higher."; | 154 LOG(WARNING) << "This tests requires Windows Vista or higher."; |
| 148 return false; | 155 return false; |
| 149 } | 156 } |
| 150 // TODO(henrika): note that we use Wave today to query the number of | 157 // TODO(henrika): note that we use Wave today to query the number of |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 179 } | 186 } |
| 180 | 187 |
| 181 // Creates AudioOutputStream object using non-default parameters where the | 188 // Creates AudioOutputStream object using non-default parameters where the |
| 182 // frame size is modified. | 189 // frame size is modified. |
| 183 AudioOutputStream* Create(int samples_per_packet) { | 190 AudioOutputStream* Create(int samples_per_packet) { |
| 184 samples_per_packet_ = samples_per_packet; | 191 samples_per_packet_ = samples_per_packet; |
| 185 return CreateOutputStream(); | 192 return CreateOutputStream(); |
| 186 } | 193 } |
| 187 | 194 |
| 188 // Creates AudioOutputStream object using non-default parameters where the | 195 // Creates AudioOutputStream object using non-default parameters where the |
| 196 // sample rate and frame size are modified. | |
| 197 AudioOutputStream* Create(int sample_rate, int samples_per_packet) { | |
| 198 sample_rate_ = sample_rate; | |
| 199 samples_per_packet_ = samples_per_packet; | |
| 200 return CreateOutputStream(); | |
| 201 } | |
| 202 | |
| 203 // Creates AudioOutputStream object using non-default parameters where the | |
| 189 // channel layout is modified. | 204 // channel layout is modified. |
| 190 AudioOutputStream* Create(ChannelLayout channel_layout) { | 205 AudioOutputStream* Create(ChannelLayout channel_layout) { |
| 191 channel_layout_ = channel_layout; | 206 channel_layout_ = channel_layout; |
| 192 return CreateOutputStream(); | 207 return CreateOutputStream(); |
| 193 } | 208 } |
| 194 | 209 |
| 195 AudioParameters::Format format() const { return format_; } | 210 AudioParameters::Format format() const { return format_; } |
| 196 int channels() const { return ChannelLayoutToChannelCount(channel_layout_); } | 211 int channels() const { return ChannelLayoutToChannelCount(channel_layout_); } |
| 197 int bits_per_sample() const { return bits_per_sample_; } | 212 int bits_per_sample() const { return bits_per_sample_; } |
| 198 int sample_rate() const { return sample_rate_; } | 213 int sample_rate() const { return sample_rate_; } |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 541 } | 556 } |
| 542 ReadFromFileAudioSource file_source(file_name); | 557 ReadFromFileAudioSource file_source(file_name); |
| 543 | 558 |
| 544 LOG(INFO) << "File name : " << file_name.c_str(); | 559 LOG(INFO) << "File name : " << file_name.c_str(); |
| 545 LOG(INFO) << "Sample rate : " << aosw.sample_rate(); | 560 LOG(INFO) << "Sample rate : " << aosw.sample_rate(); |
| 546 LOG(INFO) << "File size : " << file_source.file_size(); | 561 LOG(INFO) << "File size : " << file_source.file_size(); |
| 547 LOG(INFO) << "#file segments: " << kNumFileSegments; | 562 LOG(INFO) << "#file segments: " << kNumFileSegments; |
| 548 LOG(INFO) << ">> Listen to the file while playing..."; | 563 LOG(INFO) << ">> Listen to the file while playing..."; |
| 549 | 564 |
| 550 for (int i = 0; i < kNumFileSegments; i++) { | 565 for (int i = 0; i < kNumFileSegments; i++) { |
| 566 LOG(INFO) << ">> File segment: " << i + 1; | |
|
scherkus (not reviewing)
2012/06/27 04:20:30
logspam! remove?
henrika (OOO until Aug 14)
2012/06/27 11:26:07
Sorry. Done.
| |
| 551 // Each segment will start with a short (~20ms) block of zeros, hence | 567 // Each segment will start with a short (~20ms) block of zeros, hence |
| 552 // some short glitches might be heard in this test if kNumFileSegments | 568 // some short glitches might be heard in this test if kNumFileSegments |
| 553 // is larger than one. The exact length of the silence period depends on | 569 // is larger than one. The exact length of the silence period depends on |
| 554 // the selected sample rate. | 570 // the selected sample rate. |
| 555 aos->Start(&file_source); | 571 aos->Start(&file_source); |
| 556 base::PlatformThread::Sleep( | 572 base::PlatformThread::Sleep( |
| 557 base::TimeDelta::FromMilliseconds(kFileDurationMs / kNumFileSegments)); | 573 base::TimeDelta::FromMilliseconds(kFileDurationMs / kNumFileSegments)); |
| 558 aos->Stop(); | 574 aos->Stop(); |
| 559 } | 575 } |
| 560 | 576 |
| 561 LOG(INFO) << ">> File playout has stopped."; | 577 LOG(INFO) << ">> File playout has stopped."; |
| 562 aos->Close(); | 578 aos->Close(); |
| 563 } | 579 } |
| 564 | 580 |
| 581 // Verify that we can open the output stream in exclusive mode using a | |
| 582 // certain set of audio parameters and a sample rate of 48kHz. | |
| 583 // The expected outcomes of each setting in this test has been derived | |
| 584 // manually using log outputs (--v=1). | |
| 585 TEST(WinAudioOutputTest, | |
| 586 WASAPIAudioOutputStreamTestExclusiveModeBufferSizesAt48kHzSampleRate) { | |
| 587 if (!ExclusiveModeIsEnabled()) | |
|
scherkus (not reviewing)
2012/06/27 04:20:30
any reason we wouldn't want to run these tests all
henrika (OOO until Aug 14)
2012/06/27 11:26:07
Good point. I had the same idea initially but the
| |
| 588 return; | |
| 589 | |
| 590 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | |
| 591 if (!CanRunAudioTests(audio_manager.get())) | |
| 592 return; | |
| 593 | |
| 594 AudioOutputStreamWrapper aosw(audio_manager.get()); | |
| 595 | |
| 596 // 10ms @ 48kHz shall work. | |
| 597 // Note that, this is the same size as we can use for shared-mode streaming | |
| 598 // but here the endpoint buffer delay is only 10ms instead of 20ms. | |
| 599 AudioOutputStream* aos = aosw.Create(48000, 480); | |
| 600 EXPECT_TRUE(aos->Open()); | |
| 601 aos->Close(); | |
| 602 | |
| 603 // 5ms @ 48kHz does not work to misalignment. | |
| 604 // This test will propose an aligned buffer size of 5.3333ms. | |
| 605 aos = aosw.Create(48000, 240); | |
| 606 EXPECT_FALSE(aos->Open()); | |
| 607 aos->Close(); | |
| 608 | |
| 609 // 5.3333ms @ 48kHz shall work (see test above). | |
| 610 aos = aosw.Create(48000, 256); | |
| 611 EXPECT_TRUE(aos->Open()); | |
| 612 aos->Close(); | |
| 613 | |
| 614 // 2.6667ms is smaller than the minimum supported size (=3ms). | |
| 615 aos = aosw.Create(48000, 128); | |
| 616 EXPECT_FALSE(aos->Open()); | |
| 617 aos->Close(); | |
| 618 | |
| 619 // 3ms does not correspond to an aligned buffer size. | |
| 620 // This test will propose an aligned buffer size of 3.3333ms. | |
| 621 aos = aosw.Create(48000, 144); | |
| 622 EXPECT_FALSE(aos->Open()); | |
| 623 aos->Close(); | |
| 624 | |
| 625 // 3.3333ms @ 48kHz <=> smallest possible buffer size we can use. | |
| 626 aos = aosw.Create(48000, 160); | |
| 627 EXPECT_TRUE(aos->Open()); | |
| 628 aos->Close(); | |
| 629 } | |
| 630 | |
| 631 // Verify that we can open the output stream in exclusive mode using a | |
| 632 // certain set of audio parameters and a sample rate of 44.1kHz. | |
| 633 // The expected outcomes of each setting in this test has been derived | |
| 634 // manually using log outputs (--v=1). | |
| 635 TEST(WinAudioOutputTest, | |
| 636 WASAPIAudioOutputStreamTestExclusiveModeBufferSizesAt44kHzSampleRate) { | |
| 637 if (!ExclusiveModeIsEnabled()) | |
|
scherkus (not reviewing)
2012/06/27 04:20:30
fix indent
henrika (OOO until Aug 14)
2012/06/27 11:26:07
Done.
| |
| 638 return; | |
| 639 | |
| 640 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | |
| 641 if (!CanRunAudioTests(audio_manager.get())) | |
| 642 return; | |
| 643 | |
| 644 AudioOutputStreamWrapper aosw(audio_manager.get()); | |
| 645 | |
| 646 // 10ms @ 44.1kHz does not work due to misalignment. | |
| 647 // This test will propose an aligned buffer size of 10.1587ms. | |
| 648 AudioOutputStream* aos = aosw.Create(44100, 441); | |
| 649 EXPECT_FALSE(aos->Open()); | |
| 650 aos->Close(); | |
| 651 | |
| 652 // 10.1587ms @ 44.1kHz shall work (see test above). | |
| 653 aos = aosw.Create(44100, 448); | |
| 654 EXPECT_TRUE(aos->Open()); | |
| 655 aos->Close(); | |
| 656 | |
| 657 // 5.8050ms @ 44.1 shall work. | |
| 658 aos = aosw.Create(44100, 256); | |
| 659 EXPECT_TRUE(aos->Open()); | |
| 660 aos->Close(); | |
| 661 | |
| 662 // 4.9887ms @ 44.1kHz does not work to misalignment. | |
| 663 // This test will propose an aligned buffer size of 5.0794ms. | |
| 664 aos = aosw.Create(44100, 220); | |
| 665 EXPECT_FALSE(aos->Open()); | |
| 666 aos->Close(); | |
| 667 | |
| 668 // 5.0794ms @ 44.1kHz shall work (see test above). | |
| 669 aos = aosw.Create(44100, 224); | |
| 670 EXPECT_TRUE(aos->Open()); | |
| 671 aos->Close(); | |
| 672 | |
| 673 // 2.9025ms is smaller than the minimum supported size (=3ms). | |
| 674 aos = aosw.Create(44100, 132); | |
| 675 EXPECT_FALSE(aos->Open()); | |
| 676 aos->Close(); | |
| 677 | |
| 678 // 3.01587ms is larger than the minimum size but is not aligned. | |
| 679 // This test will propose an aligned buffer size of 3.6281ms. | |
| 680 aos = aosw.Create(44100, 133); | |
| 681 EXPECT_FALSE(aos->Open()); | |
| 682 aos->Close(); | |
| 683 | |
| 684 // 3.6281ms @ 44.1kHz <=> smallest possible buffer size we can use. | |
| 685 aos = aosw.Create(44100, 160); | |
| 686 EXPECT_TRUE(aos->Open()); | |
| 687 aos->Close(); | |
| 688 } | |
| 689 | |
| 690 // Verify that we can open and start the output stream in exclusive mode at | |
| 691 // the lowest possible delay at 48kHz. | |
| 692 TEST(WinAudioOutputTest, | |
| 693 WASAPIAudioOutputStreamTestExclusiveModeMinBufferSizeAt48kHzSampleRate) { | |
| 694 if (!ExclusiveModeIsEnabled()) | |
| 695 return; | |
| 696 | |
| 697 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | |
| 698 if (!CanRunAudioTests(audio_manager.get())) | |
| 699 return; | |
| 700 | |
| 701 MessageLoopForUI loop; | |
| 702 scoped_refptr<base::MessageLoopProxy> proxy(loop.message_loop_proxy()); | |
| 703 | |
| 704 MockAudioSourceCallback source; | |
| 705 | |
| 706 // Create exclusive-mode WASAPI output stream which plays out in stereo | |
| 707 // using the minimum buffer size at 48kHz sample rate. | |
| 708 AudioOutputStreamWrapper aosw(audio_manager.get()); | |
| 709 AudioOutputStream* aos = aosw.Create(48000, 160); | |
| 710 EXPECT_TRUE(aos->Open()); | |
| 711 | |
| 712 // Derive the expected size in bytes of each packet. | |
| 713 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | |
| 714 (aosw.bits_per_sample() / 8); | |
| 715 | |
| 716 // Set up expected minimum delay estimation. | |
| 717 AudioBuffersState state(0, bytes_per_packet); | |
| 718 | |
| 719 // Wait for the first callback and verify its parameters. | |
| 720 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet, | |
| 721 HasValidDelay(state))) | |
| 722 .WillOnce( | |
| 723 DoAll( | |
| 724 InvokeWithoutArgs( | |
| 725 CreateFunctor(&QuitMessageLoop, proxy.get())), | |
| 726 Return(bytes_per_packet))); | |
| 727 | |
| 728 aos->Start(&source); | |
| 729 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | |
| 730 TestTimeouts::action_timeout()); | |
| 731 loop.Run(); | |
| 732 aos->Stop(); | |
| 733 aos->Close(); | |
| 734 } | |
| 735 | |
| 736 // Verify that we can open and start the output stream in exclusive mode at | |
| 737 // the lowest possible delay at 44.1kHz. | |
| 738 TEST(WinAudioOutputTest, | |
| 739 WASAPIAudioOutputStreamTestExclusiveModeMinBufferSizeAt44kHzSampleRate) { | |
| 740 if (!ExclusiveModeIsEnabled()) | |
|
scherkus (not reviewing)
2012/06/27 04:20:30
fix indent
henrika (OOO until Aug 14)
2012/06/27 11:26:07
Done.
| |
| 741 return; | |
| 742 | |
| 743 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | |
| 744 if (!CanRunAudioTests(audio_manager.get())) | |
| 745 return; | |
| 746 | |
| 747 MessageLoopForUI loop; | |
| 748 scoped_refptr<base::MessageLoopProxy> proxy(loop.message_loop_proxy()); | |
| 749 | |
| 750 MockAudioSourceCallback source; | |
| 751 | |
| 752 // Create exclusive-mode WASAPI output stream which plays out in stereo | |
| 753 // using the minimum buffer size at 48kHz sample rate. | |
| 754 AudioOutputStreamWrapper aosw(audio_manager.get()); | |
| 755 AudioOutputStream* aos = aosw.Create(44100, 160); | |
| 756 EXPECT_TRUE(aos->Open()); | |
| 757 | |
| 758 // Derive the expected size in bytes of each packet. | |
| 759 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | |
| 760 (aosw.bits_per_sample() / 8); | |
| 761 | |
| 762 // Set up expected minimum delay estimation. | |
| 763 AudioBuffersState state(0, bytes_per_packet); | |
| 764 | |
| 765 // Wait for the first callback and verify its parameters. | |
| 766 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet, | |
| 767 HasValidDelay(state))) | |
| 768 .WillOnce( | |
| 769 DoAll( | |
| 770 InvokeWithoutArgs( | |
| 771 CreateFunctor(&QuitMessageLoop, proxy.get())), | |
| 772 Return(bytes_per_packet))); | |
| 773 | |
| 774 aos->Start(&source); | |
| 775 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | |
| 776 TestTimeouts::action_timeout()); | |
| 777 loop.Run(); | |
| 778 aos->Stop(); | |
| 779 aos->Close(); | |
| 780 } | |
| 781 | |
| 565 } // namespace media | 782 } // namespace media |
| OLD | NEW |