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_; } |
199 int samples_per_packet() const { return samples_per_packet_; } | 214 int samples_per_packet() const { return samples_per_packet_; } |
200 | 215 |
201 private: | 216 private: |
202 AudioOutputStream* CreateOutputStream() { | 217 AudioOutputStream* CreateOutputStream() { |
203 AudioOutputStream* aos = audio_man_->MakeAudioOutputStream( | 218 AudioOutputStream* aos = audio_man_->MakeAudioOutputStream( |
scherkus (not reviewing)
2012/06/28 00:04:41
if you change this to create a WASAPIAudioOutputSt
henrika (OOO until Aug 14)
2012/07/25 11:18:22
I explained this in a separate e-mail discussion b
| |
204 AudioParameters(format_, channel_layout_, sample_rate_, | 219 AudioParameters(format_, channel_layout_, sample_rate_, |
205 bits_per_sample_, samples_per_packet_)); | 220 bits_per_sample_, samples_per_packet_)); |
206 EXPECT_TRUE(aos); | 221 EXPECT_TRUE(aos); |
207 return aos; | 222 return aos; |
208 } | 223 } |
209 | 224 |
210 ScopedCOMInitializer com_init_; | 225 ScopedCOMInitializer com_init_; |
211 AudioManager* audio_man_; | 226 AudioManager* audio_man_; |
212 AudioParameters::Format format_; | 227 AudioParameters::Format format_; |
213 ChannelLayout channel_layout_; | 228 ChannelLayout channel_layout_; |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
555 aos->Start(&file_source); | 570 aos->Start(&file_source); |
556 base::PlatformThread::Sleep( | 571 base::PlatformThread::Sleep( |
557 base::TimeDelta::FromMilliseconds(kFileDurationMs / kNumFileSegments)); | 572 base::TimeDelta::FromMilliseconds(kFileDurationMs / kNumFileSegments)); |
558 aos->Stop(); | 573 aos->Stop(); |
559 } | 574 } |
560 | 575 |
561 LOG(INFO) << ">> File playout has stopped."; | 576 LOG(INFO) << ">> File playout has stopped."; |
562 aos->Close(); | 577 aos->Close(); |
563 } | 578 } |
564 | 579 |
580 // Verify that we can open the output stream in exclusive mode using a | |
581 // certain set of audio parameters and a sample rate of 48kHz. | |
582 // The expected outcomes of each setting in this test has been derived | |
583 // manually using log outputs (--v=1). | |
584 TEST(WinAudioOutputTest, | |
585 WASAPIAudioOutputStreamTestExclusiveModeBufferSizesAt48kHzSampleRate) { | |
586 if (!ExclusiveModeIsEnabled()) | |
587 return; | |
588 | |
589 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | |
590 if (!CanRunAudioTests(audio_manager.get())) | |
591 return; | |
592 | |
593 AudioOutputStreamWrapper aosw(audio_manager.get()); | |
594 | |
595 // 10ms @ 48kHz shall work. | |
596 // Note that, this is the same size as we can use for shared-mode streaming | |
597 // but here the endpoint buffer delay is only 10ms instead of 20ms. | |
598 AudioOutputStream* aos = aosw.Create(48000, 480); | |
599 EXPECT_TRUE(aos->Open()); | |
600 aos->Close(); | |
601 | |
602 // 5ms @ 48kHz does not work to misalignment. | |
603 // This test will propose an aligned buffer size of 5.3333ms. | |
604 aos = aosw.Create(48000, 240); | |
605 EXPECT_FALSE(aos->Open()); | |
606 aos->Close(); | |
607 | |
608 // 5.3333ms @ 48kHz shall work (see test above). | |
609 aos = aosw.Create(48000, 256); | |
610 EXPECT_TRUE(aos->Open()); | |
611 aos->Close(); | |
612 | |
613 // 2.6667ms is smaller than the minimum supported size (=3ms). | |
614 aos = aosw.Create(48000, 128); | |
615 EXPECT_FALSE(aos->Open()); | |
616 aos->Close(); | |
617 | |
618 // 3ms does not correspond to an aligned buffer size. | |
619 // This test will propose an aligned buffer size of 3.3333ms. | |
620 aos = aosw.Create(48000, 144); | |
621 EXPECT_FALSE(aos->Open()); | |
622 aos->Close(); | |
623 | |
624 // 3.3333ms @ 48kHz <=> smallest possible buffer size we can use. | |
625 aos = aosw.Create(48000, 160); | |
626 EXPECT_TRUE(aos->Open()); | |
627 aos->Close(); | |
628 } | |
629 | |
630 // Verify that we can open the output stream in exclusive mode using a | |
631 // certain set of audio parameters and a sample rate of 44.1kHz. | |
632 // The expected outcomes of each setting in this test has been derived | |
633 // manually using log outputs (--v=1). | |
634 TEST(WinAudioOutputTest, | |
635 WASAPIAudioOutputStreamTestExclusiveModeBufferSizesAt44kHzSampleRate) { | |
636 if (!ExclusiveModeIsEnabled()) | |
637 return; | |
638 | |
639 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | |
640 if (!CanRunAudioTests(audio_manager.get())) | |
641 return; | |
642 | |
643 AudioOutputStreamWrapper aosw(audio_manager.get()); | |
644 | |
645 // 10ms @ 44.1kHz does not work due to misalignment. | |
646 // This test will propose an aligned buffer size of 10.1587ms. | |
647 AudioOutputStream* aos = aosw.Create(44100, 441); | |
648 EXPECT_FALSE(aos->Open()); | |
649 aos->Close(); | |
650 | |
651 // 10.1587ms @ 44.1kHz shall work (see test above). | |
652 aos = aosw.Create(44100, 448); | |
653 EXPECT_TRUE(aos->Open()); | |
654 aos->Close(); | |
655 | |
656 // 5.8050ms @ 44.1 shall work. | |
657 aos = aosw.Create(44100, 256); | |
658 EXPECT_TRUE(aos->Open()); | |
659 aos->Close(); | |
660 | |
661 // 4.9887ms @ 44.1kHz does not work to misalignment. | |
662 // This test will propose an aligned buffer size of 5.0794ms. | |
663 aos = aosw.Create(44100, 220); | |
664 EXPECT_FALSE(aos->Open()); | |
665 aos->Close(); | |
666 | |
667 // 5.0794ms @ 44.1kHz shall work (see test above). | |
668 aos = aosw.Create(44100, 224); | |
669 EXPECT_TRUE(aos->Open()); | |
670 aos->Close(); | |
671 | |
672 // 2.9025ms is smaller than the minimum supported size (=3ms). | |
673 aos = aosw.Create(44100, 132); | |
674 EXPECT_FALSE(aos->Open()); | |
675 aos->Close(); | |
676 | |
677 // 3.01587ms is larger than the minimum size but is not aligned. | |
678 // This test will propose an aligned buffer size of 3.6281ms. | |
679 aos = aosw.Create(44100, 133); | |
680 EXPECT_FALSE(aos->Open()); | |
681 aos->Close(); | |
682 | |
683 // 3.6281ms @ 44.1kHz <=> smallest possible buffer size we can use. | |
684 aos = aosw.Create(44100, 160); | |
685 EXPECT_TRUE(aos->Open()); | |
686 aos->Close(); | |
687 } | |
688 | |
689 // Verify that we can open and start the output stream in exclusive mode at | |
690 // the lowest possible delay at 48kHz. | |
691 TEST(WinAudioOutputTest, | |
692 WASAPIAudioOutputStreamTestExclusiveModeMinBufferSizeAt48kHzSampleRate) { | |
693 if (!ExclusiveModeIsEnabled()) | |
694 return; | |
695 | |
696 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | |
697 if (!CanRunAudioTests(audio_manager.get())) | |
698 return; | |
699 | |
700 MessageLoopForUI loop; | |
701 scoped_refptr<base::MessageLoopProxy> proxy(loop.message_loop_proxy()); | |
702 | |
703 MockAudioSourceCallback source; | |
704 | |
705 // Create exclusive-mode WASAPI output stream which plays out in stereo | |
706 // using the minimum buffer size at 48kHz sample rate. | |
707 AudioOutputStreamWrapper aosw(audio_manager.get()); | |
708 AudioOutputStream* aos = aosw.Create(48000, 160); | |
709 EXPECT_TRUE(aos->Open()); | |
710 | |
711 // Derive the expected size in bytes of each packet. | |
712 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | |
713 (aosw.bits_per_sample() / 8); | |
714 | |
715 // Set up expected minimum delay estimation. | |
716 AudioBuffersState state(0, bytes_per_packet); | |
717 | |
718 // Wait for the first callback and verify its parameters. | |
719 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet, | |
720 HasValidDelay(state))) | |
721 .WillOnce( | |
722 DoAll( | |
723 InvokeWithoutArgs( | |
724 CreateFunctor(&QuitMessageLoop, proxy.get())), | |
725 Return(bytes_per_packet))); | |
726 | |
727 aos->Start(&source); | |
728 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | |
729 TestTimeouts::action_timeout()); | |
730 loop.Run(); | |
731 aos->Stop(); | |
732 aos->Close(); | |
733 } | |
734 | |
735 // Verify that we can open and start the output stream in exclusive mode at | |
736 // the lowest possible delay at 44.1kHz. | |
737 TEST(WinAudioOutputTest, | |
738 WASAPIAudioOutputStreamTestExclusiveModeMinBufferSizeAt44kHzSampleRate) { | |
739 if (!ExclusiveModeIsEnabled()) | |
740 return; | |
741 | |
742 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); | |
743 if (!CanRunAudioTests(audio_manager.get())) | |
744 return; | |
745 | |
746 MessageLoopForUI loop; | |
747 scoped_refptr<base::MessageLoopProxy> proxy(loop.message_loop_proxy()); | |
748 | |
749 MockAudioSourceCallback source; | |
750 | |
751 // Create exclusive-mode WASAPI output stream which plays out in stereo | |
752 // using the minimum buffer size at 48kHz sample rate. | |
753 AudioOutputStreamWrapper aosw(audio_manager.get()); | |
754 AudioOutputStream* aos = aosw.Create(44100, 160); | |
755 EXPECT_TRUE(aos->Open()); | |
756 | |
757 // Derive the expected size in bytes of each packet. | |
758 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | |
759 (aosw.bits_per_sample() / 8); | |
760 | |
761 // Set up expected minimum delay estimation. | |
762 AudioBuffersState state(0, bytes_per_packet); | |
763 | |
764 // Wait for the first callback and verify its parameters. | |
765 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet, | |
766 HasValidDelay(state))) | |
767 .WillOnce( | |
768 DoAll( | |
769 InvokeWithoutArgs( | |
770 CreateFunctor(&QuitMessageLoop, proxy.get())), | |
771 Return(bytes_per_packet))); | |
772 | |
773 aos->Start(&source); | |
774 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | |
775 TestTimeouts::action_timeout()); | |
776 loop.Run(); | |
777 aos->Stop(); | |
778 aos->Close(); | |
779 } | |
780 | |
565 } // namespace media | 781 } // namespace media |
OLD | NEW |