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