OLD | NEW |
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/base_paths.h" | 9 #include "base/base_paths.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/memory/aligned_memory.h" |
11 #include "base/path_service.h" | 12 #include "base/path_service.h" |
12 #include "base/sync_socket.h" | 13 #include "base/sync_socket.h" |
13 #include "base/win/scoped_com_initializer.h" | 14 #include "base/win/scoped_com_initializer.h" |
14 #include "base/win/windows_version.h" | 15 #include "base/win/windows_version.h" |
15 #include "media/base/limits.h" | 16 #include "media/base/limits.h" |
16 #include "media/audio/audio_io.h" | 17 #include "media/audio/audio_io.h" |
17 #include "media/audio/audio_util.h" | 18 #include "media/audio/audio_util.h" |
18 #include "media/audio/audio_manager.h" | 19 #include "media/audio/audio_manager.h" |
19 #include "media/audio/simple_sources.h" | 20 #include "media/audio/simple_sources.h" |
20 #include "testing/gmock/include/gmock/gmock.h" | 21 #include "testing/gmock/include/gmock/gmock.h" |
21 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
22 | 23 |
23 using ::testing::_; | 24 using ::testing::_; |
24 using ::testing::AnyNumber; | 25 using ::testing::AnyNumber; |
25 using ::testing::DoAll; | 26 using ::testing::DoAll; |
26 using ::testing::Field; | 27 using ::testing::Field; |
| 28 using ::testing::Invoke; |
27 using ::testing::InSequence; | 29 using ::testing::InSequence; |
28 using ::testing::NiceMock; | 30 using ::testing::NiceMock; |
29 using ::testing::NotNull; | 31 using ::testing::NotNull; |
30 using ::testing::Return; | 32 using ::testing::Return; |
31 | 33 |
32 using base::win::ScopedCOMInitializer; | 34 using base::win::ScopedCOMInitializer; |
33 | 35 |
34 namespace media { | 36 namespace media { |
35 | 37 |
36 static const wchar_t kAudioFile1_16b_m_16K[] | 38 static const wchar_t kAudioFile1_16b_m_16K[] |
37 = L"media\\test\\data\\sweep02_16b_mono_16KHz.raw"; | 39 = L"media\\test\\data\\sweep02_16b_mono_16KHz.raw"; |
38 | 40 |
39 // This class allows to find out if the callbacks are occurring as | 41 // This class allows to find out if the callbacks are occurring as |
40 // expected and if any error has been reported. | 42 // expected and if any error has been reported. |
41 class TestSourceBasic : public AudioOutputStream::AudioSourceCallback { | 43 class TestSourceBasic : public AudioOutputStream::AudioSourceCallback { |
42 public: | 44 public: |
43 explicit TestSourceBasic() | 45 explicit TestSourceBasic() |
44 : callback_count_(0), | 46 : callback_count_(0), |
45 had_error_(0) { | 47 had_error_(0) { |
46 } | 48 } |
47 // AudioSourceCallback::OnMoreData implementation: | 49 // AudioSourceCallback::OnMoreData implementation: |
48 virtual uint32 OnMoreData(uint8* dest, | 50 virtual int OnMoreData(AudioBus* audio_bus, |
49 uint32 max_size, | 51 AudioBuffersState buffers_state) { |
50 AudioBuffersState buffers_state) { | |
51 ++callback_count_; | 52 ++callback_count_; |
52 // Touch the first byte to make sure memory is good. | 53 // Touch the channel memory value to make sure memory is good. |
53 if (max_size) | 54 audio_bus->Zero(); |
54 reinterpret_cast<char*>(dest)[0] = 1; | 55 return audio_bus->frames(); |
55 return max_size; | |
56 } | 56 } |
57 // AudioSourceCallback::OnError implementation: | 57 // AudioSourceCallback::OnError implementation: |
58 virtual void OnError(AudioOutputStream* stream, int code) { | 58 virtual void OnError(AudioOutputStream* stream, int code) { |
59 ++had_error_; | 59 ++had_error_; |
60 } | 60 } |
61 // Returns how many times OnMoreData() has been called. | 61 // Returns how many times OnMoreData() has been called. |
62 int callback_count() const { | 62 int callback_count() const { |
63 return callback_count_; | 63 return callback_count_; |
64 } | 64 } |
65 // Returns how many times the OnError callback was called. | 65 // Returns how many times the OnError callback was called. |
66 int had_error() const { | 66 int had_error() const { |
67 return had_error_; | 67 return had_error_; |
68 } | 68 } |
69 | 69 |
70 void set_error(bool error) { | 70 void set_error(bool error) { |
71 had_error_ += error ? 1 : 0; | 71 had_error_ += error ? 1 : 0; |
72 } | 72 } |
73 | 73 |
74 private: | 74 private: |
75 int callback_count_; | 75 int callback_count_; |
76 int had_error_; | 76 int had_error_; |
77 }; | 77 }; |
78 | 78 |
79 const int kMaxNumBuffers = 3; | 79 const int kMaxNumBuffers = 3; |
80 // Specializes TestSourceBasic to detect that the AudioStream is using | |
81 // triple buffering correctly. | |
82 class TestSourceTripleBuffer : public TestSourceBasic { | |
83 public: | |
84 TestSourceTripleBuffer() { | |
85 buffer_address_[0] = NULL; | |
86 buffer_address_[1] = NULL; | |
87 buffer_address_[2] = NULL; | |
88 } | |
89 // Override of TestSourceBasic::OnMoreData. | |
90 virtual uint32 OnMoreData(uint8* dest, | |
91 uint32 max_size, | |
92 AudioBuffersState buffers_state) { | |
93 // Call the base, which increments the callback_count_. | |
94 TestSourceBasic::OnMoreData(dest, max_size, buffers_state); | |
95 if (callback_count() % NumberOfWaveOutBuffers() == 2) { | |
96 set_error(!CompareExistingIfNotNULL(2, dest)); | |
97 } else if (callback_count() % NumberOfWaveOutBuffers() == 1) { | |
98 set_error(!CompareExistingIfNotNULL(1, dest)); | |
99 } else { | |
100 set_error(!CompareExistingIfNotNULL(0, dest)); | |
101 } | |
102 if (callback_count() > kMaxNumBuffers) { | |
103 set_error(buffer_address_[0] == buffer_address_[1]); | |
104 set_error(buffer_address_[1] == buffer_address_[2]); | |
105 } | |
106 return max_size; | |
107 } | |
108 | |
109 private: | |
110 bool CompareExistingIfNotNULL(uint32 index, void* address) { | |
111 void*& entry = buffer_address_[index]; | |
112 if (!entry) | |
113 entry = address; | |
114 return (entry == address); | |
115 } | |
116 | |
117 void* buffer_address_[kMaxNumBuffers]; | |
118 }; | |
119 | |
120 // Specializes TestSourceBasic to simulate a source that blocks for some time | 80 // Specializes TestSourceBasic to simulate a source that blocks for some time |
121 // in the OnMoreData callback. | 81 // in the OnMoreData callback. |
122 class TestSourceLaggy : public TestSourceBasic { | 82 class TestSourceLaggy : public TestSourceBasic { |
123 public: | 83 public: |
124 TestSourceLaggy(int laggy_after_buffer, int lag_in_ms) | 84 TestSourceLaggy(int laggy_after_buffer, int lag_in_ms) |
125 : laggy_after_buffer_(laggy_after_buffer), lag_in_ms_(lag_in_ms) { | 85 : laggy_after_buffer_(laggy_after_buffer), lag_in_ms_(lag_in_ms) { |
126 } | 86 } |
127 virtual uint32 OnMoreData(uint8* dest, | 87 virtual int OnMoreData(AudioBus* audio_bus, |
128 uint32 max_size, | 88 AudioBuffersState buffers_state) { |
129 AudioBuffersState buffers_state) { | |
130 // Call the base, which increments the callback_count_. | 89 // Call the base, which increments the callback_count_. |
131 TestSourceBasic::OnMoreData(dest, max_size, buffers_state); | 90 TestSourceBasic::OnMoreData(audio_bus, buffers_state); |
132 if (callback_count() > kMaxNumBuffers) { | 91 if (callback_count() > kMaxNumBuffers) { |
133 ::Sleep(lag_in_ms_); | 92 ::Sleep(lag_in_ms_); |
134 } | 93 } |
135 return max_size; | 94 return audio_bus->frames(); |
136 } | 95 } |
137 private: | 96 private: |
138 int laggy_after_buffer_; | 97 int laggy_after_buffer_; |
139 int lag_in_ms_; | 98 int lag_in_ms_; |
140 }; | 99 }; |
141 | 100 |
142 class MockAudioSource : public AudioOutputStream::AudioSourceCallback { | 101 class MockAudioSource : public AudioOutputStream::AudioSourceCallback { |
143 public: | 102 public: |
144 MOCK_METHOD3(OnMoreData, uint32(uint8* dest, | 103 MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus, |
145 uint32 max_size, | 104 AudioBuffersState buffers_state)); |
146 AudioBuffersState buffers_state)); | |
147 MOCK_METHOD2(OnError, void(AudioOutputStream* stream, int code)); | 105 MOCK_METHOD2(OnError, void(AudioOutputStream* stream, int code)); |
| 106 |
| 107 static int ClearData(AudioBus* audio_bus, AudioBuffersState buffers_state) { |
| 108 audio_bus->Zero(); |
| 109 return audio_bus->frames(); |
| 110 } |
148 }; | 111 }; |
149 | 112 |
150 // Helper class to memory map an entire file. The mapping is read-only. Don't | 113 // Helper class to memory map an entire file. The mapping is read-only. Don't |
151 // use for gigabyte-sized files. Attempts to write to this memory generate | 114 // use for gigabyte-sized files. Attempts to write to this memory generate |
152 // memory access violations. | 115 // memory access violations. |
153 class ReadOnlyMappedFile { | 116 class ReadOnlyMappedFile { |
154 public: | 117 public: |
155 explicit ReadOnlyMappedFile(const wchar_t* file_name) | 118 explicit ReadOnlyMappedFile(const wchar_t* file_name) |
156 : fmap_(NULL), start_(NULL), size_(0) { | 119 : fmap_(NULL), start_(NULL), size_(0) { |
157 HANDLE file = ::CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, | 120 HANDLE file = ::CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 } | 251 } |
289 | 252 |
290 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( | 253 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( |
291 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, | 254 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, |
292 8000, 16, 1024 * 1024 * 1024)); | 255 8000, 16, 1024 * 1024 * 1024)); |
293 EXPECT_TRUE(NULL == oas); | 256 EXPECT_TRUE(NULL == oas); |
294 if (oas) | 257 if (oas) |
295 oas->Close(); | 258 oas->Close(); |
296 } | 259 } |
297 | 260 |
298 // Test that it uses the triple buffers correctly. Because it uses the actual | |
299 // audio device, you might hear a short pop noise for a short time. | |
300 TEST(WinAudioTest, PCMWaveStreamTripleBuffer) { | |
301 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); | |
302 if (!audio_man->HasAudioOutputDevices()) { | |
303 LOG(WARNING) << "No output device detected."; | |
304 return; | |
305 } | |
306 | |
307 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( | |
308 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, | |
309 16000, 16, 256)); | |
310 ASSERT_TRUE(NULL != oas); | |
311 TestSourceTripleBuffer test_triple_buffer; | |
312 EXPECT_TRUE(oas->Open()); | |
313 oas->Start(&test_triple_buffer); | |
314 ::Sleep(300); | |
315 EXPECT_GT(test_triple_buffer.callback_count(), kMaxNumBuffers); | |
316 EXPECT_FALSE(test_triple_buffer.had_error()); | |
317 oas->Stop(); | |
318 ::Sleep(500); | |
319 oas->Close(); | |
320 } | |
321 | |
322 // Test potential deadlock situation if the source is slow or blocks for some | 261 // Test potential deadlock situation if the source is slow or blocks for some |
323 // time. The actual EXPECT_GT are mostly meaningless and the real test is that | 262 // time. The actual EXPECT_GT are mostly meaningless and the real test is that |
324 // the test completes in reasonable time. | 263 // the test completes in reasonable time. |
325 TEST(WinAudioTest, PCMWaveSlowSource) { | 264 TEST(WinAudioTest, PCMWaveSlowSource) { |
326 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); | 265 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); |
327 if (!audio_man->HasAudioOutputDevices()) { | 266 if (!audio_man->HasAudioOutputDevices()) { |
328 LOG(WARNING) << "No output device detected."; | 267 LOG(WARNING) << "No output device detected."; |
329 return; | 268 return; |
330 } | 269 } |
331 | 270 |
(...skipping 23 matching lines...) Expand all Loading... |
355 LOG(WARNING) << "No output device detected."; | 294 LOG(WARNING) << "No output device detected."; |
356 return; | 295 return; |
357 } | 296 } |
358 | 297 |
359 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; | 298 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; |
360 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( | 299 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( |
361 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, | 300 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, |
362 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); | 301 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); |
363 ASSERT_TRUE(NULL != oas); | 302 ASSERT_TRUE(NULL != oas); |
364 | 303 |
365 SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1, | 304 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); |
366 200.0, AudioParameters::kAudioCDSampleRate); | |
367 | 305 |
368 EXPECT_TRUE(oas->Open()); | 306 EXPECT_TRUE(oas->Open()); |
369 oas->SetVolume(1.0); | 307 oas->SetVolume(1.0); |
370 | 308 |
371 for (int ix = 0; ix != 5; ++ix) { | 309 for (int ix = 0; ix != 5; ++ix) { |
372 oas->Start(&source); | 310 oas->Start(&source); |
373 ::Sleep(10); | 311 ::Sleep(10); |
374 oas->Stop(); | 312 oas->Stop(); |
375 } | 313 } |
376 oas->Close(); | 314 oas->Close(); |
377 } | 315 } |
378 | 316 |
379 | 317 |
380 // This test produces actual audio for .5 seconds on the default wave | 318 // This test produces actual audio for .5 seconds on the default wave |
381 // device at 44.1K s/sec. Parameters have been chosen carefully so you should | 319 // device at 44.1K s/sec. Parameters have been chosen carefully so you should |
382 // not hear pops or noises while the sound is playing. | 320 // not hear pops or noises while the sound is playing. |
383 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) { | 321 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) { |
384 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); | 322 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); |
385 if (!audio_man->HasAudioOutputDevices()) { | 323 if (!audio_man->HasAudioOutputDevices()) { |
386 LOG(WARNING) << "No output device detected."; | 324 LOG(WARNING) << "No output device detected."; |
387 return; | 325 return; |
388 } | 326 } |
389 | 327 |
390 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; | 328 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; |
391 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( | 329 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( |
392 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, | 330 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, |
393 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); | 331 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); |
394 ASSERT_TRUE(NULL != oas); | 332 ASSERT_TRUE(NULL != oas); |
395 | 333 |
396 SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1, | 334 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); |
397 200.0, AudioParameters::kAudioCDSampleRate); | |
398 | 335 |
399 EXPECT_TRUE(oas->Open()); | 336 EXPECT_TRUE(oas->Open()); |
400 oas->SetVolume(1.0); | 337 oas->SetVolume(1.0); |
401 oas->Start(&source); | 338 oas->Start(&source); |
402 ::Sleep(500); | 339 ::Sleep(500); |
403 oas->Stop(); | 340 oas->Stop(); |
404 oas->Close(); | 341 oas->Close(); |
405 } | 342 } |
406 | 343 |
407 // This test produces actual audio for for .5 seconds on the default wave | 344 // This test produces actual audio for for .5 seconds on the default wave |
408 // device at 22K s/sec. Parameters have been chosen carefully so you should | 345 // device at 22K s/sec. Parameters have been chosen carefully so you should |
409 // not hear pops or noises while the sound is playing. The audio also should | 346 // not hear pops or noises while the sound is playing. The audio also should |
410 // sound with a lower volume than PCMWaveStreamPlay200HzTone44Kss. | 347 // sound with a lower volume than PCMWaveStreamPlay200HzTone44Kss. |
411 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) { | 348 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) { |
412 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); | 349 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); |
413 if (!audio_man->HasAudioOutputDevices()) { | 350 if (!audio_man->HasAudioOutputDevices()) { |
414 LOG(WARNING) << "No output device detected."; | 351 LOG(WARNING) << "No output device detected."; |
415 return; | 352 return; |
416 } | 353 } |
417 | 354 |
418 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 20; | 355 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 20; |
419 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( | 356 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( |
420 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, | 357 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, |
421 AudioParameters::kAudioCDSampleRate / 2, 16, | 358 AudioParameters::kAudioCDSampleRate / 2, 16, |
422 samples_100_ms)); | 359 samples_100_ms)); |
423 ASSERT_TRUE(NULL != oas); | 360 ASSERT_TRUE(NULL != oas); |
424 | 361 |
425 SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1, | 362 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2); |
426 200.0, AudioParameters::kAudioCDSampleRate/2); | |
427 | 363 |
428 EXPECT_TRUE(oas->Open()); | 364 EXPECT_TRUE(oas->Open()); |
429 | 365 |
430 oas->SetVolume(0.5); | 366 oas->SetVolume(0.5); |
431 oas->Start(&source); | 367 oas->Start(&source); |
432 ::Sleep(500); | 368 ::Sleep(500); |
433 | 369 |
434 // Test that the volume is within the set limits. | 370 // Test that the volume is within the set limits. |
435 double volume = 0.0; | 371 double volume = 0.0; |
436 oas->GetVolume(&volume); | 372 oas->GetVolume(&volume); |
437 EXPECT_LT(volume, 0.51); | 373 EXPECT_LT(volume, 0.51); |
438 EXPECT_GT(volume, 0.49); | 374 EXPECT_GT(volume, 0.49); |
439 oas->Stop(); | 375 oas->Stop(); |
440 oas->Close(); | 376 oas->Close(); |
441 } | 377 } |
442 | 378 |
443 // Uses the PushSource to play a 2 seconds file clip for about 5 seconds. We | 379 // Uses a restricted source to play ~2 seconds of audio for about 5 seconds. We |
444 // try hard to generate situation where the two threads are accessing the | 380 // try hard to generate situation where the two threads are accessing the |
445 // object roughly at the same time. What you hear is a sweeping tone from 1KHz | 381 // object roughly at the same time. |
446 // to 2KHz with a bit of fade out at the end for one second. The file is two | |
447 // of these sweeping tones back to back. | |
448 TEST(WinAudioTest, PushSourceFile16KHz) { | 382 TEST(WinAudioTest, PushSourceFile16KHz) { |
449 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); | 383 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); |
450 if (!audio_man->HasAudioOutputDevices()) { | 384 if (!audio_man->HasAudioOutputDevices()) { |
451 LOG(WARNING) << "No output device detected."; | 385 LOG(WARNING) << "No output device detected."; |
452 return; | 386 return; |
453 } | 387 } |
454 | 388 |
455 // Open sweep02_16b_mono_16KHz.raw which has no format. It contains the | 389 static const int kSampleRate = 16000; |
456 // raw 16 bit samples for a single channel in little-endian format. The | 390 SineWaveAudioSource source(1, 200.0, kSampleRate); |
457 // creation sample rate is 16KHz. | |
458 FilePath audio_file; | |
459 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &audio_file)); | |
460 audio_file = audio_file.Append(kAudioFile1_16b_m_16K); | |
461 // Map the entire file in memory. | |
462 ReadOnlyMappedFile file_reader(audio_file.value().c_str()); | |
463 ASSERT_TRUE(file_reader.is_valid()); | |
464 | |
465 // Compute buffer size for 100ms of audio. | 391 // Compute buffer size for 100ms of audio. |
466 const uint32 kSamples100ms = (16000 / 1000) * 100; | 392 const uint32 kSamples100ms = (kSampleRate / 1000) * 100; |
467 const uint32 kSize100ms = kSamples100ms * 2; | 393 // Restrict SineWaveAudioSource to 100ms of samples. |
| 394 source.CapSamples(kSamples100ms); |
468 | 395 |
469 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( | 396 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( |
470 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, | 397 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, |
471 16000, 16, kSamples100ms)); | 398 kSampleRate, 16, kSamples100ms)); |
472 ASSERT_TRUE(NULL != oas); | 399 ASSERT_TRUE(NULL != oas); |
473 | 400 |
474 EXPECT_TRUE(oas->Open()); | 401 EXPECT_TRUE(oas->Open()); |
475 | 402 |
476 uint32 offset = 0; | 403 oas->SetVolume(1.0); |
477 const uint32 kMaxStartOffset = file_reader.size() - kSize100ms; | 404 oas->Start(&source); |
478 | 405 |
479 // We buffer and play at the same time, buffering happens every ~10ms and the | 406 // We buffer and play at the same time, buffering happens every ~10ms and the |
480 // consuming of the buffer happens every ~100ms. We do 100 buffers which | 407 // consuming of the buffer happens every ~100ms. We do 100 buffers which |
481 // effectively wrap around the file more than once. | 408 // effectively wrap around the file more than once. |
482 PushSource push_source; | |
483 for (uint32 ix = 0; ix != 100; ++ix) { | 409 for (uint32 ix = 0; ix != 100; ++ix) { |
484 push_source.Write(file_reader.GetChunkAt(offset), kSize100ms); | |
485 if (ix == 2) { | |
486 // For glitch free, start playing after some buffers are in. | |
487 oas->Start(&push_source); | |
488 } | |
489 ::Sleep(10); | 410 ::Sleep(10); |
490 offset += kSize100ms; | 411 source.Reset(); |
491 if (offset > kMaxStartOffset) | |
492 offset = 0; | |
493 } | 412 } |
494 | 413 |
495 // Play a little bit more of the file. | 414 // Play a little bit more of the file. |
496 ::Sleep(500); | 415 ::Sleep(500); |
497 | 416 |
498 oas->Stop(); | 417 oas->Stop(); |
499 oas->Close(); | 418 oas->Close(); |
500 } | 419 } |
501 | 420 |
502 // This test is to make sure an AudioOutputStream can be started after it was | 421 // This test is to make sure an AudioOutputStream can be started after it was |
503 // stopped. You will here two .5 seconds wave signal separated by 0.5 seconds | 422 // stopped. You will here two .5 seconds wave signal separated by 0.5 seconds |
504 // of silence. | 423 // of silence. |
505 TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) { | 424 TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) { |
506 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); | 425 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); |
507 if (!audio_man->HasAudioOutputDevices()) { | 426 if (!audio_man->HasAudioOutputDevices()) { |
508 LOG(WARNING) << "No output device detected."; | 427 LOG(WARNING) << "No output device detected."; |
509 return; | 428 return; |
510 } | 429 } |
511 | 430 |
512 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; | 431 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; |
513 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( | 432 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( |
514 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, | 433 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, |
515 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); | 434 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); |
516 ASSERT_TRUE(NULL != oas); | 435 ASSERT_TRUE(NULL != oas); |
517 | 436 |
518 SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1, | 437 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); |
519 200.0, AudioParameters::kAudioCDSampleRate); | |
520 EXPECT_TRUE(oas->Open()); | 438 EXPECT_TRUE(oas->Open()); |
521 oas->SetVolume(1.0); | 439 oas->SetVolume(1.0); |
522 | 440 |
523 // Play the wave for .5 seconds. | 441 // Play the wave for .5 seconds. |
524 oas->Start(&source); | 442 oas->Start(&source); |
525 ::Sleep(500); | 443 ::Sleep(500); |
526 oas->Stop(); | 444 oas->Stop(); |
527 | 445 |
528 // Sleep to give silence after stopping the AudioOutputStream. | 446 // Sleep to give silence after stopping the AudioOutputStream. |
529 ::Sleep(250); | 447 ::Sleep(250); |
(...skipping 24 matching lines...) Expand all Loading... |
554 int sample_rate = static_cast<int>(media::GetAudioHardwareSampleRate()); | 472 int sample_rate = static_cast<int>(media::GetAudioHardwareSampleRate()); |
555 uint32 samples_10_ms = sample_rate / 100; | 473 uint32 samples_10_ms = sample_rate / 100; |
556 int n = 1; | 474 int n = 1; |
557 (base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1; | 475 (base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1; |
558 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( | 476 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( |
559 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, | 477 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
560 CHANNEL_LAYOUT_MONO, sample_rate, | 478 CHANNEL_LAYOUT_MONO, sample_rate, |
561 16, n * samples_10_ms)); | 479 16, n * samples_10_ms)); |
562 ASSERT_TRUE(NULL != oas); | 480 ASSERT_TRUE(NULL != oas); |
563 | 481 |
564 SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1, | 482 SineWaveAudioSource source(1, 200, sample_rate); |
565 200.0, sample_rate); | |
566 | 483 |
567 bool opened = oas->Open(); | 484 bool opened = oas->Open(); |
568 if (!opened) { | 485 if (!opened) { |
569 // It was not possible to open this audio device in mono. | 486 // It was not possible to open this audio device in mono. |
570 // No point in continuing the test so let's break here. | 487 // No point in continuing the test so let's break here. |
571 LOG(WARNING) << "Mono is not supported. Skipping test."; | 488 LOG(WARNING) << "Mono is not supported. Skipping test."; |
572 oas->Close(); | 489 oas->Close(); |
573 return; | 490 return; |
574 } | 491 } |
575 oas->SetVolume(1.0); | 492 oas->SetVolume(1.0); |
(...skipping 25 matching lines...) Expand all Loading... |
601 uint32 bytes_100_ms = samples_100_ms * 2; | 518 uint32 bytes_100_ms = samples_100_ms * 2; |
602 | 519 |
603 // Audio output stream has either a double or triple buffer scheme. | 520 // Audio output stream has either a double or triple buffer scheme. |
604 // We expect the amount of pending bytes will reaching up to 2 times of | 521 // We expect the amount of pending bytes will reaching up to 2 times of |
605 // |bytes_100_ms| depending on number of buffers used. | 522 // |bytes_100_ms| depending on number of buffers used. |
606 // From that it would decrease as we are playing the data but not providing | 523 // From that it would decrease as we are playing the data but not providing |
607 // new one. And then we will try to provide zero data so the amount of | 524 // new one. And then we will try to provide zero data so the amount of |
608 // pending bytes will go down and eventually read zero. | 525 // pending bytes will go down and eventually read zero. |
609 InSequence s; | 526 InSequence s; |
610 | 527 |
611 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, | 528 EXPECT_CALL(source, OnMoreData(NotNull(), |
612 Field(&AudioBuffersState::pending_bytes, 0))) | 529 Field(&AudioBuffersState::pending_bytes, 0))) |
613 .WillOnce(Return(bytes_100_ms)); | 530 .WillOnce(Invoke(MockAudioSource::ClearData)); |
614 switch (NumberOfWaveOutBuffers()) { | 531 switch (NumberOfWaveOutBuffers()) { |
615 case 2: | 532 case 2: |
616 break; // Calls are the same as at end of 3-buffer scheme. | 533 break; // Calls are the same as at end of 3-buffer scheme. |
617 case 3: | 534 case 3: |
618 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, | 535 EXPECT_CALL(source, OnMoreData(NotNull(), |
619 Field(&AudioBuffersState::pending_bytes, | 536 Field(&AudioBuffersState::pending_bytes, |
620 bytes_100_ms))) | 537 bytes_100_ms))) |
621 .WillOnce(Return(bytes_100_ms)); | 538 .WillOnce(Invoke(MockAudioSource::ClearData)); |
622 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, | 539 EXPECT_CALL(source, OnMoreData(NotNull(), |
623 Field(&AudioBuffersState::pending_bytes, | 540 Field(&AudioBuffersState::pending_bytes, |
624 2 * bytes_100_ms))) | 541 2 * bytes_100_ms))) |
625 .WillOnce(Return(bytes_100_ms)); | 542 .WillOnce(Invoke(MockAudioSource::ClearData)); |
626 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, | 543 EXPECT_CALL(source, OnMoreData(NotNull(), |
627 Field(&AudioBuffersState::pending_bytes, | 544 Field(&AudioBuffersState::pending_bytes, |
628 2 * bytes_100_ms))) | 545 2 * bytes_100_ms))) |
629 .Times(AnyNumber()) | 546 .Times(AnyNumber()) |
630 .WillRepeatedly(Return(0)); | 547 .WillRepeatedly(Return(0)); |
631 break; | 548 break; |
632 default: | 549 default: |
633 ASSERT_TRUE(false) << "Unexpected number of buffers"; | 550 ASSERT_TRUE(false) |
| 551 << "Unexpected number of buffers: " << NumberOfWaveOutBuffers(); |
634 } | 552 } |
635 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, | 553 EXPECT_CALL(source, OnMoreData(NotNull(), |
636 Field(&AudioBuffersState::pending_bytes, | 554 Field(&AudioBuffersState::pending_bytes, |
637 bytes_100_ms))) | 555 bytes_100_ms))) |
638 .Times(AnyNumber()) | 556 .Times(AnyNumber()) |
639 .WillRepeatedly(Return(0)); | 557 .WillRepeatedly(Return(0)); |
640 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, | 558 EXPECT_CALL(source, OnMoreData(NotNull(), |
641 Field(&AudioBuffersState::pending_bytes, 0))) | 559 Field(&AudioBuffersState::pending_bytes, 0))) |
642 .Times(AnyNumber()) | 560 .Times(AnyNumber()) |
643 .WillRepeatedly(Return(0)); | 561 .WillRepeatedly(Return(0)); |
644 | 562 |
645 oas->Start(&source); | 563 oas->Start(&source); |
646 ::Sleep(500); | 564 ::Sleep(500); |
647 oas->Stop(); | 565 oas->Stop(); |
648 oas->Close(); | 566 oas->Close(); |
649 } | 567 } |
650 | 568 |
651 // Simple source that uses a SyncSocket to retrieve the audio data | 569 // Simple source that uses a SyncSocket to retrieve the audio data |
652 // from a potentially remote thread. | 570 // from a potentially remote thread. |
653 class SyncSocketSource : public AudioOutputStream::AudioSourceCallback { | 571 class SyncSocketSource : public AudioOutputStream::AudioSourceCallback { |
654 public: | 572 public: |
655 explicit SyncSocketSource(base::SyncSocket* socket) | 573 SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params) |
656 : socket_(socket) {} | 574 : socket_(socket) { |
657 | 575 // Setup AudioBus wrapping data we'll receive over the sync socket. |
658 ~SyncSocketSource() { | 576 data_size_ = AudioBus::CalculateMemorySize(params); |
| 577 data_.reset(static_cast<float*>( |
| 578 base::AlignedAlloc(data_size_, AudioBus::kChannelAlignment))); |
| 579 audio_bus_ = AudioBus::WrapMemory(params, data_.get()); |
659 } | 580 } |
| 581 ~SyncSocketSource() {} |
660 | 582 |
661 // AudioSourceCallback::OnMoreData implementation: | 583 // AudioSourceCallback::OnMoreData implementation: |
662 virtual uint32 OnMoreData(uint8* dest, | 584 virtual int OnMoreData(AudioBus* audio_bus, |
663 uint32 max_size, | 585 AudioBuffersState buffers_state) { |
664 AudioBuffersState buffers_state) { | |
665 socket_->Send(&buffers_state, sizeof(buffers_state)); | 586 socket_->Send(&buffers_state, sizeof(buffers_state)); |
666 uint32 got = socket_->Receive(dest, max_size); | 587 uint32 size = socket_->Receive(data_.get(), data_size_); |
667 return got; | 588 DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U); |
| 589 audio_bus_->CopyTo(audio_bus); |
| 590 return audio_bus_->frames(); |
668 } | 591 } |
669 // AudioSourceCallback::OnError implementation: | 592 // AudioSourceCallback::OnError implementation: |
670 virtual void OnError(AudioOutputStream* stream, int code) { | 593 virtual void OnError(AudioOutputStream* stream, int code) { |
671 } | 594 } |
672 | 595 |
673 private: | 596 private: |
674 base::SyncSocket* socket_; | 597 base::SyncSocket* socket_; |
| 598 int data_size_; |
| 599 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data_; |
| 600 scoped_ptr<AudioBus> audio_bus_; |
675 }; | 601 }; |
676 | 602 |
677 struct SyncThreadContext { | 603 struct SyncThreadContext { |
678 base::SyncSocket* socket; | 604 base::SyncSocket* socket; |
679 int sample_rate; | 605 int sample_rate; |
| 606 int channels; |
| 607 int frames; |
680 double sine_freq; | 608 double sine_freq; |
681 uint32 packet_size_bytes; | 609 uint32 packet_size_bytes; |
682 }; | 610 }; |
683 | 611 |
684 // This thread provides the data that the SyncSocketSource above needs | 612 // This thread provides the data that the SyncSocketSource above needs |
685 // using the other end of a SyncSocket. The protocol is as follows: | 613 // using the other end of a SyncSocket. The protocol is as follows: |
686 // | 614 // |
687 // SyncSocketSource ---send 4 bytes ------------> SyncSocketThread | 615 // SyncSocketSource ---send 4 bytes ------------> SyncSocketThread |
688 // <--- audio packet ---------- | 616 // <--- audio packet ---------- |
689 // | 617 // |
690 DWORD __stdcall SyncSocketThread(void* context) { | 618 DWORD __stdcall SyncSocketThread(void* context) { |
691 SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context)); | 619 SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context)); |
692 | 620 |
693 const int kTwoSecBytes = | 621 // Setup AudioBus wrapping data we'll pass over the sync socket. |
694 AudioParameters::kAudioCDSampleRate * 2 * sizeof(uint16); // NOLINT | 622 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data(static_cast<float*>( |
695 uint8* buffer = new uint8[kTwoSecBytes]; | 623 base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment))); |
696 SineWaveAudioSource sine(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, | 624 scoped_ptr<AudioBus> audio_bus = AudioBus::WrapMemory( |
697 1, ctx.sine_freq, ctx.sample_rate); | 625 ctx.channels, ctx.frames, data.get()); |
698 sine.OnMoreData(buffer, kTwoSecBytes, AudioBuffersState()); | 626 |
| 627 SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate); |
| 628 const int kTwoSecFrames = ctx.sample_rate * 2; |
699 | 629 |
700 AudioBuffersState buffers_state; | 630 AudioBuffersState buffers_state; |
701 int times = 0; | 631 int times = 0; |
702 for (int ix = 0; ix < kTwoSecBytes; ix += ctx.packet_size_bytes) { | 632 for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) { |
703 if (ctx.socket->Receive(&buffers_state, sizeof(buffers_state)) == 0) | 633 if (ctx.socket->Receive(&buffers_state, sizeof(buffers_state)) == 0) |
704 break; | 634 break; |
705 if ((times > 0) && (buffers_state.pending_bytes < 1000)) __debugbreak(); | 635 if ((times > 0) && (buffers_state.pending_bytes < 1000)) __debugbreak(); |
706 ctx.socket->Send(&buffer[ix], ctx.packet_size_bytes); | 636 sine.OnMoreData(audio_bus.get(), buffers_state); |
| 637 ctx.socket->Send(data.get(), ctx.packet_size_bytes); |
707 ++times; | 638 ++times; |
708 } | 639 } |
709 | 640 |
710 delete buffer; | |
711 return 0; | 641 return 0; |
712 } | 642 } |
713 | 643 |
714 // Test the basic operation of AudioOutputStream used with a SyncSocket. | 644 // Test the basic operation of AudioOutputStream used with a SyncSocket. |
715 // The emphasis is to verify that it is possible to feed data to the audio | 645 // The emphasis is to verify that it is possible to feed data to the audio |
716 // layer using a source based on SyncSocket. In a real situation we would | 646 // layer using a source based on SyncSocket. In a real situation we would |
717 // go for the low-latency version in combination with SyncSocket, but to keep | 647 // go for the low-latency version in combination with SyncSocket, but to keep |
718 // the test more simple, AUDIO_PCM_LINEAR is utilized instead. The main | 648 // the test more simple, AUDIO_PCM_LINEAR is utilized instead. The main |
719 // principle of the test still remains and we avoid the additional complexity | 649 // principle of the test still remains and we avoid the additional complexity |
720 // related to the two different audio-layers for AUDIO_PCM_LOW_LATENCY. | 650 // related to the two different audio-layers for AUDIO_PCM_LOW_LATENCY. |
721 // In this test you should hear a continuous 200Hz tone for 2 seconds. | 651 // In this test you should hear a continuous 200Hz tone for 2 seconds. |
722 TEST(WinAudioTest, SyncSocketBasic) { | 652 TEST(WinAudioTest, SyncSocketBasic) { |
723 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); | 653 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); |
724 if (!audio_man->HasAudioOutputDevices()) { | 654 if (!audio_man->HasAudioOutputDevices()) { |
725 LOG(WARNING) << "No output device detected."; | 655 LOG(WARNING) << "No output device detected."; |
726 return; | 656 return; |
727 } | 657 } |
728 | 658 |
729 int sample_rate = AudioParameters::kAudioCDSampleRate; | 659 static const int sample_rate = AudioParameters::kAudioCDSampleRate; |
730 const uint32 kSamples20ms = sample_rate / 50; | 660 static const uint32 kSamples20ms = sample_rate / 50; |
731 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( | 661 AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, |
732 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, | 662 CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms); |
733 CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms)); | 663 |
| 664 |
| 665 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params); |
734 ASSERT_TRUE(NULL != oas); | 666 ASSERT_TRUE(NULL != oas); |
735 | 667 |
736 ASSERT_TRUE(oas->Open()); | 668 ASSERT_TRUE(oas->Open()); |
737 | 669 |
738 base::SyncSocket sockets[2]; | 670 base::SyncSocket sockets[2]; |
739 ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1])); | 671 ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1])); |
740 | 672 |
741 SyncSocketSource source(&sockets[0]); | 673 SyncSocketSource source(&sockets[0], params); |
742 | 674 |
743 SyncThreadContext thread_context; | 675 SyncThreadContext thread_context; |
744 thread_context.sample_rate = sample_rate; | 676 thread_context.sample_rate = params.sample_rate(); |
745 thread_context.sine_freq = 200.0; | 677 thread_context.sine_freq = 200.0; |
746 thread_context.packet_size_bytes = kSamples20ms * 2; | 678 thread_context.packet_size_bytes = AudioBus::CalculateMemorySize(params); |
| 679 thread_context.frames = params.frames_per_buffer(); |
| 680 thread_context.channels = params.channels(); |
747 thread_context.socket = &sockets[1]; | 681 thread_context.socket = &sockets[1]; |
748 | 682 |
749 HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread, | 683 HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread, |
750 &thread_context, 0, NULL); | 684 &thread_context, 0, NULL); |
751 | 685 |
752 oas->Start(&source); | 686 oas->Start(&source); |
753 | 687 |
754 ::WaitForSingleObject(thread, INFINITE); | 688 ::WaitForSingleObject(thread, INFINITE); |
755 ::CloseHandle(thread); | 689 ::CloseHandle(thread); |
756 | 690 |
757 oas->Stop(); | 691 oas->Stop(); |
758 oas->Close(); | 692 oas->Close(); |
759 } | 693 } |
760 | 694 |
761 } // namespace media | 695 } // namespace media |
OLD | NEW |