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

Side by Side Diff: media/audio/win/audio_low_latency_output_win_unittest.cc

Issue 10575017: Adding experimental exclusive-mode streaming to WASAPIAudioOutputStream (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Changes based on review comments by Chris Created 8 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/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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698