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

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 by Chris and Andrew Created 8 years, 5 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_; }
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698