Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(319)

Side by Side Diff: media/audio/win/audio_low_latency_output_win_unittest.cc

Issue 12049070: Avoids irregular OnMoreData callbacks on Windows using Core Audio (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Non trivial rebase Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <windows.h> 5 #include <windows.h>
6 #include <mmsystem.h> 6 #include <mmsystem.h>
7 7
8 #include "base/basictypes.h" 8 #include "base/basictypes.h"
9 #include "base/environment.h" 9 #include "base/environment.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
(...skipping 10 matching lines...) Expand all
21 #include "media/audio/win/core_audio_util_win.h" 21 #include "media/audio/win/core_audio_util_win.h"
22 #include "media/base/decoder_buffer.h" 22 #include "media/base/decoder_buffer.h"
23 #include "media/base/seekable_buffer.h" 23 #include "media/base/seekable_buffer.h"
24 #include "media/base/test_data_util.h" 24 #include "media/base/test_data_util.h"
25 #include "testing/gmock_mutant.h" 25 #include "testing/gmock_mutant.h"
26 #include "testing/gmock/include/gmock/gmock.h" 26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h" 27 #include "testing/gtest/include/gtest/gtest.h"
28 28
29 using ::testing::_; 29 using ::testing::_;
30 using ::testing::AnyNumber; 30 using ::testing::AnyNumber;
31 using ::testing::AtLeast;
31 using ::testing::Between; 32 using ::testing::Between;
32 using ::testing::CreateFunctor; 33 using ::testing::CreateFunctor;
33 using ::testing::DoAll; 34 using ::testing::DoAll;
34 using ::testing::Gt; 35 using ::testing::Gt;
35 using ::testing::InvokeWithoutArgs; 36 using ::testing::InvokeWithoutArgs;
36 using ::testing::NotNull; 37 using ::testing::NotNull;
37 using ::testing::Return; 38 using ::testing::Return;
38 using base::win::ScopedCOMInitializer; 39 using base::win::ScopedCOMInitializer;
39 40
40 namespace media { 41 namespace media {
41 42
42 static const char kSpeechFile_16b_s_48k[] = "speech_16b_stereo_48kHz.raw"; 43 static const char kSpeechFile_16b_s_48k[] = "speech_16b_stereo_48kHz.raw";
43 static const char kSpeechFile_16b_s_44k[] = "speech_16b_stereo_44kHz.raw"; 44 static const char kSpeechFile_16b_s_44k[] = "speech_16b_stereo_44kHz.raw";
44 static const size_t kFileDurationMs = 20000; 45 static const size_t kFileDurationMs = 20000;
45 static const size_t kNumFileSegments = 2; 46 static const size_t kNumFileSegments = 2;
46 static const int kBitsPerSample = 16; 47 static const int kBitsPerSample = 16;
47 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
48 static const size_t kMaxDeltaSamples = 1000; 48 static const size_t kMaxDeltaSamples = 1000;
49 static const char* kDeltaTimeMsFileName = "delta_times_ms.txt"; 49 static const char* kDeltaTimeMsFileName = "delta_times_ms.txt";
50 50
51 MATCHER_P(HasValidDelay, value, "") { 51 MATCHER_P(HasValidDelay, value, "") {
52 // It is difficult to come up with a perfect test condition for the delay 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 53 // estimation. For now, verify that the produced output delay is always
54 // larger than the selected buffer size. 54 // larger than the selected buffer size.
55 return arg.hardware_delay_bytes > value.hardware_delay_bytes; 55 return arg.hardware_delay_bytes >= value.hardware_delay_bytes;
56 } 56 }
57 57
58 // Used to terminate a loop from a different thread than the loop belongs to. 58 // Used to terminate a loop from a different thread than the loop belongs to.
59 // |loop| should be a MessageLoopProxy. 59 // |loop| should be a MessageLoopProxy.
60 ACTION_P(QuitLoop, loop) { 60 ACTION_P(QuitLoop, loop) {
61 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 61 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
62 } 62 }
63 63
64 class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { 64 class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback {
65 public: 65 public:
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 return false; 174 return false;
175 } 175 }
176 176
177 // TODO(henrika): note that we use Wave today to query the number of 177 // TODO(henrika): note that we use Wave today to query the number of
178 // existing output devices. 178 // existing output devices.
179 if (!audio_man->HasAudioOutputDevices()) { 179 if (!audio_man->HasAudioOutputDevices()) {
180 LOG(WARNING) << "No output devices detected."; 180 LOG(WARNING) << "No output devices detected.";
181 return false; 181 return false;
182 } 182 }
183 183
184 if (WASAPIAudioOutputStream::HardwareChannelLayout() != kChannelLayout) {
185 LOG(WARNING) << "This test requires stereo audio output.";
186 return false;
187 }
188
189 return true; 184 return true;
190 } 185 }
191 186
192 // Convenience method which creates a default AudioOutputStream object but 187 // Convenience method which creates a default AudioOutputStream object but
193 // also allows the user to modify the default settings. 188 // also allows the user to modify the default settings.
194 class AudioOutputStreamWrapper { 189 class AudioOutputStreamWrapper {
195 public: 190 public:
196 explicit AudioOutputStreamWrapper(AudioManager* audio_manager) 191 explicit AudioOutputStreamWrapper(AudioManager* audio_manager)
197 : com_init_(ScopedCOMInitializer::kMTA), 192 : audio_man_(audio_manager),
198 audio_man_(audio_manager),
199 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY), 193 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
200 channel_layout_(kChannelLayout),
201 bits_per_sample_(kBitsPerSample) { 194 bits_per_sample_(kBitsPerSample) {
202 // Use native/mixing sample rate and 10ms frame size as default. 195 AudioParameters preferred_params;
203 sample_rate_ = static_cast<int>( 196 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
204 WASAPIAudioOutputStream::HardwareSampleRate(eConsole)); 197 eRender, eConsole, &preferred_params)));
205 samples_per_packet_ = sample_rate_ / 100; 198 channel_layout_ = preferred_params.channel_layout();
206 DCHECK(sample_rate_); 199 sample_rate_ = preferred_params.sample_rate();
200 samples_per_packet_ = preferred_params.frames_per_buffer();
207 } 201 }
208 202
209 ~AudioOutputStreamWrapper() {} 203 ~AudioOutputStreamWrapper() {}
210 204
211 // Creates AudioOutputStream object using default parameters. 205 // Creates AudioOutputStream object using default parameters.
212 AudioOutputStream* Create() { 206 AudioOutputStream* Create() {
213 return CreateOutputStream(); 207 return CreateOutputStream();
214 } 208 }
215 209
216 // Creates AudioOutputStream object using non-default parameters where the 210 // Creates AudioOutputStream object using non-default parameters where the
(...skipping 19 matching lines...) Expand all
236 230
237 private: 231 private:
238 AudioOutputStream* CreateOutputStream() { 232 AudioOutputStream* CreateOutputStream() {
239 AudioOutputStream* aos = audio_man_->MakeAudioOutputStream( 233 AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(
240 AudioParameters(format_, channel_layout_, sample_rate_, 234 AudioParameters(format_, channel_layout_, sample_rate_,
241 bits_per_sample_, samples_per_packet_)); 235 bits_per_sample_, samples_per_packet_));
242 EXPECT_TRUE(aos); 236 EXPECT_TRUE(aos);
243 return aos; 237 return aos;
244 } 238 }
245 239
246 ScopedCOMInitializer com_init_;
247 AudioManager* audio_man_; 240 AudioManager* audio_man_;
248 AudioParameters::Format format_; 241 AudioParameters::Format format_;
249 ChannelLayout channel_layout_; 242 ChannelLayout channel_layout_;
250 int bits_per_sample_; 243 int bits_per_sample_;
251 int sample_rate_; 244 int sample_rate_;
252 int samples_per_packet_; 245 int samples_per_packet_;
253 }; 246 };
254 247
255 // Convenience method which creates a default AudioOutputStream object. 248 // Convenience method which creates a default AudioOutputStream object.
256 static AudioOutputStream* CreateDefaultAudioOutputStream( 249 static AudioOutputStream* CreateDefaultAudioOutputStream(
257 AudioManager* audio_manager) { 250 AudioManager* audio_manager) {
258 AudioOutputStreamWrapper aosw(audio_manager); 251 AudioOutputStreamWrapper aosw(audio_manager);
259 AudioOutputStream* aos = aosw.Create(); 252 AudioOutputStream* aos = aosw.Create();
260 return aos; 253 return aos;
261 } 254 }
262 255
263 // Verify that we can retrieve the current hardware/mixing sample rate 256 // Verify that we can retrieve the current hardware/mixing sample rate
264 // for all supported device roles. The ERole enumeration defines constants 257 // for the default audio device.
265 // that indicate the role that the system/user has assigned to an audio
266 // endpoint device.
267 // TODO(henrika): modify this test when we support full device enumeration. 258 // TODO(henrika): modify this test when we support full device enumeration.
268 TEST(WASAPIAudioOutputStreamTest, HardwareSampleRate) { 259 TEST(WASAPIAudioOutputStreamTest, HardwareSampleRate) {
269 // Skip this test in exclusive mode since the resulting rate is only utilized 260 // Skip this test in exclusive mode since the resulting rate is only utilized
270 // for shared mode streams. 261 // for shared mode streams.
271 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); 262 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
272 if (!CanRunAudioTests(audio_manager.get()) || ExclusiveModeIsEnabled()) 263 if (!CanRunAudioTests(audio_manager.get()) || ExclusiveModeIsEnabled())
273 return; 264 return;
274 265
275 ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
276
277 // Default device intended for games, system notification sounds, 266 // Default device intended for games, system notification sounds,
278 // and voice commands. 267 // and voice commands.
279 int fs = static_cast<int>( 268 int fs = static_cast<int>(
280 WASAPIAudioOutputStream::HardwareSampleRate(eConsole)); 269 WASAPIAudioOutputStream::HardwareSampleRate());
281 EXPECT_GE(fs, 0);
282
283 // Default communication device intended for e.g. VoIP communication.
284 fs = static_cast<int>(
285 WASAPIAudioOutputStream::HardwareSampleRate(eCommunications));
286 EXPECT_GE(fs, 0);
287
288 // Multimedia device for music, movies and live music recording.
289 fs = static_cast<int>(
290 WASAPIAudioOutputStream::HardwareSampleRate(eMultimedia));
291 EXPECT_GE(fs, 0); 270 EXPECT_GE(fs, 0);
292 } 271 }
293 272
294 // Test Create(), Close() calling sequence. 273 // Test Create(), Close() calling sequence.
295 TEST(WASAPIAudioOutputStreamTest, CreateAndClose) { 274 TEST(WASAPIAudioOutputStreamTest, CreateAndClose) {
296 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); 275 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
297 if (!CanRunAudioTests(audio_manager.get())) 276 if (!CanRunAudioTests(audio_manager.get()))
298 return; 277 return;
299 AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get()); 278 AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get());
300 aos->Close(); 279 aos->Close();
301 } 280 }
302 281
303 // Verify that the created object is configured to use the same number of 282 // Verify that the created object is configured to use the same number of
304 // audio channels as is reported by the static HardwareChannelCount() method. 283 // audio channels as is reported by the static HardwareChannelCount() method.
305 TEST(WASAPIAudioOutputStreamTest, HardwareChannelCount) { 284 TEST(WASAPIAudioOutputStreamTest, HardwareChannelCount) {
306 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); 285 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
307 if (!CanRunAudioTests(audio_manager.get())) 286 if (!CanRunAudioTests(audio_manager.get()))
308 return; 287 return;
309 288
310 ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
311
312 // First, verify that we can read a valid native/hardware channel-count. 289 // First, verify that we can read a valid native/hardware channel-count.
313 int hardware_channel_count = WASAPIAudioOutputStream::HardwareChannelCount(); 290 int hardware_channel_count = WASAPIAudioOutputStream::HardwareChannelCount();
314 EXPECT_GE(hardware_channel_count, 1); 291 EXPECT_GE(hardware_channel_count, 1);
315 292
316 AudioOutputStreamWrapper aosw(audio_manager.get()); 293 AudioOutputStreamWrapper aosw(audio_manager.get());
317 WASAPIAudioOutputStream* aos = 294 WASAPIAudioOutputStream* aos =
318 static_cast<WASAPIAudioOutputStream*>(aosw.Create()); 295 static_cast<WASAPIAudioOutputStream*>(aosw.Create());
319 296
320 // Next, ensure that the created output stream object is really using the 297 // Next, ensure that the created output stream object is really using the
321 // hardware channel-count. 298 // hardware channel-count.
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 aos->Stop(); 409 aos->Stop();
433 EXPECT_FALSE(waos->started()); 410 EXPECT_FALSE(waos->started());
434 aos->Start(&source); 411 aos->Start(&source);
435 EXPECT_TRUE(waos->started()); 412 EXPECT_TRUE(waos->started());
436 aos->Stop(); 413 aos->Stop();
437 EXPECT_FALSE(waos->started()); 414 EXPECT_FALSE(waos->started());
438 415
439 aos->Close(); 416 aos->Close();
440 } 417 }
441 418
442 // Use default packet size (10ms) and verify that rendering starts. 419 // Use preferred packet size and verify that rendering starts.
443 TEST(WASAPIAudioOutputStreamTest, PacketSizeInMilliseconds) { 420 TEST(WASAPIAudioOutputStreamTest, ValidPacketSize) {
444 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); 421 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
445 if (!CanRunAudioTests(audio_manager.get())) 422 if (!CanRunAudioTests(audio_manager.get()))
446 return; 423 return;
447 424
448 MessageLoopForUI loop; 425 MessageLoopForUI loop;
449 MockAudioSourceCallback source; 426 MockAudioSourceCallback source;
450 427
451 // Create default WASAPI output stream which plays out in stereo using 428 // Create default WASAPI output stream which plays out in stereo using
452 // the shared mixing rate. The default buffer size is 10ms. 429 // the shared mixing rate. The default buffer size is 10ms.
453 AudioOutputStreamWrapper aosw(audio_manager.get()); 430 AudioOutputStreamWrapper aosw(audio_manager.get());
(...skipping 14 matching lines...) Expand all
468 Return(aosw.samples_per_packet()))); 445 Return(aosw.samples_per_packet())));
469 446
470 aos->Start(&source); 447 aos->Start(&source);
471 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), 448 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
472 TestTimeouts::action_timeout()); 449 TestTimeouts::action_timeout());
473 loop.Run(); 450 loop.Run();
474 aos->Stop(); 451 aos->Stop();
475 aos->Close(); 452 aos->Close();
476 } 453 }
477 454
478 // Use a fixed packets size (independent of sample rate) and verify 455 // Use a non-preferred packet size and verify that Open() fails.
479 // that rendering starts. 456 TEST(WASAPIAudioOutputStreamTest, InvalidPacketSize) {
480 TEST(WASAPIAudioOutputStreamTest, PacketSizeInSamples) {
481 scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); 457 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
482 if (!CanRunAudioTests(audio_manager.get())) 458 if (!CanRunAudioTests(audio_manager.get()))
483 return; 459 return;
484 460
485 MessageLoopForUI loop; 461 if (ExclusiveModeIsEnabled())
486 MockAudioSourceCallback source; 462 return;
487 463
488 // Create default WASAPI output stream which reads data in stereo using 464 AudioParameters preferred_params;
489 // the native mixing rate and channel count. The buffer size is set to 465 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
490 // 1024 samples. 466 eRender, eConsole, &preferred_params)));
467 int too_large_packet_size = 2 * preferred_params.frames_per_buffer();
468
491 AudioOutputStreamWrapper aosw(audio_manager.get()); 469 AudioOutputStreamWrapper aosw(audio_manager.get());
492 AudioOutputStream* aos = aosw.Create(1024); 470 AudioOutputStream* aos = aosw.Create(too_large_packet_size);
493 EXPECT_TRUE(aos->Open()); 471 EXPECT_FALSE(aos->Open());
494 472
495 // Derive the expected size in bytes of each packet.
496 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() *
497 (aosw.bits_per_sample() / 8);
498
499 // Set up expected minimum delay estimation.
500 AudioBuffersState state(0, bytes_per_packet);
501
502 // Ensure that callbacks start correctly.
503 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state)))
504 .WillOnce(DoAll(
505 QuitLoop(loop.message_loop_proxy()),
506 Return(aosw.samples_per_packet())))
507 .WillRepeatedly(Return(aosw.samples_per_packet()));
508
509 aos->Start(&source);
510 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
511 TestTimeouts::action_timeout());
512 loop.Run();
513 aos->Stop();
514 aos->Close(); 473 aos->Close();
515 } 474 }
516 475
517 // This test is intended for manual tests and should only be enabled 476 // This test is intended for manual tests and should only be enabled
518 // when it is required to play out data from a local PCM file. 477 // when it is required to play out data from a local PCM file.
519 // By default, GTest will print out YOU HAVE 1 DISABLED TEST. 478 // By default, GTest will print out YOU HAVE 1 DISABLED TEST.
520 // To include disabled tests in test execution, just invoke the test program 479 // To include disabled tests in test execution, just invoke the test program
521 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS 480 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
522 // environment variable to a value greater than 0. 481 // environment variable to a value greater than 0.
523 // The test files are approximately 20 seconds long. 482 // The test files are approximately 20 seconds long.
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
697 AudioOutputStream* aos = aosw.Create(48000, 160); 656 AudioOutputStream* aos = aosw.Create(48000, 160);
698 EXPECT_TRUE(aos->Open()); 657 EXPECT_TRUE(aos->Open());
699 658
700 // Derive the expected size in bytes of each packet. 659 // Derive the expected size in bytes of each packet.
701 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * 660 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() *
702 (aosw.bits_per_sample() / 8); 661 (aosw.bits_per_sample() / 8);
703 662
704 // Set up expected minimum delay estimation. 663 // Set up expected minimum delay estimation.
705 AudioBuffersState state(0, bytes_per_packet); 664 AudioBuffersState state(0, bytes_per_packet);
706 665
707 // Wait for the first callback and verify its parameters. 666 // Wait for the first callback and verify its parameters.
708 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state))) 667 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state)))
709 .WillOnce(DoAll( 668 .WillOnce(DoAll(
710 QuitLoop(loop.message_loop_proxy()), 669 QuitLoop(loop.message_loop_proxy()),
711 Return(aosw.samples_per_packet()))) 670 Return(aosw.samples_per_packet())))
712 .WillRepeatedly(Return(aosw.samples_per_packet())); 671 .WillRepeatedly(Return(aosw.samples_per_packet()));
713 672
714 aos->Start(&source); 673 aos->Start(&source);
715 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), 674 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
716 TestTimeouts::action_timeout()); 675 TestTimeouts::action_timeout());
717 loop.Run(); 676 loop.Run();
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
754 713
755 aos->Start(&source); 714 aos->Start(&source);
756 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), 715 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
757 TestTimeouts::action_timeout()); 716 TestTimeouts::action_timeout());
758 loop.Run(); 717 loop.Run();
759 aos->Stop(); 718 aos->Stop();
760 aos->Close(); 719 aos->Close();
761 } 720 }
762 721
763 } // namespace media 722 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698