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; |
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()) |
| 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()) |
| 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()) |
| 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 |