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