Report errors from ChromiumEnv::GetChildren in Posix.
[chromium-blink-merge.git] / media / audio / win / audio_output_win_unittest.cc
blobe9040e7f64ca5d4a2fbf3e11b47774f8c41a949e
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.
5 #include <windows.h>
6 #include <mmsystem.h>
8 #include "base/basictypes.h"
9 #include "base/base_paths.h"
10 #include "base/memory/aligned_memory.h"
11 #include "base/path_service.h"
12 #include "base/sync_socket.h"
13 #include "base/win/scoped_com_initializer.h"
14 #include "base/win/windows_version.h"
15 #include "media/base/limits.h"
16 #include "media/audio/audio_io.h"
17 #include "media/audio/audio_manager.h"
18 #include "media/audio/simple_sources.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using ::testing::_;
23 using ::testing::AnyNumber;
24 using ::testing::DoAll;
25 using ::testing::Field;
26 using ::testing::Invoke;
27 using ::testing::InSequence;
28 using ::testing::NiceMock;
29 using ::testing::NotNull;
30 using ::testing::Return;
32 using base::win::ScopedCOMInitializer;
34 namespace media {
36 static const wchar_t kAudioFile1_16b_m_16K[]
37 = L"media\\test\\data\\sweep02_16b_mono_16KHz.raw";
39 // This class allows to find out if the callbacks are occurring as
40 // expected and if any error has been reported.
41 class TestSourceBasic : public AudioOutputStream::AudioSourceCallback {
42 public:
43 explicit TestSourceBasic()
44 : callback_count_(0),
45 had_error_(0) {
47 // AudioSourceCallback::OnMoreData implementation:
48 virtual int OnMoreData(AudioBus* audio_bus,
49 AudioBuffersState buffers_state) {
50 ++callback_count_;
51 // Touch the channel memory value to make sure memory is good.
52 audio_bus->Zero();
53 return audio_bus->frames();
55 virtual int OnMoreIOData(AudioBus* source,
56 AudioBus* dest,
57 AudioBuffersState buffers_state) {
58 NOTREACHED();
59 return 0;
61 // AudioSourceCallback::OnError implementation:
62 virtual void OnError(AudioOutputStream* stream) {
63 ++had_error_;
65 // Returns how many times OnMoreData() has been called.
66 int callback_count() const {
67 return callback_count_;
69 // Returns how many times the OnError callback was called.
70 int had_error() const {
71 return had_error_;
74 void set_error(bool error) {
75 had_error_ += error ? 1 : 0;
78 private:
79 int callback_count_;
80 int had_error_;
83 const int kMaxNumBuffers = 3;
84 // Specializes TestSourceBasic to simulate a source that blocks for some time
85 // in the OnMoreData callback.
86 class TestSourceLaggy : public TestSourceBasic {
87 public:
88 TestSourceLaggy(int laggy_after_buffer, int lag_in_ms)
89 : laggy_after_buffer_(laggy_after_buffer), lag_in_ms_(lag_in_ms) {
91 virtual int OnMoreData(AudioBus* audio_bus,
92 AudioBuffersState buffers_state) {
93 // Call the base, which increments the callback_count_.
94 TestSourceBasic::OnMoreData(audio_bus, buffers_state);
95 if (callback_count() > kMaxNumBuffers) {
96 ::Sleep(lag_in_ms_);
98 return audio_bus->frames();
100 private:
101 int laggy_after_buffer_;
102 int lag_in_ms_;
105 class MockAudioSource : public AudioOutputStream::AudioSourceCallback {
106 public:
107 MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus,
108 AudioBuffersState buffers_state));
109 MOCK_METHOD3(OnMoreIOData, int(AudioBus* source,
110 AudioBus* dest,
111 AudioBuffersState buffers_state));
112 MOCK_METHOD1(OnError, void(AudioOutputStream* stream));
114 static int ClearData(AudioBus* audio_bus, AudioBuffersState buffers_state) {
115 audio_bus->Zero();
116 return audio_bus->frames();
120 // Helper class to memory map an entire file. The mapping is read-only. Don't
121 // use for gigabyte-sized files. Attempts to write to this memory generate
122 // memory access violations.
123 class ReadOnlyMappedFile {
124 public:
125 explicit ReadOnlyMappedFile(const wchar_t* file_name)
126 : fmap_(NULL), start_(NULL), size_(0) {
127 HANDLE file = ::CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
128 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
129 if (INVALID_HANDLE_VALUE == file)
130 return;
131 fmap_ = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
132 ::CloseHandle(file);
133 if (!fmap_)
134 return;
135 start_ = reinterpret_cast<char*>(::MapViewOfFile(fmap_, FILE_MAP_READ,
136 0, 0, 0));
137 if (!start_)
138 return;
139 MEMORY_BASIC_INFORMATION mbi = {0};
140 ::VirtualQuery(start_, &mbi, sizeof(mbi));
141 size_ = mbi.RegionSize;
143 ~ReadOnlyMappedFile() {
144 if (start_) {
145 ::UnmapViewOfFile(start_);
146 ::CloseHandle(fmap_);
149 // Returns true if the file was successfully mapped.
150 bool is_valid() const {
151 return ((start_ > 0) && (size_ > 0));
153 // Returns the size in bytes of the mapped memory.
154 uint32 size() const {
155 return size_;
157 // Returns the memory backing the file.
158 const void* GetChunkAt(uint32 offset) {
159 return &start_[offset];
162 private:
163 HANDLE fmap_;
164 char* start_;
165 uint32 size_;
168 // ===========================================================================
169 // Validation of AudioManager::AUDIO_PCM_LINEAR
171 // NOTE:
172 // The tests can fail on the build bots when somebody connects to them via
173 // remote-desktop and the rdp client installs an audio device that fails to open
174 // at some point, possibly when the connection goes idle.
176 // Test that can it be created and closed.
177 TEST(WinAudioTest, PCMWaveStreamGetAndClose) {
178 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
179 if (!audio_man->HasAudioOutputDevices()) {
180 LOG(WARNING) << "No output device detected.";
181 return;
184 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
185 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
186 8000, 16, 256),
187 std::string(), std::string());
188 ASSERT_TRUE(NULL != oas);
189 oas->Close();
192 // Test that can it be cannot be created with invalid parameters.
193 TEST(WinAudioTest, SanityOnMakeParams) {
194 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
195 if (!audio_man->HasAudioOutputDevices()) {
196 LOG(WARNING) << "No output device detected.";
197 return;
200 AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR;
201 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
202 AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
203 std::string(), std::string()));
204 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
205 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256),
206 std::string(), std::string()));
207 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
208 AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256),
209 std::string(), std::string()));
210 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
211 AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
212 std::string(), std::string()));
213 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
214 AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256),
215 std::string(), std::string()));
216 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
217 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100),
218 std::string(), std::string()));
219 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
220 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0),
221 std::string(), std::string()));
222 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
223 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16,
224 media::limits::kMaxSamplesPerPacket + 1),
225 std::string(), std::string()));
228 // Test that it can be opened and closed.
229 TEST(WinAudioTest, PCMWaveStreamOpenAndClose) {
230 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
231 if (!audio_man->HasAudioOutputDevices()) {
232 LOG(WARNING) << "No output device detected.";
233 return;
236 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
237 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
238 8000, 16, 256),
239 std::string(), std::string());
240 ASSERT_TRUE(NULL != oas);
241 EXPECT_TRUE(oas->Open());
242 oas->Close();
245 // Test that it has a maximum packet size.
246 TEST(WinAudioTest, PCMWaveStreamOpenLimit) {
247 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
248 if (!audio_man->HasAudioOutputDevices()) {
249 LOG(WARNING) << "No output device detected.";
250 return;
253 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
254 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
255 8000, 16, 1024 * 1024 * 1024),
256 std::string(), std::string());
257 EXPECT_TRUE(NULL == oas);
258 if (oas)
259 oas->Close();
262 // Test potential deadlock situation if the source is slow or blocks for some
263 // time. The actual EXPECT_GT are mostly meaningless and the real test is that
264 // the test completes in reasonable time.
265 TEST(WinAudioTest, PCMWaveSlowSource) {
266 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
267 if (!audio_man->HasAudioOutputDevices()) {
268 LOG(WARNING) << "No output device detected.";
269 return;
272 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
273 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
274 16000, 16, 256),
275 std::string(), std::string());
276 ASSERT_TRUE(NULL != oas);
277 TestSourceLaggy test_laggy(2, 90);
278 EXPECT_TRUE(oas->Open());
279 // The test parameters cause a callback every 32 ms and the source is
280 // sleeping for 90 ms, so it is guaranteed that we run out of ready buffers.
281 oas->Start(&test_laggy);
282 ::Sleep(500);
283 EXPECT_GT(test_laggy.callback_count(), 2);
284 EXPECT_FALSE(test_laggy.had_error());
285 oas->Stop();
286 ::Sleep(500);
287 oas->Close();
290 // Test another potential deadlock situation if the thread that calls Start()
291 // gets paused. This test is best when run over RDP with audio enabled. See
292 // bug 19276 for more details.
293 TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) {
294 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
295 if (!audio_man->HasAudioOutputDevices()) {
296 LOG(WARNING) << "No output device detected.";
297 return;
300 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
301 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
302 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
303 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
304 std::string(), std::string());
305 ASSERT_TRUE(NULL != oas);
307 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
309 EXPECT_TRUE(oas->Open());
310 oas->SetVolume(1.0);
312 for (int ix = 0; ix != 5; ++ix) {
313 oas->Start(&source);
314 ::Sleep(10);
315 oas->Stop();
317 oas->Close();
321 // This test produces actual audio for .5 seconds on the default wave
322 // device at 44.1K s/sec. Parameters have been chosen carefully so you should
323 // not hear pops or noises while the sound is playing.
324 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
325 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
326 if (!audio_man->HasAudioOutputDevices()) {
327 LOG(WARNING) << "No output device detected.";
328 return;
331 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
332 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
333 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
334 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
335 std::string(), std::string());
336 ASSERT_TRUE(NULL != oas);
338 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
340 EXPECT_TRUE(oas->Open());
341 oas->SetVolume(1.0);
342 oas->Start(&source);
343 ::Sleep(500);
344 oas->Stop();
345 oas->Close();
348 // This test produces actual audio for for .5 seconds on the default wave
349 // device at 22K s/sec. Parameters have been chosen carefully so you should
350 // not hear pops or noises while the sound is playing. The audio also should
351 // sound with a lower volume than PCMWaveStreamPlay200HzTone44Kss.
352 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
353 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
354 if (!audio_man->HasAudioOutputDevices()) {
355 LOG(WARNING) << "No output device detected.";
356 return;
359 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 20;
360 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
361 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
362 AudioParameters::kAudioCDSampleRate / 2, 16,
363 samples_100_ms),
364 std::string(), std::string());
365 ASSERT_TRUE(NULL != oas);
367 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2);
369 EXPECT_TRUE(oas->Open());
371 oas->SetVolume(0.5);
372 oas->Start(&source);
373 ::Sleep(500);
375 // Test that the volume is within the set limits.
376 double volume = 0.0;
377 oas->GetVolume(&volume);
378 EXPECT_LT(volume, 0.51);
379 EXPECT_GT(volume, 0.49);
380 oas->Stop();
381 oas->Close();
384 // Uses a restricted source to play ~2 seconds of audio for about 5 seconds. We
385 // try hard to generate situation where the two threads are accessing the
386 // object roughly at the same time.
387 TEST(WinAudioTest, PushSourceFile16KHz) {
388 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
389 if (!audio_man->HasAudioOutputDevices()) {
390 LOG(WARNING) << "No output device detected.";
391 return;
394 static const int kSampleRate = 16000;
395 SineWaveAudioSource source(1, 200.0, kSampleRate);
396 // Compute buffer size for 100ms of audio.
397 const uint32 kSamples100ms = (kSampleRate / 1000) * 100;
398 // Restrict SineWaveAudioSource to 100ms of samples.
399 source.CapSamples(kSamples100ms);
401 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
402 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
403 kSampleRate, 16, kSamples100ms),
404 std::string(), std::string());
405 ASSERT_TRUE(NULL != oas);
407 EXPECT_TRUE(oas->Open());
409 oas->SetVolume(1.0);
410 oas->Start(&source);
412 // We buffer and play at the same time, buffering happens every ~10ms and the
413 // consuming of the buffer happens every ~100ms. We do 100 buffers which
414 // effectively wrap around the file more than once.
415 for (uint32 ix = 0; ix != 100; ++ix) {
416 ::Sleep(10);
417 source.Reset();
420 // Play a little bit more of the file.
421 ::Sleep(500);
423 oas->Stop();
424 oas->Close();
427 // This test is to make sure an AudioOutputStream can be started after it was
428 // stopped. You will here two .5 seconds wave signal separated by 0.5 seconds
429 // of silence.
430 TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
431 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
432 if (!audio_man->HasAudioOutputDevices()) {
433 LOG(WARNING) << "No output device detected.";
434 return;
437 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
438 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
439 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
440 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
441 std::string(), std::string());
442 ASSERT_TRUE(NULL != oas);
444 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
445 EXPECT_TRUE(oas->Open());
446 oas->SetVolume(1.0);
448 // Play the wave for .5 seconds.
449 oas->Start(&source);
450 ::Sleep(500);
451 oas->Stop();
453 // Sleep to give silence after stopping the AudioOutputStream.
454 ::Sleep(250);
456 // Start again and play for .5 seconds.
457 oas->Start(&source);
458 ::Sleep(500);
459 oas->Stop();
461 oas->Close();
464 // With the low latency mode, WASAPI is utilized by default for Vista and
465 // higher and Wave is used for XP and lower. It is possible to utilize a
466 // smaller buffer size for WASAPI than for Wave.
467 TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
468 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
469 if (!audio_man->HasAudioOutputDevices()) {
470 LOG(WARNING) << "No output device detected.";
471 return;
474 // The WASAPI API requires a correct COM environment.
475 ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
477 // Use 10 ms buffer size for WASAPI and 50 ms buffer size for Wave.
478 // Take the existing native sample rate into account.
479 const AudioParameters params = audio_man->GetDefaultOutputStreamParameters();
480 int sample_rate = params.sample_rate();
481 uint32 samples_10_ms = sample_rate / 100;
482 int n = 1;
483 (base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1;
484 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
485 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
486 CHANNEL_LAYOUT_MONO, sample_rate,
487 16, n * samples_10_ms),
488 std::string(), std::string());
489 ASSERT_TRUE(NULL != oas);
491 SineWaveAudioSource source(1, 200, sample_rate);
493 bool opened = oas->Open();
494 if (!opened) {
495 // It was not possible to open this audio device in mono.
496 // No point in continuing the test so let's break here.
497 LOG(WARNING) << "Mono is not supported. Skipping test.";
498 oas->Close();
499 return;
501 oas->SetVolume(1.0);
503 // Play the wave for .8 seconds.
504 oas->Start(&source);
505 ::Sleep(800);
506 oas->Stop();
507 oas->Close();
510 // Check that the pending bytes value is correct what the stream starts.
511 TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
512 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
513 if (!audio_man->HasAudioOutputDevices()) {
514 LOG(WARNING) << "No output device detected.";
515 return;
518 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
519 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
520 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
521 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
522 std::string(), std::string());
523 ASSERT_TRUE(NULL != oas);
525 NiceMock<MockAudioSource> source;
526 EXPECT_TRUE(oas->Open());
528 uint32 bytes_100_ms = samples_100_ms * 2;
530 // Audio output stream has either a double or triple buffer scheme.
531 // We expect the amount of pending bytes will reaching up to 2 times of
532 // |bytes_100_ms| depending on number of buffers used.
533 // From that it would decrease as we are playing the data but not providing
534 // new one. And then we will try to provide zero data so the amount of
535 // pending bytes will go down and eventually read zero.
536 InSequence s;
538 EXPECT_CALL(source, OnMoreData(NotNull(),
539 Field(&AudioBuffersState::pending_bytes, 0)))
540 .WillOnce(Invoke(MockAudioSource::ClearData));
542 // Note: If AudioManagerWin::NumberOfWaveOutBuffers() ever changes, or if this
543 // test is run on Vista, these expectations will fail.
544 EXPECT_CALL(source, OnMoreData(NotNull(),
545 Field(&AudioBuffersState::pending_bytes,
546 bytes_100_ms)))
547 .WillOnce(Invoke(MockAudioSource::ClearData));
548 EXPECT_CALL(source, OnMoreData(NotNull(),
549 Field(&AudioBuffersState::pending_bytes,
550 2 * bytes_100_ms)))
551 .WillOnce(Invoke(MockAudioSource::ClearData));
552 EXPECT_CALL(source, OnMoreData(NotNull(),
553 Field(&AudioBuffersState::pending_bytes,
554 2 * bytes_100_ms)))
555 .Times(AnyNumber())
556 .WillRepeatedly(Return(0));
557 EXPECT_CALL(source, OnMoreData(NotNull(),
558 Field(&AudioBuffersState::pending_bytes,
559 bytes_100_ms)))
560 .Times(AnyNumber())
561 .WillRepeatedly(Return(0));
562 EXPECT_CALL(source, OnMoreData(NotNull(),
563 Field(&AudioBuffersState::pending_bytes, 0)))
564 .Times(AnyNumber())
565 .WillRepeatedly(Return(0));
567 oas->Start(&source);
568 ::Sleep(500);
569 oas->Stop();
570 oas->Close();
573 // Simple source that uses a SyncSocket to retrieve the audio data
574 // from a potentially remote thread.
575 class SyncSocketSource : public AudioOutputStream::AudioSourceCallback {
576 public:
577 SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params)
578 : socket_(socket) {
579 // Setup AudioBus wrapping data we'll receive over the sync socket.
580 data_size_ = AudioBus::CalculateMemorySize(params);
581 data_.reset(static_cast<float*>(
582 base::AlignedAlloc(data_size_, AudioBus::kChannelAlignment)));
583 audio_bus_ = AudioBus::WrapMemory(params, data_.get());
585 ~SyncSocketSource() {}
587 // AudioSourceCallback::OnMoreData implementation:
588 virtual int OnMoreData(AudioBus* audio_bus,
589 AudioBuffersState buffers_state) {
590 socket_->Send(&buffers_state, sizeof(buffers_state));
591 uint32 size = socket_->Receive(data_.get(), data_size_);
592 DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U);
593 audio_bus_->CopyTo(audio_bus);
594 return audio_bus_->frames();
596 virtual int OnMoreIOData(AudioBus* source,
597 AudioBus* dest,
598 AudioBuffersState buffers_state) {
599 NOTREACHED();
600 return 0;
602 // AudioSourceCallback::OnError implementation:
603 virtual void OnError(AudioOutputStream* stream) {
606 private:
607 base::SyncSocket* socket_;
608 int data_size_;
609 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data_;
610 scoped_ptr<AudioBus> audio_bus_;
613 struct SyncThreadContext {
614 base::SyncSocket* socket;
615 int sample_rate;
616 int channels;
617 int frames;
618 double sine_freq;
619 uint32 packet_size_bytes;
622 // This thread provides the data that the SyncSocketSource above needs
623 // using the other end of a SyncSocket. The protocol is as follows:
625 // SyncSocketSource ---send 4 bytes ------------> SyncSocketThread
626 // <--- audio packet ----------
628 DWORD __stdcall SyncSocketThread(void* context) {
629 SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context));
631 // Setup AudioBus wrapping data we'll pass over the sync socket.
632 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data(static_cast<float*>(
633 base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment)));
634 scoped_ptr<AudioBus> audio_bus = AudioBus::WrapMemory(
635 ctx.channels, ctx.frames, data.get());
637 SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate);
638 const int kTwoSecFrames = ctx.sample_rate * 2;
640 AudioBuffersState buffers_state;
641 int times = 0;
642 for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) {
643 if (ctx.socket->Receive(&buffers_state, sizeof(buffers_state)) == 0)
644 break;
645 if ((times > 0) && (buffers_state.pending_bytes < 1000)) __debugbreak();
646 sine.OnMoreData(audio_bus.get(), buffers_state);
647 ctx.socket->Send(data.get(), ctx.packet_size_bytes);
648 ++times;
651 return 0;
654 // Test the basic operation of AudioOutputStream used with a SyncSocket.
655 // The emphasis is to verify that it is possible to feed data to the audio
656 // layer using a source based on SyncSocket. In a real situation we would
657 // go for the low-latency version in combination with SyncSocket, but to keep
658 // the test more simple, AUDIO_PCM_LINEAR is utilized instead. The main
659 // principle of the test still remains and we avoid the additional complexity
660 // related to the two different audio-layers for AUDIO_PCM_LOW_LATENCY.
661 // In this test you should hear a continuous 200Hz tone for 2 seconds.
662 TEST(WinAudioTest, SyncSocketBasic) {
663 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
664 if (!audio_man->HasAudioOutputDevices()) {
665 LOG(WARNING) << "No output device detected.";
666 return;
669 static const int sample_rate = AudioParameters::kAudioCDSampleRate;
670 static const uint32 kSamples20ms = sample_rate / 50;
671 AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
672 CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms);
675 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params,
676 std::string(), std::string());
677 ASSERT_TRUE(NULL != oas);
679 ASSERT_TRUE(oas->Open());
681 base::SyncSocket sockets[2];
682 ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1]));
684 SyncSocketSource source(&sockets[0], params);
686 SyncThreadContext thread_context;
687 thread_context.sample_rate = params.sample_rate();
688 thread_context.sine_freq = 200.0;
689 thread_context.packet_size_bytes = AudioBus::CalculateMemorySize(params);
690 thread_context.frames = params.frames_per_buffer();
691 thread_context.channels = params.channels();
692 thread_context.socket = &sockets[1];
694 HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread,
695 &thread_context, 0, NULL);
697 oas->Start(&source);
699 ::WaitForSingleObject(thread, INFINITE);
700 ::CloseHandle(thread);
702 oas->Stop();
703 oas->Close();
706 } // namespace media