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