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
3 // found in the LICENSE file.
4 
5 #include "media/audio/win/audio_low_latency_output_win.h"
6 
7 #include <mmsystem.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <windows.h>
11 
12 #include <memory>
13 
14 #include "base/environment.h"
15 #include "base/files/file_util.h"
16 #include "base/logging.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/path_service.h"
19 #include "base/run_loop.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/test/task_environment.h"
22 #include "base/test/test_timeouts.h"
23 #include "base/threading/thread_task_runner_handle.h"
24 #include "base/time/time.h"
25 #include "base/win/scoped_com_initializer.h"
26 #include "media/audio/audio_device_description.h"
27 #include "media/audio/audio_device_info_accessor_for_tests.h"
28 #include "media/audio/audio_io.h"
29 #include "media/audio/audio_manager.h"
30 #include "media/audio/audio_unittest_util.h"
31 #include "media/audio/mock_audio_source_callback.h"
32 #include "media/audio/test_audio_thread.h"
33 #include "media/audio/win/core_audio_util_win.h"
34 #include "media/base/decoder_buffer.h"
35 #include "media/base/seekable_buffer.h"
36 #include "media/base/test_data_util.h"
37 #include "testing/gmock/include/gmock/gmock.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 
40 using ::base::ThreadTaskRunnerHandle;
41 using ::testing::_;
42 using ::testing::DoAll;
43 using ::testing::NotNull;
44 using ::testing::Return;
45 
46 namespace media {
47 
48 static const int kBitsPerSample = 16;
49 static const size_t kMaxDeltaSamples = 1000;
50 static const char kDeltaTimeMsFileName[] = "delta_times_ms.txt";
51 
52 MATCHER_P(HasValidDelay, value, "") {
53   // It is difficult to come up with a perfect test condition for the delay
54   // estimation. For now, verify that the produced output delay is always
55   // larger than the selected buffer size.
56   return arg >= value;
57 }
58 
59 // Used to terminate a loop from a different thread than the loop belongs to.
60 // |task_runner| should be a SingleThreadTaskRunner.
ACTION_P(QuitLoop,task_runner)61 ACTION_P(QuitLoop, task_runner) {
62   task_runner->PostTask(FROM_HERE,
63                         base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
64 }
65 
66 // This audio source implementation should be used for manual tests only since
67 // it takes about 20 seconds to play out a file.
68 class ReadFromFileAudioSource : public AudioOutputStream::AudioSourceCallback {
69  public:
ReadFromFileAudioSource(const std::string & name)70   explicit ReadFromFileAudioSource(const std::string& name)
71       : pos_(0),
72         previous_call_time_(base::TimeTicks::Now()),
73         text_file_(nullptr),
74         elements_to_write_(0) {
75     // Reads a test file from media/test/data directory.
76     file_ = ReadTestDataFile(name);
77 
78     // Creates an array that will store delta times between callbacks.
79     // The content of this array will be written to a text file at
80     // destruction and can then be used for off-line analysis of the exact
81     // timing of callbacks. The text file will be stored in media/test/data.
82     delta_times_.reset(new int[kMaxDeltaSamples]);
83   }
84 
~ReadFromFileAudioSource()85   ~ReadFromFileAudioSource() override {
86     // Get complete file path to output file in directory containing
87     // media_unittests.exe.
88     base::FilePath file_name;
89     EXPECT_TRUE(base::PathService::Get(base::DIR_EXE, &file_name));
90     file_name = file_name.AppendASCII(kDeltaTimeMsFileName);
91 
92     EXPECT_TRUE(!text_file_);
93     text_file_ = base::OpenFile(file_name, "wt");
94     DLOG_IF(ERROR, !text_file_) << "Failed to open log file.";
95 
96     // Write the array which contains delta times to a text file.
97     size_t elements_written = 0;
98     while (elements_written < elements_to_write_) {
99       fprintf(text_file_, "%d\n", delta_times_[elements_written]);
100       ++elements_written;
101     }
102 
103     base::CloseFile(text_file_);
104   }
105 
106   // AudioOutputStream::AudioSourceCallback implementation.
OnMoreData(base::TimeDelta,base::TimeTicks,int,AudioBus * dest)107   int OnMoreData(base::TimeDelta /* delay */,
108                  base::TimeTicks /* delay_timestamp */,
109                  int /* prior_frames_skipped */,
110                  AudioBus* dest) override {
111     // Store time difference between two successive callbacks in an array.
112     // These values will be written to a file in the destructor.
113     const base::TimeTicks now_time = base::TimeTicks::Now();
114     const int diff = (now_time - previous_call_time_).InMilliseconds();
115     previous_call_time_ = now_time;
116     if (elements_to_write_ < kMaxDeltaSamples) {
117       delta_times_[elements_to_write_] = diff;
118       ++elements_to_write_;
119     }
120 
121     int max_size = dest->frames() * dest->channels() * kBitsPerSample / 8;
122 
123     // Use samples read from a data file and fill up the audio buffer
124     // provided to us in the callback.
125     if (pos_ + max_size > file_size())
126       max_size = file_size() - pos_;
127     int frames = max_size / (dest->channels() * kBitsPerSample / 8);
128     if (max_size) {
129       static_assert(kBitsPerSample == 16, "FromInterleaved expects 2 bytes.");
130       dest->FromInterleaved<SignedInt16SampleTypeTraits>(
131           reinterpret_cast<const int16_t*>(file_->data() + pos_), frames);
132       pos_ += max_size;
133     }
134     return frames;
135   }
136 
OnError(ErrorType type)137   void OnError(ErrorType type) override {}
138 
file_size()139   int file_size() { return file_->data_size(); }
140 
141  private:
142   scoped_refptr<DecoderBuffer> file_;
143   std::unique_ptr<int[]> delta_times_;
144   int pos_;
145   base::TimeTicks previous_call_time_;
146   FILE* text_file_;
147   size_t elements_to_write_;
148 };
149 
ExclusiveModeIsEnabled()150 static bool ExclusiveModeIsEnabled() {
151   return (WASAPIAudioOutputStream::GetShareMode() ==
152           AUDCLNT_SHAREMODE_EXCLUSIVE);
153 }
154 
HasCoreAudioAndOutputDevices(AudioManager * audio_man)155 static bool HasCoreAudioAndOutputDevices(AudioManager* audio_man) {
156   // The low-latency (WASAPI-based) version requires Windows Vista or higher.
157   // TODO(henrika): note that we use Wave today to query the number of
158   // existing output devices.
159   return CoreAudioUtil::IsSupported() &&
160          AudioDeviceInfoAccessorForTests(audio_man).HasAudioOutputDevices();
161 }
162 
163 // Convenience method which creates a default AudioOutputStream object but
164 // also allows the user to modify the default settings.
165 class AudioOutputStreamWrapper {
166  public:
AudioOutputStreamWrapper(AudioManager * audio_manager)167   explicit AudioOutputStreamWrapper(AudioManager* audio_manager)
168       : audio_man_(audio_manager),
169         format_(AudioParameters::AUDIO_PCM_LOW_LATENCY) {
170     AudioParameters preferred_params;
171     EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
172         AudioDeviceDescription::kDefaultDeviceId, true, &preferred_params)));
173     channels_ = preferred_params.channels();
174     channel_layout_ = preferred_params.channel_layout();
175     sample_rate_ = preferred_params.sample_rate();
176     samples_per_packet_ = preferred_params.frames_per_buffer();
177   }
178 
~AudioOutputStreamWrapper()179   ~AudioOutputStreamWrapper() {}
180 
181   // Creates AudioOutputStream object using default parameters.
Create()182   AudioOutputStream* Create() { return CreateOutputStream(); }
183 
184   // Creates AudioOutputStream object using non-default parameters where the
185   // frame size is modified.
Create(int samples_per_packet)186   AudioOutputStream* Create(int samples_per_packet) {
187     samples_per_packet_ = samples_per_packet;
188     return CreateOutputStream();
189   }
190 
191   // Creates AudioOutputStream object using non-default parameters where the
192   // sample rate and frame size are modified.
Create(int sample_rate,int samples_per_packet)193   AudioOutputStream* Create(int sample_rate, int samples_per_packet) {
194     sample_rate_ = sample_rate;
195     samples_per_packet_ = samples_per_packet;
196     return CreateOutputStream();
197   }
198 
format() const199   AudioParameters::Format format() const { return format_; }
channels() const200   int channels() const { return channels_; }
sample_rate() const201   int sample_rate() const { return sample_rate_; }
samples_per_packet() const202   int samples_per_packet() const { return samples_per_packet_; }
203 
204  private:
CreateOutputStream()205   AudioOutputStream* CreateOutputStream() {
206     AudioParameters params(format_, channel_layout_, sample_rate_,
207                            samples_per_packet_);
208     if (channel_layout_ == CHANNEL_LAYOUT_DISCRETE) {
209       params.set_channels_for_discrete(channels_);
210     }
211     DVLOG(1) << params.AsHumanReadableString();
212     AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(
213         params, std::string(), AudioManager::LogCallback());
214     EXPECT_TRUE(aos);
215     return aos;
216   }
217 
218   AudioManager* audio_man_;
219   AudioParameters::Format format_;
220   int channels_;
221   ChannelLayout channel_layout_;
222   int sample_rate_;
223   int samples_per_packet_;
224 };
225 
226 // Convenience method which creates a default AudioOutputStream object.
CreateDefaultAudioOutputStream(AudioManager * audio_manager)227 static AudioOutputStream* CreateDefaultAudioOutputStream(
228     AudioManager* audio_manager) {
229   AudioOutputStreamWrapper aosw(audio_manager);
230   AudioOutputStream* aos = aosw.Create();
231   return aos;
232 }
233 
234 class WASAPIAudioOutputStreamTest : public ::testing::Test {
235  public:
WASAPIAudioOutputStreamTest()236   WASAPIAudioOutputStreamTest() {
237     audio_manager_ =
238         AudioManager::CreateForTesting(std::make_unique<TestAudioThread>());
239     base::RunLoop().RunUntilIdle();
240   }
~WASAPIAudioOutputStreamTest()241   ~WASAPIAudioOutputStreamTest() override { audio_manager_->Shutdown(); }
242 
243  protected:
244   base::test::SingleThreadTaskEnvironment task_environment_{
245       base::test::SingleThreadTaskEnvironment::MainThreadType::UI};
246   std::unique_ptr<AudioManager> audio_manager_;
247 };
248 
249 // Test Create(), Close() calling sequence.
TEST_F(WASAPIAudioOutputStreamTest,CreateAndClose)250 TEST_F(WASAPIAudioOutputStreamTest, CreateAndClose) {
251   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()));
252   AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get());
253   aos->Close();
254 }
255 
256 // Test Open(), Close() calling sequence.
TEST_F(WASAPIAudioOutputStreamTest,OpenAndClose)257 TEST_F(WASAPIAudioOutputStreamTest, OpenAndClose) {
258   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()));
259   AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get());
260   EXPECT_TRUE(aos->Open());
261   aos->Close();
262 }
263 
264 // Test Open(), Start(), Close() calling sequence.
TEST_F(WASAPIAudioOutputStreamTest,OpenStartAndClose)265 TEST_F(WASAPIAudioOutputStreamTest, OpenStartAndClose) {
266   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()));
267   AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get());
268   EXPECT_TRUE(aos->Open());
269   MockAudioSourceCallback source;
270   EXPECT_CALL(source, OnError(_)).Times(0);
271   aos->Start(&source);
272   aos->Close();
273 }
274 
275 // Test Open(), Start(), Stop(), Close() calling sequence.
TEST_F(WASAPIAudioOutputStreamTest,OpenStartStopAndClose)276 TEST_F(WASAPIAudioOutputStreamTest, OpenStartStopAndClose) {
277   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()));
278   AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get());
279   EXPECT_TRUE(aos->Open());
280   MockAudioSourceCallback source;
281   EXPECT_CALL(source, OnError(_)).Times(0);
282   aos->Start(&source);
283   aos->Stop();
284   aos->Close();
285 }
286 
287 // Test SetVolume(), GetVolume()
TEST_F(WASAPIAudioOutputStreamTest,Volume)288 TEST_F(WASAPIAudioOutputStreamTest, Volume) {
289   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()));
290   AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get());
291 
292   // Initial volume should be full volume (1.0).
293   double volume = 0.0;
294   aos->GetVolume(&volume);
295   EXPECT_EQ(1.0, volume);
296 
297   // Verify some valid volume settings.
298   aos->SetVolume(0.0);
299   aos->GetVolume(&volume);
300   EXPECT_EQ(0.0, volume);
301 
302   aos->SetVolume(0.5);
303   aos->GetVolume(&volume);
304   EXPECT_EQ(0.5, volume);
305 
306   aos->SetVolume(1.0);
307   aos->GetVolume(&volume);
308   EXPECT_EQ(1.0, volume);
309 
310   // Ensure that invalid volume setting have no effect.
311   aos->SetVolume(1.5);
312   aos->GetVolume(&volume);
313   EXPECT_EQ(1.0, volume);
314 
315   aos->SetVolume(-0.5);
316   aos->GetVolume(&volume);
317   EXPECT_EQ(1.0, volume);
318 
319   aos->Close();
320 }
321 
322 // Test some additional calling sequences.
TEST_F(WASAPIAudioOutputStreamTest,MiscCallingSequences)323 TEST_F(WASAPIAudioOutputStreamTest, MiscCallingSequences) {
324   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()));
325 
326   AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get());
327   WASAPIAudioOutputStream* waos = static_cast<WASAPIAudioOutputStream*>(aos);
328 
329   // Open(), Open() is a valid calling sequence (second call does nothing).
330   EXPECT_TRUE(aos->Open());
331   EXPECT_TRUE(aos->Open());
332 
333   MockAudioSourceCallback source;
334 
335   // Start(), Start() is a valid calling sequence (second call does nothing).
336   aos->Start(&source);
337   EXPECT_TRUE(waos->started());
338   aos->Start(&source);
339   EXPECT_TRUE(waos->started());
340 
341   // Stop(), Stop() is a valid calling sequence (second call does nothing).
342   aos->Stop();
343   EXPECT_FALSE(waos->started());
344   aos->Stop();
345   EXPECT_FALSE(waos->started());
346 
347   // Start(), Stop(), Start(), Stop().
348   aos->Start(&source);
349   EXPECT_TRUE(waos->started());
350   aos->Stop();
351   EXPECT_FALSE(waos->started());
352   aos->Start(&source);
353   EXPECT_TRUE(waos->started());
354   aos->Stop();
355   EXPECT_FALSE(waos->started());
356 
357   aos->Close();
358 }
359 
360 // Use preferred packet size and verify that rendering starts.
TEST_F(WASAPIAudioOutputStreamTest,ValidPacketSize)361 TEST_F(WASAPIAudioOutputStreamTest, ValidPacketSize) {
362   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()));
363 
364   MockAudioSourceCallback source;
365   // Create default WASAPI output stream which plays out in stereo using
366   // the shared mixing rate. The default buffer size is 10ms.
367   AudioOutputStreamWrapper aosw(audio_manager_.get());
368   AudioOutputStream* aos = aosw.Create();
369   EXPECT_TRUE(aos->Open());
370 
371   // Derive the expected duration of each packet.
372   base::TimeDelta packet_duration = base::TimeDelta::FromSecondsD(
373       static_cast<double>(aosw.samples_per_packet()) / aosw.sample_rate());
374 
375   // Wait for the first callback and verify its parameters.  Ignore any
376   // subsequent callbacks that might arrive.
377   EXPECT_CALL(source,
378               OnMoreData(HasValidDelay(packet_duration), _, 0, NotNull()))
379       .WillOnce(DoAll(QuitLoop(ThreadTaskRunnerHandle::Get()),
380                       Return(aosw.samples_per_packet())))
381       .WillRepeatedly(Return(0));
382 
383   aos->Start(&source);
384   ThreadTaskRunnerHandle::Get()->PostDelayedTask(
385       FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
386       TestTimeouts::action_timeout());
387   base::RunLoop().Run();
388   aos->Stop();
389   aos->Close();
390 }
391 
392 // Verify that we can open the output stream in exclusive mode using a
393 // certain set of audio parameters and a sample rate of 48kHz.
394 // The expected outcomes of each setting in this test has been derived
395 // manually using log outputs (--v=1).
396 // It's disabled by default because a flag is required to enable exclusive mode.
TEST_F(WASAPIAudioOutputStreamTest,DISABLED_ExclusiveModeBufferSizesAt48kHz)397 TEST_F(WASAPIAudioOutputStreamTest, DISABLED_ExclusiveModeBufferSizesAt48kHz) {
398   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) &&
399                           ExclusiveModeIsEnabled());
400 
401   AudioOutputStreamWrapper aosw(audio_manager_.get());
402 
403   // 10ms @ 48kHz shall work.
404   // Note that, this is the same size as we can use for shared-mode streaming
405   // but here the endpoint buffer delay is only 10ms instead of 20ms.
406   AudioOutputStream* aos = aosw.Create(48000, 480);
407   EXPECT_TRUE(aos->Open());
408   aos->Close();
409 
410   // 5ms @ 48kHz does not work due to misalignment.
411   // This test will propose an aligned buffer size of 5.3333ms.
412   // Note that we must call Close() even is Open() fails since Close() also
413   // deletes the object and we want to create a new object in the next test.
414   aos = aosw.Create(48000, 240);
415   EXPECT_FALSE(aos->Open());
416   aos->Close();
417 
418   // 5.3333ms @ 48kHz should work (see test above).
419   aos = aosw.Create(48000, 256);
420   EXPECT_TRUE(aos->Open());
421   aos->Close();
422 
423   // 2.6667ms is smaller than the minimum supported size (=3ms).
424   aos = aosw.Create(48000, 128);
425   EXPECT_FALSE(aos->Open());
426   aos->Close();
427 
428   // 3ms does not correspond to an aligned buffer size.
429   // This test will propose an aligned buffer size of 3.3333ms.
430   aos = aosw.Create(48000, 144);
431   EXPECT_FALSE(aos->Open());
432   aos->Close();
433 
434   // 3.3333ms @ 48kHz <=> smallest possible buffer size we can use.
435   aos = aosw.Create(48000, 160);
436   EXPECT_TRUE(aos->Open());
437   aos->Close();
438 }
439 
440 // Verify that we can open the output stream in exclusive mode using a
441 // certain set of audio parameters and a sample rate of 44.1kHz.
442 // The expected outcomes of each setting in this test has been derived
443 // manually using log outputs (--v=1).
444 // It's disabled by default because a flag is required to enable exclusive mode.
TEST_F(WASAPIAudioOutputStreamTest,DISABLED_ExclusiveModeBufferSizesAt44kHz)445 TEST_F(WASAPIAudioOutputStreamTest, DISABLED_ExclusiveModeBufferSizesAt44kHz) {
446   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) &&
447                           ExclusiveModeIsEnabled());
448 
449   AudioOutputStreamWrapper aosw(audio_manager_.get());
450 
451   // 10ms @ 44.1kHz does not work due to misalignment.
452   // This test will propose an aligned buffer size of 10.1587ms.
453   AudioOutputStream* aos = aosw.Create(44100, 441);
454   EXPECT_FALSE(aos->Open());
455   aos->Close();
456 
457   // 10.1587ms @ 44.1kHz shall work (see test above).
458   aos = aosw.Create(44100, 448);
459   EXPECT_TRUE(aos->Open());
460   aos->Close();
461 
462   // 5.8050ms @ 44.1 should work.
463   aos = aosw.Create(44100, 256);
464   EXPECT_TRUE(aos->Open());
465   aos->Close();
466 
467   // 4.9887ms @ 44.1kHz does not work to misalignment.
468   // This test will propose an aligned buffer size of 5.0794ms.
469   // Note that we must call Close() even is Open() fails since Close() also
470   // deletes the object and we want to create a new object in the next test.
471   aos = aosw.Create(44100, 220);
472   EXPECT_FALSE(aos->Open());
473   aos->Close();
474 
475   // 5.0794ms @ 44.1kHz shall work (see test above).
476   aos = aosw.Create(44100, 224);
477   EXPECT_TRUE(aos->Open());
478   aos->Close();
479 
480   // 2.9025ms is smaller than the minimum supported size (=3ms).
481   aos = aosw.Create(44100, 132);
482   EXPECT_FALSE(aos->Open());
483   aos->Close();
484 
485   // 3.01587ms is larger than the minimum size but is not aligned.
486   // This test will propose an aligned buffer size of 3.6281ms.
487   aos = aosw.Create(44100, 133);
488   EXPECT_FALSE(aos->Open());
489   aos->Close();
490 
491   // 3.6281ms @ 44.1kHz <=> smallest possible buffer size we can use.
492   aos = aosw.Create(44100, 160);
493   EXPECT_TRUE(aos->Open());
494   aos->Close();
495 }
496 
497 // Verify that we can open and start the output stream in exclusive mode at
498 // the lowest possible delay at 48kHz.
499 // It's disabled by default because a flag is required to enable exclusive mode.
TEST_F(WASAPIAudioOutputStreamTest,DISABLED_ExclusiveModeMinBufferSizeAt48kHz)500 TEST_F(WASAPIAudioOutputStreamTest,
501        DISABLED_ExclusiveModeMinBufferSizeAt48kHz) {
502   ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) &&
503                           ExclusiveModeIsEnabled());
504 
505   MockAudioSourceCallback source;
506   // Create exclusive-mode WASAPI output stream which plays out in stereo
507   // using the minimum buffer size at 48kHz sample rate.
508   AudioOutputStreamWrapper aosw(audio_manager_.get());
509   AudioOutputStream* aos = aosw.Create(48000, 160);
510   EXPECT_TRUE(aos->Open());
511 
512   // Derive the expected size in bytes of each packet.
513   base::TimeDelta packet_duration = base::TimeDelta::FromSecondsD(
514       static_cast<double>(aosw.samples_per_packet()) / aosw.sample_rate());
515 
516   // Wait for the first callback and verify its parameters.
517   EXPECT_CALL(source,
518               OnMoreData(HasValidDelay(packet_duration), _, 0, NotNull()))
519       .WillOnce(DoAll(QuitLoop(ThreadTaskRunnerHandle::Get()),
520                       Return(aosw.samples_per_packet())))
521       .WillRepeatedly(Return(aosw.samples_per_packet()));
522 
523   aos->Start(&source);
524   ThreadTaskRunnerHandle::Get()->PostDelayedTask(
525       FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
526       TestTimeouts::action_timeout());
527   base::RunLoop().Run();
528   aos->Stop();
529   aos->Close();
530 }
531 
532 // Verify that we can open and start the output stream in exclusive mode at
533 // the lowest possible delay at 44.1kHz.
534 // It's disabled by default because a flag is required to enable exclusive mode.
TEST_F(WASAPIAudioOutputStreamTest,DISABLED_ExclusiveModeMinBufferSizeAt44kHz)535 TEST_F(WASAPIAudioOutputStreamTest,
536        DISABLED_ExclusiveModeMinBufferSizeAt44kHz) {
537   ABORT_AUDIO_TEST_IF_NOT(ExclusiveModeIsEnabled());
538 
539   MockAudioSourceCallback source;
540   // Create exclusive-mode WASAPI output stream which plays out in stereo
541   // using the minimum buffer size at 44.1kHz sample rate.
542   AudioOutputStreamWrapper aosw(audio_manager_.get());
543   AudioOutputStream* aos = aosw.Create(44100, 160);
544   EXPECT_TRUE(aos->Open());
545 
546   // Derive the expected size in bytes of each packet.
547   base::TimeDelta packet_duration = base::TimeDelta::FromSecondsD(
548       static_cast<double>(aosw.samples_per_packet()) / aosw.sample_rate());
549 
550   // Wait for the first callback and verify its parameters.
551   EXPECT_CALL(source,
552               OnMoreData(HasValidDelay(packet_duration), _, 0, NotNull()))
553       .WillOnce(DoAll(QuitLoop(ThreadTaskRunnerHandle::Get()),
554                       Return(aosw.samples_per_packet())))
555       .WillRepeatedly(Return(aosw.samples_per_packet()));
556 
557   aos->Start(&source);
558   ThreadTaskRunnerHandle::Get()->PostDelayedTask(
559       FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
560       TestTimeouts::action_timeout());
561   base::RunLoop().Run();
562   aos->Stop();
563   aos->Close();
564 }
565 
566 }  // namespace media
567