| Index: media/audio/win/audio_low_latency_output_win_unittest.cc
|
| diff --git a/media/audio/win/audio_low_latency_output_win_unittest.cc b/media/audio/win/audio_low_latency_output_win_unittest.cc
|
| index f764834571199c012b7fe65aad362ae2f742dbb9..3ab9268cc58a642489abc4b176b591a1bd38703c 100644
|
| --- a/media/audio/win/audio_low_latency_output_win_unittest.cc
|
| +++ b/media/audio/win/audio_low_latency_output_win_unittest.cc
|
| @@ -41,7 +41,7 @@ namespace media {
|
| static const char kSpeechFile_16b_s_48k[] = "speech_16b_stereo_48kHz.raw";
|
| static const char kSpeechFile_16b_s_44k[] = "speech_16b_stereo_44kHz.raw";
|
| static const size_t kFileDurationMs = 20000;
|
| -static const size_t kNumFileSegments = 1;
|
| +static const size_t kNumFileSegments = 2;
|
|
|
| static const size_t kMaxDeltaSamples = 1000;
|
| static const char* kDeltaTimeMsFileName = "delta_times_ms.txt";
|
| @@ -53,6 +53,12 @@ MATCHER_P(HasValidDelay, value, "") {
|
| return arg.hardware_delay_bytes > value.hardware_delay_bytes;
|
| }
|
|
|
| +// Used to terminate a loop from a different thread than the loop belongs to.
|
| +// |loop| should be a MessageLoopProxy.
|
| +ACTION_P(QuitLoop, loop) {
|
| + loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
|
| +}
|
| +
|
| class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback {
|
| public:
|
| MOCK_METHOD3(OnMoreData, uint32(uint8* dest,
|
| @@ -138,6 +144,11 @@ class ReadFromFileAudioSource : public AudioOutputStream::AudioSourceCallback {
|
| size_t elements_to_write_;
|
| };
|
|
|
| +static bool ExclusiveModeIsEnabled() {
|
| + return (WASAPIAudioOutputStream::GetShareMode() ==
|
| + AUDCLNT_SHAREMODE_EXCLUSIVE);
|
| +}
|
| +
|
| // Convenience method which ensures that we are not running on the build
|
| // bots and that at least one valid output device can be found. We also
|
| // verify that we are not running on XP since the low-latency (WASAPI-
|
| @@ -186,6 +197,14 @@ class AudioOutputStreamWrapper {
|
| }
|
|
|
| // Creates AudioOutputStream object using non-default parameters where the
|
| + // sample rate and frame size are modified.
|
| + AudioOutputStream* Create(int sample_rate, int samples_per_packet) {
|
| + sample_rate_ = sample_rate;
|
| + samples_per_packet_ = samples_per_packet;
|
| + return CreateOutputStream();
|
| + }
|
| +
|
| + // Creates AudioOutputStream object using non-default parameters where the
|
| // channel layout is modified.
|
| AudioOutputStream* Create(ChannelLayout channel_layout) {
|
| channel_layout_ = channel_layout;
|
| @@ -224,18 +243,16 @@ static AudioOutputStream* CreateDefaultAudioOutputStream(
|
| return aos;
|
| }
|
|
|
| -static void QuitMessageLoop(base::MessageLoopProxy* proxy) {
|
| - proxy->PostTask(FROM_HERE, MessageLoop::QuitClosure());
|
| -}
|
| -
|
| // Verify that we can retrieve the current hardware/mixing sample rate
|
| // for all supported device roles. The ERole enumeration defines constants
|
| // that indicate the role that the system/user has assigned to an audio
|
| // endpoint device.
|
| // TODO(henrika): modify this test when we support full device enumeration.
|
| TEST(WinAudioOutputTest, WASAPIAudioOutputStreamTestHardwareSampleRate) {
|
| + // Skip this test in exclusive mode since the resulting rate is only utilized
|
| + // for shared mode streams.
|
| scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
|
| - if (!CanRunAudioTests(audio_manager.get()))
|
| + if (!CanRunAudioTests(audio_manager.get()) || ExclusiveModeIsEnabled())
|
| return;
|
|
|
| ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
|
| @@ -389,8 +406,6 @@ TEST(WinAudioOutputTest, WASAPIAudioOutputStreamTestPacketSizeInMilliseconds) {
|
| return;
|
|
|
| MessageLoopForUI loop;
|
| - scoped_refptr<base::MessageLoopProxy> proxy(loop.message_loop_proxy());
|
| -
|
| MockAudioSourceCallback source;
|
|
|
| // Create default WASAPI output stream which plays out in stereo using
|
| @@ -409,11 +424,9 @@ TEST(WinAudioOutputTest, WASAPIAudioOutputStreamTestPacketSizeInMilliseconds) {
|
| // Wait for the first callback and verify its parameters.
|
| EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet,
|
| HasValidDelay(state)))
|
| - .WillOnce(
|
| - DoAll(
|
| - InvokeWithoutArgs(
|
| - CreateFunctor(&QuitMessageLoop, proxy.get())),
|
| - Return(bytes_per_packet)));
|
| + .WillOnce(DoAll(
|
| + QuitLoop(loop.message_loop_proxy()),
|
| + Return(bytes_per_packet)));
|
|
|
| aos->Start(&source);
|
| loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
|
| @@ -431,8 +444,6 @@ TEST(WinAudioOutputTest, WASAPIAudioOutputStreamTestPacketSizeInSamples) {
|
| return;
|
|
|
| MessageLoopForUI loop;
|
| - scoped_refptr<base::MessageLoopProxy> proxy(loop.message_loop_proxy());
|
| -
|
| MockAudioSourceCallback source;
|
|
|
| // Create default WASAPI output stream which plays out in stereo using
|
| @@ -448,14 +459,13 @@ TEST(WinAudioOutputTest, WASAPIAudioOutputStreamTestPacketSizeInSamples) {
|
| // Set up expected minimum delay estimation.
|
| AudioBuffersState state(0, bytes_per_packet);
|
|
|
| - // Wait for the first callback and verify its parameters.
|
| + // Ensure that callbacks start correctly.
|
| EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet,
|
| HasValidDelay(state)))
|
| - .WillOnce(
|
| - DoAll(
|
| - InvokeWithoutArgs(
|
| - CreateFunctor(&QuitMessageLoop, proxy.get())),
|
| - Return(bytes_per_packet)));
|
| + .WillOnce(DoAll(
|
| + QuitLoop(loop.message_loop_proxy()),
|
| + Return(bytes_per_packet)))
|
| + .WillRepeatedly(Return(bytes_per_packet));
|
|
|
| aos->Start(&source);
|
| loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
|
| @@ -471,8 +481,6 @@ TEST(WinAudioOutputTest, WASAPIAudioOutputStreamTestMono) {
|
| return;
|
|
|
| MessageLoopForUI loop;
|
| - scoped_refptr<base::MessageLoopProxy> proxy(loop.message_loop_proxy());
|
| -
|
| MockAudioSourceCallback source;
|
|
|
| // Create default WASAPI output stream which plays out in *mono* using
|
| @@ -497,11 +505,10 @@ TEST(WinAudioOutputTest, WASAPIAudioOutputStreamTestMono) {
|
|
|
| EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet,
|
| HasValidDelay(state)))
|
| - .WillOnce(
|
| - DoAll(
|
| - InvokeWithoutArgs(
|
| - CreateFunctor(&QuitMessageLoop, proxy.get())),
|
| - Return(bytes_per_packet)));
|
| + .WillOnce(DoAll(
|
| + QuitLoop(loop.message_loop_proxy()),
|
| + Return(bytes_per_packet)))
|
| + .WillRepeatedly(Return(bytes_per_packet));
|
|
|
| aos->Start(&source);
|
| loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
|
| @@ -562,4 +569,199 @@ TEST(WinAudioOutputTest, DISABLED_WASAPIAudioOutputStreamReadFromFile) {
|
| aos->Close();
|
| }
|
|
|
| +// Verify that we can open the output stream in exclusive mode using a
|
| +// certain set of audio parameters and a sample rate of 48kHz.
|
| +// The expected outcomes of each setting in this test has been derived
|
| +// manually using log outputs (--v=1).
|
| +TEST(WinAudioOutputTest, WASAPIExclusiveModeBufferSizesAt48kHz) {
|
| + if (!ExclusiveModeIsEnabled())
|
| + return;
|
| +
|
| + scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
|
| + if (!CanRunAudioTests(audio_manager.get()))
|
| + return;
|
| +
|
| + AudioOutputStreamWrapper aosw(audio_manager.get());
|
| +
|
| + // 10ms @ 48kHz shall work.
|
| + // Note that, this is the same size as we can use for shared-mode streaming
|
| + // but here the endpoint buffer delay is only 10ms instead of 20ms.
|
| + AudioOutputStream* aos = aosw.Create(48000, 480);
|
| + EXPECT_TRUE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 5ms @ 48kHz does not work due to misalignment.
|
| + // This test will propose an aligned buffer size of 5.3333ms.
|
| + // Note that we must call Close() even is Open() fails since Close() also
|
| + // deletes the object and we want to create a new object in the next test.
|
| + aos = aosw.Create(48000, 240);
|
| + EXPECT_FALSE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 5.3333ms @ 48kHz should work (see test above).
|
| + aos = aosw.Create(48000, 256);
|
| + EXPECT_TRUE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 2.6667ms is smaller than the minimum supported size (=3ms).
|
| + aos = aosw.Create(48000, 128);
|
| + EXPECT_FALSE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 3ms does not correspond to an aligned buffer size.
|
| + // This test will propose an aligned buffer size of 3.3333ms.
|
| + aos = aosw.Create(48000, 144);
|
| + EXPECT_FALSE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 3.3333ms @ 48kHz <=> smallest possible buffer size we can use.
|
| + aos = aosw.Create(48000, 160);
|
| + EXPECT_TRUE(aos->Open());
|
| + aos->Close();
|
| +}
|
| +
|
| +// Verify that we can open the output stream in exclusive mode using a
|
| +// certain set of audio parameters and a sample rate of 44.1kHz.
|
| +// The expected outcomes of each setting in this test has been derived
|
| +// manually using log outputs (--v=1).
|
| +TEST(WinAudioOutputTest, WASAPIExclusiveModeBufferSizesAt44kHz) {
|
| + if (!ExclusiveModeIsEnabled())
|
| + return;
|
| +
|
| + scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
|
| + if (!CanRunAudioTests(audio_manager.get()))
|
| + return;
|
| +
|
| + AudioOutputStreamWrapper aosw(audio_manager.get());
|
| +
|
| + // 10ms @ 44.1kHz does not work due to misalignment.
|
| + // This test will propose an aligned buffer size of 10.1587ms.
|
| + AudioOutputStream* aos = aosw.Create(44100, 441);
|
| + EXPECT_FALSE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 10.1587ms @ 44.1kHz shall work (see test above).
|
| + aos = aosw.Create(44100, 448);
|
| + EXPECT_TRUE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 5.8050ms @ 44.1 should work.
|
| + aos = aosw.Create(44100, 256);
|
| + EXPECT_TRUE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 4.9887ms @ 44.1kHz does not work to misalignment.
|
| + // This test will propose an aligned buffer size of 5.0794ms.
|
| + // Note that we must call Close() even is Open() fails since Close() also
|
| + // deletes the object and we want to create a new object in the next test.
|
| + aos = aosw.Create(44100, 220);
|
| + EXPECT_FALSE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 5.0794ms @ 44.1kHz shall work (see test above).
|
| + aos = aosw.Create(44100, 224);
|
| + EXPECT_TRUE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 2.9025ms is smaller than the minimum supported size (=3ms).
|
| + aos = aosw.Create(44100, 132);
|
| + EXPECT_FALSE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 3.01587ms is larger than the minimum size but is not aligned.
|
| + // This test will propose an aligned buffer size of 3.6281ms.
|
| + aos = aosw.Create(44100, 133);
|
| + EXPECT_FALSE(aos->Open());
|
| + aos->Close();
|
| +
|
| + // 3.6281ms @ 44.1kHz <=> smallest possible buffer size we can use.
|
| + aos = aosw.Create(44100, 160);
|
| + EXPECT_TRUE(aos->Open());
|
| + aos->Close();
|
| +}
|
| +
|
| +// Verify that we can open and start the output stream in exclusive mode at
|
| +// the lowest possible delay at 48kHz.
|
| +TEST(WinAudioOutputTest, WASAPIExclusiveModeMinBufferSizeAt48kHz) {
|
| + if (!ExclusiveModeIsEnabled())
|
| + return;
|
| +
|
| + scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
|
| + if (!CanRunAudioTests(audio_manager.get()))
|
| + return;
|
| +
|
| + MessageLoopForUI loop;
|
| + MockAudioSourceCallback source;
|
| +
|
| + // Create exclusive-mode WASAPI output stream which plays out in stereo
|
| + // using the minimum buffer size at 48kHz sample rate.
|
| + AudioOutputStreamWrapper aosw(audio_manager.get());
|
| + AudioOutputStream* aos = aosw.Create(48000, 160);
|
| + EXPECT_TRUE(aos->Open());
|
| +
|
| + // Derive the expected size in bytes of each packet.
|
| + uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() *
|
| + (aosw.bits_per_sample() / 8);
|
| +
|
| + // Set up expected minimum delay estimation.
|
| + AudioBuffersState state(0, bytes_per_packet);
|
| +
|
| + // Wait for the first callback and verify its parameters.
|
| + EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet,
|
| + HasValidDelay(state)))
|
| + .WillOnce(DoAll(
|
| + QuitLoop(loop.message_loop_proxy()),
|
| + Return(bytes_per_packet)))
|
| + .WillRepeatedly(Return(bytes_per_packet));
|
| +
|
| + aos->Start(&source);
|
| + loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
|
| + TestTimeouts::action_timeout());
|
| + loop.Run();
|
| + aos->Stop();
|
| + aos->Close();
|
| +}
|
| +
|
| +// Verify that we can open and start the output stream in exclusive mode at
|
| +// the lowest possible delay at 44.1kHz.
|
| +TEST(WinAudioOutputTest, WASAPIExclusiveModeMinBufferSizeAt44kHz) {
|
| + if (!ExclusiveModeIsEnabled())
|
| + return;
|
| +
|
| + scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
|
| + if (!CanRunAudioTests(audio_manager.get()))
|
| + return;
|
| +
|
| + MessageLoopForUI loop;
|
| + MockAudioSourceCallback source;
|
| +
|
| + // Create exclusive-mode WASAPI output stream which plays out in stereo
|
| + // using the minimum buffer size at 44.1kHz sample rate.
|
| + AudioOutputStreamWrapper aosw(audio_manager.get());
|
| + AudioOutputStream* aos = aosw.Create(44100, 160);
|
| + EXPECT_TRUE(aos->Open());
|
| +
|
| + // Derive the expected size in bytes of each packet.
|
| + uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() *
|
| + (aosw.bits_per_sample() / 8);
|
| +
|
| + // Set up expected minimum delay estimation.
|
| + AudioBuffersState state(0, bytes_per_packet);
|
| +
|
| + // Wait for the first callback and verify its parameters.
|
| + EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet,
|
| + HasValidDelay(state)))
|
| + .WillOnce(DoAll(
|
| + QuitLoop(loop.message_loop_proxy()),
|
| + Return(bytes_per_packet)))
|
| + .WillRepeatedly(Return(bytes_per_packet));
|
| +
|
| + aos->Start(&source);
|
| + loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
|
| + TestTimeouts::action_timeout());
|
| + loop.Run();
|
| + aos->Stop();
|
| + aos->Close();
|
| +}
|
| +
|
| } // namespace media
|
|
|