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