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 <windows.h>
6 #include <mmsystem.h>
7
8 #include "base/basictypes.h"
9 #include "base/environment.h"
10 #include "base/files/file_util.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/path_service.h"
14 #include "base/test/test_timeouts.h"
15 #include "base/time/time.h"
16 #include "base/win/scoped_com_initializer.h"
17 #include "media/audio/audio_io.h"
18 #include "media/audio/audio_manager.h"
19 #include "media/audio/mock_audio_source_callback.h"
20 #include "media/audio/win/audio_low_latency_output_win.h"
21 #include "media/audio/win/core_audio_util_win.h"
22 #include "media/base/decoder_buffer.h"
23 #include "media/base/seekable_buffer.h"
24 #include "media/base/test_data_util.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gmock_mutant.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 using ::testing::_;
30 using ::testing::AnyNumber;
31 using ::testing::AtLeast;
32 using ::testing::Between;
33 using ::testing::CreateFunctor;
34 using ::testing::DoAll;
35 using ::testing::Gt;
36 using ::testing::InvokeWithoutArgs;
37 using ::testing::NotNull;
38 using ::testing::Return;
39 using base::win::ScopedCOMInitializer;
40
41 namespace media {
42
43 static const char kSpeechFile_16b_s_48k[] = "speech_16b_stereo_48kHz.raw";
44 static const char kSpeechFile_16b_s_44k[] = "speech_16b_stereo_44kHz.raw";
45 static const size_t kFileDurationMs = 20000;
46 static const size_t kNumFileSegments = 2;
47 static const int kBitsPerSample = 16;
48 static const size_t kMaxDeltaSamples = 1000;
49 static const char kDeltaTimeMsFileName[] = "delta_times_ms.txt";
50
51 MATCHER_P(HasValidDelay, value, "") {
52 // It is difficult to come up with a perfect test condition for the delay
53 // estimation. For now, verify that the produced output delay is always
54 // larger than the selected buffer size.
55 return arg.hardware_delay_bytes >= value.hardware_delay_bytes;
56 }
57
58 // Used to terminate a loop from a different thread than the loop belongs to.
59 // |loop| should be a MessageLoopProxy.
ACTION_P(QuitLoop,loop)60 ACTION_P(QuitLoop, loop) {
61 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
62 }
63
64 // This audio source implementation should be used for manual tests only since
65 // it takes about 20 seconds to play out a file.
66 class ReadFromFileAudioSource : public AudioOutputStream::AudioSourceCallback {
67 public:
ReadFromFileAudioSource(const std::string & name)68 explicit ReadFromFileAudioSource(const std::string& name)
69 : pos_(0),
70 previous_call_time_(base::TimeTicks::Now()),
71 text_file_(NULL),
72 elements_to_write_(0) {
73 // Reads a test file from media/test/data directory.
74 file_ = ReadTestDataFile(name);
75
76 // Creates an array that will store delta times between callbacks.
77 // The content of this array will be written to a text file at
78 // destruction and can then be used for off-line analysis of the exact
79 // timing of callbacks. The text file will be stored in media/test/data.
80 delta_times_.reset(new int[kMaxDeltaSamples]);
81 }
82
~ReadFromFileAudioSource()83 virtual ~ReadFromFileAudioSource() {
84 // Get complete file path to output file in directory containing
85 // media_unittests.exe.
86 base::FilePath file_name;
87 EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_name));
88 file_name = file_name.AppendASCII(kDeltaTimeMsFileName);
89
90 EXPECT_TRUE(!text_file_);
91 text_file_ = base::OpenFile(file_name, "wt");
92 DLOG_IF(ERROR, !text_file_) << "Failed to open log file.";
93
94 // Write the array which contains delta times to a text file.
95 size_t elements_written = 0;
96 while (elements_written < elements_to_write_) {
97 fprintf(text_file_, "%d\n", delta_times_[elements_written]);
98 ++elements_written;
99 }
100
101 base::CloseFile(text_file_);
102 }
103
104 // AudioOutputStream::AudioSourceCallback implementation.
OnMoreData(AudioBus * audio_bus,AudioBuffersState buffers_state)105 virtual int OnMoreData(AudioBus* audio_bus,
106 AudioBuffersState buffers_state) {
107 // Store time difference between two successive callbacks in an array.
108 // These values will be written to a file in the destructor.
109 const base::TimeTicks now_time = base::TimeTicks::Now();
110 const int diff = (now_time - previous_call_time_).InMilliseconds();
111 previous_call_time_ = now_time;
112 if (elements_to_write_ < kMaxDeltaSamples) {
113 delta_times_[elements_to_write_] = diff;
114 ++elements_to_write_;
115 }
116
117 int max_size =
118 audio_bus->frames() * audio_bus->channels() * kBitsPerSample / 8;
119
120 // Use samples read from a data file and fill up the audio buffer
121 // provided to us in the callback.
122 if (pos_ + static_cast<int>(max_size) > file_size())
123 max_size = file_size() - pos_;
124 int frames = max_size / (audio_bus->channels() * kBitsPerSample / 8);
125 if (max_size) {
126 audio_bus->FromInterleaved(
127 file_->data() + pos_, frames, kBitsPerSample / 8);
128 pos_ += max_size;
129 }
130 return frames;
131 }
132
OnError(AudioOutputStream * stream)133 virtual void OnError(AudioOutputStream* stream) {}
134
file_size()135 int file_size() { return file_->data_size(); }
136
137 private:
138 scoped_refptr<DecoderBuffer> file_;
139 scoped_ptr<int[]> delta_times_;
140 int pos_;
141 base::TimeTicks previous_call_time_;
142 FILE* text_file_;
143 size_t elements_to_write_;
144 };
145
ExclusiveModeIsEnabled()146 static bool ExclusiveModeIsEnabled() {
147 return (WASAPIAudioOutputStream::GetShareMode() ==
148 AUDCLNT_SHAREMODE_EXCLUSIVE);
149 }
150
151 // Convenience method which ensures that we are not running on the build
152 // bots and that at least one valid output device can be found. We also
153 // verify that we are not running on XP since the low-latency (WASAPI-
154 // based) version requires Windows Vista or higher.
CanRunAudioTests(AudioManager * audio_man)155 static bool CanRunAudioTests(AudioManager* audio_man) {
156 if (!CoreAudioUtil::IsSupported()) {
157 LOG(WARNING) << "This test requires Windows Vista or higher.";
158 return false;
159 }
160
161 // TODO(henrika): note that we use Wave today to query the number of
162 // existing output devices.
163 if (!audio_man->HasAudioOutputDevices()) {
164 LOG(WARNING) << "No output devices detected.";
165 return false;
166 }
167
168 return true;
169 }
170
171 // Convenience method which creates a default AudioOutputStream object but
172 // also allows the user to modify the default settings.
173 class AudioOutputStreamWrapper {
174 public:
AudioOutputStreamWrapper(AudioManager * audio_manager)175 explicit AudioOutputStreamWrapper(AudioManager* audio_manager)
176 : audio_man_(audio_manager),
177 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
178 bits_per_sample_(kBitsPerSample) {
179 AudioParameters preferred_params;
180 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
181 eRender, eConsole, &preferred_params)));
182 channel_layout_ = preferred_params.channel_layout();
183 sample_rate_ = preferred_params.sample_rate();
184 samples_per_packet_ = preferred_params.frames_per_buffer();
185 }
186
~AudioOutputStreamWrapper()187 ~AudioOutputStreamWrapper() {}
188
189 // Creates AudioOutputStream object using default parameters.
Create()190 AudioOutputStream* Create() {
191 return CreateOutputStream();
192 }
193
194 // Creates AudioOutputStream object using non-default parameters where the
195 // frame size is modified.
Create(int samples_per_packet)196 AudioOutputStream* Create(int samples_per_packet) {
197 samples_per_packet_ = samples_per_packet;
198 return CreateOutputStream();
199 }
200
201 // Creates AudioOutputStream object using non-default parameters where the
202 // sample rate and frame size are modified.
Create(int sample_rate,int samples_per_packet)203 AudioOutputStream* Create(int sample_rate, int samples_per_packet) {
204 sample_rate_ = sample_rate;
205 samples_per_packet_ = samples_per_packet;
206 return CreateOutputStream();
207 }
208
format() const209 AudioParameters::Format format() const { return format_; }
channels() const210 int channels() const { return ChannelLayoutToChannelCount(channel_layout_); }
bits_per_sample() const211 int bits_per_sample() const { return bits_per_sample_; }
sample_rate() const212 int sample_rate() const { return sample_rate_; }
samples_per_packet() const213 int samples_per_packet() const { return samples_per_packet_; }
214
215 private:
CreateOutputStream()216 AudioOutputStream* CreateOutputStream() {
217 AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(
218 AudioParameters(format_, channel_layout_, sample_rate_,
219 bits_per_sample_, samples_per_packet_),
220 std::string());
221 EXPECT_TRUE(aos);
222 return aos;
223 }
224
225 AudioManager* audio_man_;
226 AudioParameters::Format format_;
227 ChannelLayout channel_layout_;
228 int bits_per_sample_;
229 int sample_rate_;
230 int samples_per_packet_;
231 };
232
233 // Convenience method which creates a default AudioOutputStream object.
CreateDefaultAudioOutputStream(AudioManager * audio_manager)234 static AudioOutputStream* CreateDefaultAudioOutputStream(
235 AudioManager* audio_manager) {
236 AudioOutputStreamWrapper aosw(audio_manager);
237 AudioOutputStream* aos = aosw.Create();
238 return aos;
239 }
240
241 // Verify that we can retrieve the current hardware/mixing sample rate
242 // for the default audio device.
243 // TODO(henrika): modify this test when we support full device enumeration.
TEST(WASAPIAudioOutputStreamTest,HardwareSampleRate)244 TEST(WASAPIAudioOutputStreamTest, HardwareSampleRate) {
245 // Skip this test in exclusive mode since the resulting rate is only utilized
246 // for shared mode streams.
247 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
248 if (!CanRunAudioTests(audio_manager.get()) || ExclusiveModeIsEnabled())
249 return;
250
251 // Default device intended for games, system notification sounds,
252 // and voice commands.
253 int fs = static_cast<int>(
254 WASAPIAudioOutputStream::HardwareSampleRate(std::string()));
255 EXPECT_GE(fs, 0);
256 }
257
258 // Test Create(), Close() calling sequence.
TEST(WASAPIAudioOutputStreamTest,CreateAndClose)259 TEST(WASAPIAudioOutputStreamTest, CreateAndClose) {
260 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
261 if (!CanRunAudioTests(audio_manager.get()))
262 return;
263 AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get());
264 aos->Close();
265 }
266
267 // Test Open(), Close() calling sequence.
TEST(WASAPIAudioOutputStreamTest,OpenAndClose)268 TEST(WASAPIAudioOutputStreamTest, OpenAndClose) {
269 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
270 if (!CanRunAudioTests(audio_manager.get()))
271 return;
272 AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get());
273 EXPECT_TRUE(aos->Open());
274 aos->Close();
275 }
276
277 // Test Open(), Start(), Close() calling sequence.
TEST(WASAPIAudioOutputStreamTest,OpenStartAndClose)278 TEST(WASAPIAudioOutputStreamTest, OpenStartAndClose) {
279 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
280 if (!CanRunAudioTests(audio_manager.get()))
281 return;
282 AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get());
283 EXPECT_TRUE(aos->Open());
284 MockAudioSourceCallback source;
285 EXPECT_CALL(source, OnError(aos))
286 .Times(0);
287 aos->Start(&source);
288 aos->Close();
289 }
290
291 // Test Open(), Start(), Stop(), Close() calling sequence.
TEST(WASAPIAudioOutputStreamTest,OpenStartStopAndClose)292 TEST(WASAPIAudioOutputStreamTest, OpenStartStopAndClose) {
293 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
294 if (!CanRunAudioTests(audio_manager.get()))
295 return;
296 AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get());
297 EXPECT_TRUE(aos->Open());
298 MockAudioSourceCallback source;
299 EXPECT_CALL(source, OnError(aos))
300 .Times(0);
301 aos->Start(&source);
302 aos->Stop();
303 aos->Close();
304 }
305
306 // Test SetVolume(), GetVolume()
TEST(WASAPIAudioOutputStreamTest,Volume)307 TEST(WASAPIAudioOutputStreamTest, Volume) {
308 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
309 if (!CanRunAudioTests(audio_manager.get()))
310 return;
311 AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get());
312
313 // Initial volume should be full volume (1.0).
314 double volume = 0.0;
315 aos->GetVolume(&volume);
316 EXPECT_EQ(1.0, volume);
317
318 // Verify some valid volume settings.
319 aos->SetVolume(0.0);
320 aos->GetVolume(&volume);
321 EXPECT_EQ(0.0, volume);
322
323 aos->SetVolume(0.5);
324 aos->GetVolume(&volume);
325 EXPECT_EQ(0.5, volume);
326
327 aos->SetVolume(1.0);
328 aos->GetVolume(&volume);
329 EXPECT_EQ(1.0, volume);
330
331 // Ensure that invalid volume setting have no effect.
332 aos->SetVolume(1.5);
333 aos->GetVolume(&volume);
334 EXPECT_EQ(1.0, volume);
335
336 aos->SetVolume(-0.5);
337 aos->GetVolume(&volume);
338 EXPECT_EQ(1.0, volume);
339
340 aos->Close();
341 }
342
343 // Test some additional calling sequences.
TEST(WASAPIAudioOutputStreamTest,MiscCallingSequences)344 TEST(WASAPIAudioOutputStreamTest, MiscCallingSequences) {
345 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
346 if (!CanRunAudioTests(audio_manager.get()))
347 return;
348
349 AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get());
350 WASAPIAudioOutputStream* waos = static_cast<WASAPIAudioOutputStream*>(aos);
351
352 // Open(), Open() is a valid calling sequence (second call does nothing).
353 EXPECT_TRUE(aos->Open());
354 EXPECT_TRUE(aos->Open());
355
356 MockAudioSourceCallback source;
357
358 // Start(), Start() is a valid calling sequence (second call does nothing).
359 aos->Start(&source);
360 EXPECT_TRUE(waos->started());
361 aos->Start(&source);
362 EXPECT_TRUE(waos->started());
363
364 // Stop(), Stop() is a valid calling sequence (second call does nothing).
365 aos->Stop();
366 EXPECT_FALSE(waos->started());
367 aos->Stop();
368 EXPECT_FALSE(waos->started());
369
370 // Start(), Stop(), Start(), Stop().
371 aos->Start(&source);
372 EXPECT_TRUE(waos->started());
373 aos->Stop();
374 EXPECT_FALSE(waos->started());
375 aos->Start(&source);
376 EXPECT_TRUE(waos->started());
377 aos->Stop();
378 EXPECT_FALSE(waos->started());
379
380 aos->Close();
381 }
382
383 // Use preferred packet size and verify that rendering starts.
TEST(WASAPIAudioOutputStreamTest,ValidPacketSize)384 TEST(WASAPIAudioOutputStreamTest, ValidPacketSize) {
385 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
386 if (!CanRunAudioTests(audio_manager.get()))
387 return;
388
389 base::MessageLoopForUI loop;
390 MockAudioSourceCallback source;
391
392 // Create default WASAPI output stream which plays out in stereo using
393 // the shared mixing rate. The default buffer size is 10ms.
394 AudioOutputStreamWrapper aosw(audio_manager.get());
395 AudioOutputStream* aos = aosw.Create();
396 EXPECT_TRUE(aos->Open());
397
398 // Derive the expected size in bytes of each packet.
399 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() *
400 (aosw.bits_per_sample() / 8);
401
402 // Set up expected minimum delay estimation.
403 AudioBuffersState state(0, bytes_per_packet);
404
405 // Wait for the first callback and verify its parameters.
406 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state)))
407 .WillOnce(DoAll(
408 QuitLoop(loop.message_loop_proxy()),
409 Return(aosw.samples_per_packet())));
410
411 aos->Start(&source);
412 loop.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(),
413 TestTimeouts::action_timeout());
414 loop.Run();
415 aos->Stop();
416 aos->Close();
417 }
418
419 // This test is intended for manual tests and should only be enabled
420 // when it is required to play out data from a local PCM file.
421 // By default, GTest will print out YOU HAVE 1 DISABLED TEST.
422 // To include disabled tests in test execution, just invoke the test program
423 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
424 // environment variable to a value greater than 0.
425 // The test files are approximately 20 seconds long.
TEST(WASAPIAudioOutputStreamTest,DISABLED_ReadFromStereoFile)426 TEST(WASAPIAudioOutputStreamTest, DISABLED_ReadFromStereoFile) {
427 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
428 if (!CanRunAudioTests(audio_manager.get()))
429 return;
430
431 AudioOutputStreamWrapper aosw(audio_manager.get());
432 AudioOutputStream* aos = aosw.Create();
433 EXPECT_TRUE(aos->Open());
434
435 std::string file_name;
436 if (aosw.sample_rate() == 48000) {
437 file_name = kSpeechFile_16b_s_48k;
438 } else if (aosw.sample_rate() == 44100) {
439 file_name = kSpeechFile_16b_s_44k;
440 } else if (aosw.sample_rate() == 96000) {
441 // Use 48kHz file at 96kHz as well. Will sound like Donald Duck.
442 file_name = kSpeechFile_16b_s_48k;
443 } else {
444 FAIL() << "This test supports 44.1, 48kHz and 96kHz only.";
445 return;
446 }
447 ReadFromFileAudioSource file_source(file_name);
448
449 VLOG(0) << "File name : " << file_name.c_str();
450 VLOG(0) << "Sample rate : " << aosw.sample_rate();
451 VLOG(0) << "Bits per sample: " << aosw.bits_per_sample();
452 VLOG(0) << "#channels : " << aosw.channels();
453 VLOG(0) << "File size : " << file_source.file_size();
454 VLOG(0) << "#file segments : " << kNumFileSegments;
455 VLOG(0) << ">> Listen to the stereo file while playing...";
456
457 for (int i = 0; i < kNumFileSegments; i++) {
458 // Each segment will start with a short (~20ms) block of zeros, hence
459 // some short glitches might be heard in this test if kNumFileSegments
460 // is larger than one. The exact length of the silence period depends on
461 // the selected sample rate.
462 aos->Start(&file_source);
463 base::PlatformThread::Sleep(
464 base::TimeDelta::FromMilliseconds(kFileDurationMs / kNumFileSegments));
465 aos->Stop();
466 }
467
468 VLOG(0) << ">> Stereo file playout has stopped.";
469 aos->Close();
470 }
471
472 // Verify that we can open the output stream in exclusive mode using a
473 // certain set of audio parameters and a sample rate of 48kHz.
474 // The expected outcomes of each setting in this test has been derived
475 // manually using log outputs (--v=1).
TEST(WASAPIAudioOutputStreamTest,ExclusiveModeBufferSizesAt48kHz)476 TEST(WASAPIAudioOutputStreamTest, ExclusiveModeBufferSizesAt48kHz) {
477 if (!ExclusiveModeIsEnabled())
478 return;
479
480 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
481 if (!CanRunAudioTests(audio_manager.get()))
482 return;
483
484 AudioOutputStreamWrapper aosw(audio_manager.get());
485
486 // 10ms @ 48kHz shall work.
487 // Note that, this is the same size as we can use for shared-mode streaming
488 // but here the endpoint buffer delay is only 10ms instead of 20ms.
489 AudioOutputStream* aos = aosw.Create(48000, 480);
490 EXPECT_TRUE(aos->Open());
491 aos->Close();
492
493 // 5ms @ 48kHz does not work due to misalignment.
494 // This test will propose an aligned buffer size of 5.3333ms.
495 // Note that we must call Close() even is Open() fails since Close() also
496 // deletes the object and we want to create a new object in the next test.
497 aos = aosw.Create(48000, 240);
498 EXPECT_FALSE(aos->Open());
499 aos->Close();
500
501 // 5.3333ms @ 48kHz should work (see test above).
502 aos = aosw.Create(48000, 256);
503 EXPECT_TRUE(aos->Open());
504 aos->Close();
505
506 // 2.6667ms is smaller than the minimum supported size (=3ms).
507 aos = aosw.Create(48000, 128);
508 EXPECT_FALSE(aos->Open());
509 aos->Close();
510
511 // 3ms does not correspond to an aligned buffer size.
512 // This test will propose an aligned buffer size of 3.3333ms.
513 aos = aosw.Create(48000, 144);
514 EXPECT_FALSE(aos->Open());
515 aos->Close();
516
517 // 3.3333ms @ 48kHz <=> smallest possible buffer size we can use.
518 aos = aosw.Create(48000, 160);
519 EXPECT_TRUE(aos->Open());
520 aos->Close();
521 }
522
523 // Verify that we can open the output stream in exclusive mode using a
524 // certain set of audio parameters and a sample rate of 44.1kHz.
525 // The expected outcomes of each setting in this test has been derived
526 // manually using log outputs (--v=1).
TEST(WASAPIAudioOutputStreamTest,ExclusiveModeBufferSizesAt44kHz)527 TEST(WASAPIAudioOutputStreamTest, ExclusiveModeBufferSizesAt44kHz) {
528 if (!ExclusiveModeIsEnabled())
529 return;
530
531 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
532 if (!CanRunAudioTests(audio_manager.get()))
533 return;
534
535 AudioOutputStreamWrapper aosw(audio_manager.get());
536
537 // 10ms @ 44.1kHz does not work due to misalignment.
538 // This test will propose an aligned buffer size of 10.1587ms.
539 AudioOutputStream* aos = aosw.Create(44100, 441);
540 EXPECT_FALSE(aos->Open());
541 aos->Close();
542
543 // 10.1587ms @ 44.1kHz shall work (see test above).
544 aos = aosw.Create(44100, 448);
545 EXPECT_TRUE(aos->Open());
546 aos->Close();
547
548 // 5.8050ms @ 44.1 should work.
549 aos = aosw.Create(44100, 256);
550 EXPECT_TRUE(aos->Open());
551 aos->Close();
552
553 // 4.9887ms @ 44.1kHz does not work to misalignment.
554 // This test will propose an aligned buffer size of 5.0794ms.
555 // Note that we must call Close() even is Open() fails since Close() also
556 // deletes the object and we want to create a new object in the next test.
557 aos = aosw.Create(44100, 220);
558 EXPECT_FALSE(aos->Open());
559 aos->Close();
560
561 // 5.0794ms @ 44.1kHz shall work (see test above).
562 aos = aosw.Create(44100, 224);
563 EXPECT_TRUE(aos->Open());
564 aos->Close();
565
566 // 2.9025ms is smaller than the minimum supported size (=3ms).
567 aos = aosw.Create(44100, 132);
568 EXPECT_FALSE(aos->Open());
569 aos->Close();
570
571 // 3.01587ms is larger than the minimum size but is not aligned.
572 // This test will propose an aligned buffer size of 3.6281ms.
573 aos = aosw.Create(44100, 133);
574 EXPECT_FALSE(aos->Open());
575 aos->Close();
576
577 // 3.6281ms @ 44.1kHz <=> smallest possible buffer size we can use.
578 aos = aosw.Create(44100, 160);
579 EXPECT_TRUE(aos->Open());
580 aos->Close();
581 }
582
583 // Verify that we can open and start the output stream in exclusive mode at
584 // the lowest possible delay at 48kHz.
TEST(WASAPIAudioOutputStreamTest,ExclusiveModeMinBufferSizeAt48kHz)585 TEST(WASAPIAudioOutputStreamTest, ExclusiveModeMinBufferSizeAt48kHz) {
586 if (!ExclusiveModeIsEnabled())
587 return;
588
589 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
590 if (!CanRunAudioTests(audio_manager.get()))
591 return;
592
593 base::MessageLoopForUI loop;
594 MockAudioSourceCallback source;
595
596 // Create exclusive-mode WASAPI output stream which plays out in stereo
597 // using the minimum buffer size at 48kHz sample rate.
598 AudioOutputStreamWrapper aosw(audio_manager.get());
599 AudioOutputStream* aos = aosw.Create(48000, 160);
600 EXPECT_TRUE(aos->Open());
601
602 // Derive the expected size in bytes of each packet.
603 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() *
604 (aosw.bits_per_sample() / 8);
605
606 // Set up expected minimum delay estimation.
607 AudioBuffersState state(0, bytes_per_packet);
608
609 // Wait for the first callback and verify its parameters.
610 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state)))
611 .WillOnce(DoAll(
612 QuitLoop(loop.message_loop_proxy()),
613 Return(aosw.samples_per_packet())))
614 .WillRepeatedly(Return(aosw.samples_per_packet()));
615
616 aos->Start(&source);
617 loop.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(),
618 TestTimeouts::action_timeout());
619 loop.Run();
620 aos->Stop();
621 aos->Close();
622 }
623
624 // Verify that we can open and start the output stream in exclusive mode at
625 // the lowest possible delay at 44.1kHz.
TEST(WASAPIAudioOutputStreamTest,ExclusiveModeMinBufferSizeAt44kHz)626 TEST(WASAPIAudioOutputStreamTest, ExclusiveModeMinBufferSizeAt44kHz) {
627 if (!ExclusiveModeIsEnabled())
628 return;
629
630 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
631 if (!CanRunAudioTests(audio_manager.get()))
632 return;
633
634 base::MessageLoopForUI loop;
635 MockAudioSourceCallback source;
636
637 // Create exclusive-mode WASAPI output stream which plays out in stereo
638 // using the minimum buffer size at 44.1kHz sample rate.
639 AudioOutputStreamWrapper aosw(audio_manager.get());
640 AudioOutputStream* aos = aosw.Create(44100, 160);
641 EXPECT_TRUE(aos->Open());
642
643 // Derive the expected size in bytes of each packet.
644 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() *
645 (aosw.bits_per_sample() / 8);
646
647 // Set up expected minimum delay estimation.
648 AudioBuffersState state(0, bytes_per_packet);
649
650 // Wait for the first callback and verify its parameters.
651 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state)))
652 .WillOnce(DoAll(
653 QuitLoop(loop.message_loop_proxy()),
654 Return(aosw.samples_per_packet())))
655 .WillRepeatedly(Return(aosw.samples_per_packet()));
656
657 aos->Start(&source);
658 loop.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(),
659 TestTimeouts::action_timeout());
660 loop.Run();
661 aos->Stop();
662 aos->Close();
663 }
664
665 } // namespace media
666