Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / media / audio / win / audio_output_win_unittest.cc
blobd8d2b4e20e165c1feafe0a501c53e1e271b6abff
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/file_util.h"
11 #include "base/memory/aligned_memory.h"
12 #include "base/path_service.h"
13 #include "base/sync_socket.h"
14 #include "base/win/scoped_com_initializer.h"
15 #include "base/win/windows_version.h"
16 #include "media/base/limits.h"
17 #include "media/audio/audio_io.h"
18 #include "media/audio/audio_util.h"
19 #include "media/audio/audio_manager.h"
20 #include "media/audio/simple_sources.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using ::testing::_;
25 using ::testing::AnyNumber;
26 using ::testing::DoAll;
27 using ::testing::Field;
28 using ::testing::Invoke;
29 using ::testing::InSequence;
30 using ::testing::NiceMock;
31 using ::testing::NotNull;
32 using ::testing::Return;
34 using base::win::ScopedCOMInitializer;
36 namespace media {
38 static const wchar_t kAudioFile1_16b_m_16K[]
39 = L"media\\test\\data\\sweep02_16b_mono_16KHz.raw";
41 // This class allows to find out if the callbacks are occurring as
42 // expected and if any error has been reported.
43 class TestSourceBasic : public AudioOutputStream::AudioSourceCallback {
44 public:
45 explicit TestSourceBasic()
46 : callback_count_(0),
47 had_error_(0) {
49 // AudioSourceCallback::OnMoreData implementation:
50 virtual int OnMoreData(AudioBus* audio_bus,
51 AudioBuffersState buffers_state) {
52 ++callback_count_;
53 // Touch the channel memory value to make sure memory is good.
54 audio_bus->Zero();
55 return audio_bus->frames();
57 virtual int OnMoreIOData(AudioBus* source,
58 AudioBus* dest,
59 AudioBuffersState buffers_state) {
60 NOTREACHED();
61 return 0;
63 // AudioSourceCallback::OnError implementation:
64 virtual void OnError(AudioOutputStream* stream) {
65 ++had_error_;
67 // Returns how many times OnMoreData() has been called.
68 int callback_count() const {
69 return callback_count_;
71 // Returns how many times the OnError callback was called.
72 int had_error() const {
73 return had_error_;
76 void set_error(bool error) {
77 had_error_ += error ? 1 : 0;
80 private:
81 int callback_count_;
82 int had_error_;
85 const int kMaxNumBuffers = 3;
86 // Specializes TestSourceBasic to simulate a source that blocks for some time
87 // in the OnMoreData callback.
88 class TestSourceLaggy : public TestSourceBasic {
89 public:
90 TestSourceLaggy(int laggy_after_buffer, int lag_in_ms)
91 : laggy_after_buffer_(laggy_after_buffer), lag_in_ms_(lag_in_ms) {
93 virtual int OnMoreData(AudioBus* audio_bus,
94 AudioBuffersState buffers_state) {
95 // Call the base, which increments the callback_count_.
96 TestSourceBasic::OnMoreData(audio_bus, buffers_state);
97 if (callback_count() > kMaxNumBuffers) {
98 ::Sleep(lag_in_ms_);
100 return audio_bus->frames();
102 private:
103 int laggy_after_buffer_;
104 int lag_in_ms_;
107 class MockAudioSource : public AudioOutputStream::AudioSourceCallback {
108 public:
109 MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus,
110 AudioBuffersState buffers_state));
111 MOCK_METHOD3(OnMoreIOData, int(AudioBus* source,
112 AudioBus* dest,
113 AudioBuffersState buffers_state));
114 MOCK_METHOD1(OnError, void(AudioOutputStream* stream));
116 static int ClearData(AudioBus* audio_bus, AudioBuffersState buffers_state) {
117 audio_bus->Zero();
118 return audio_bus->frames();
122 // Helper class to memory map an entire file. The mapping is read-only. Don't
123 // use for gigabyte-sized files. Attempts to write to this memory generate
124 // memory access violations.
125 class ReadOnlyMappedFile {
126 public:
127 explicit ReadOnlyMappedFile(const wchar_t* file_name)
128 : fmap_(NULL), start_(NULL), size_(0) {
129 HANDLE file = ::CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
130 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
131 if (INVALID_HANDLE_VALUE == file)
132 return;
133 fmap_ = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
134 ::CloseHandle(file);
135 if (!fmap_)
136 return;
137 start_ = reinterpret_cast<char*>(::MapViewOfFile(fmap_, FILE_MAP_READ,
138 0, 0, 0));
139 if (!start_)
140 return;
141 MEMORY_BASIC_INFORMATION mbi = {0};
142 ::VirtualQuery(start_, &mbi, sizeof(mbi));
143 size_ = mbi.RegionSize;
145 ~ReadOnlyMappedFile() {
146 if (start_) {
147 ::UnmapViewOfFile(start_);
148 ::CloseHandle(fmap_);
151 // Returns true if the file was successfully mapped.
152 bool is_valid() const {
153 return ((start_ > 0) && (size_ > 0));
155 // Returns the size in bytes of the mapped memory.
156 uint32 size() const {
157 return size_;
159 // Returns the memory backing the file.
160 const void* GetChunkAt(uint32 offset) {
161 return &start_[offset];
164 private:
165 HANDLE fmap_;
166 char* start_;
167 uint32 size_;
170 // ===========================================================================
171 // Validation of AudioManager::AUDIO_PCM_LINEAR
173 // NOTE:
174 // The tests can fail on the build bots when somebody connects to them via
175 // remote-desktop and the rdp client installs an audio device that fails to open
176 // at some point, possibly when the connection goes idle.
178 // Test that can it be created and closed.
179 TEST(WinAudioTest, PCMWaveStreamGetAndClose) {
180 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
181 if (!audio_man->HasAudioOutputDevices()) {
182 LOG(WARNING) << "No output device detected.";
183 return;
186 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
187 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
188 8000, 16, 256));
189 ASSERT_TRUE(NULL != oas);
190 oas->Close();
193 // Test that can it be cannot be created with invalid parameters.
194 TEST(WinAudioTest, SanityOnMakeParams) {
195 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
196 if (!audio_man->HasAudioOutputDevices()) {
197 LOG(WARNING) << "No output device detected.";
198 return;
201 AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR;
202 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
203 AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256)));
204 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
205 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256)));
206 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
207 AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256)));
208 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
209 AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256)));
210 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
211 AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256)));
212 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
213 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100)));
214 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
215 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0)));
216 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
217 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16,
218 media::limits::kMaxSamplesPerPacket + 1)));
221 // Test that it can be opened and closed.
222 TEST(WinAudioTest, PCMWaveStreamOpenAndClose) {
223 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
224 if (!audio_man->HasAudioOutputDevices()) {
225 LOG(WARNING) << "No output device detected.";
226 return;
229 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
230 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
231 8000, 16, 256));
232 ASSERT_TRUE(NULL != oas);
233 EXPECT_TRUE(oas->Open());
234 oas->Close();
237 // Test that it has a maximum packet size.
238 TEST(WinAudioTest, PCMWaveStreamOpenLimit) {
239 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
240 if (!audio_man->HasAudioOutputDevices()) {
241 LOG(WARNING) << "No output device detected.";
242 return;
245 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
246 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
247 8000, 16, 1024 * 1024 * 1024));
248 EXPECT_TRUE(NULL == oas);
249 if (oas)
250 oas->Close();
253 // Test potential deadlock situation if the source is slow or blocks for some
254 // time. The actual EXPECT_GT are mostly meaningless and the real test is that
255 // the test completes in reasonable time.
256 TEST(WinAudioTest, PCMWaveSlowSource) {
257 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
258 if (!audio_man->HasAudioOutputDevices()) {
259 LOG(WARNING) << "No output device detected.";
260 return;
263 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
264 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
265 16000, 16, 256));
266 ASSERT_TRUE(NULL != oas);
267 TestSourceLaggy test_laggy(2, 90);
268 EXPECT_TRUE(oas->Open());
269 // The test parameters cause a callback every 32 ms and the source is
270 // sleeping for 90 ms, so it is guaranteed that we run out of ready buffers.
271 oas->Start(&test_laggy);
272 ::Sleep(500);
273 EXPECT_GT(test_laggy.callback_count(), 2);
274 EXPECT_FALSE(test_laggy.had_error());
275 oas->Stop();
276 ::Sleep(500);
277 oas->Close();
280 // Test another potential deadlock situation if the thread that calls Start()
281 // gets paused. This test is best when run over RDP with audio enabled. See
282 // bug 19276 for more details.
283 TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) {
284 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
285 if (!audio_man->HasAudioOutputDevices()) {
286 LOG(WARNING) << "No output device detected.";
287 return;
290 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
291 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
292 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
293 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms));
294 ASSERT_TRUE(NULL != oas);
296 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
298 EXPECT_TRUE(oas->Open());
299 oas->SetVolume(1.0);
301 for (int ix = 0; ix != 5; ++ix) {
302 oas->Start(&source);
303 ::Sleep(10);
304 oas->Stop();
306 oas->Close();
310 // This test produces actual audio for .5 seconds on the default wave
311 // device at 44.1K s/sec. Parameters have been chosen carefully so you should
312 // not hear pops or noises while the sound is playing.
313 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
314 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
315 if (!audio_man->HasAudioOutputDevices()) {
316 LOG(WARNING) << "No output device detected.";
317 return;
320 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
321 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
322 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
323 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms));
324 ASSERT_TRUE(NULL != oas);
326 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
328 EXPECT_TRUE(oas->Open());
329 oas->SetVolume(1.0);
330 oas->Start(&source);
331 ::Sleep(500);
332 oas->Stop();
333 oas->Close();
336 // This test produces actual audio for for .5 seconds on the default wave
337 // device at 22K s/sec. Parameters have been chosen carefully so you should
338 // not hear pops or noises while the sound is playing. The audio also should
339 // sound with a lower volume than PCMWaveStreamPlay200HzTone44Kss.
340 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
341 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
342 if (!audio_man->HasAudioOutputDevices()) {
343 LOG(WARNING) << "No output device detected.";
344 return;
347 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 20;
348 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
349 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
350 AudioParameters::kAudioCDSampleRate / 2, 16,
351 samples_100_ms));
352 ASSERT_TRUE(NULL != oas);
354 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2);
356 EXPECT_TRUE(oas->Open());
358 oas->SetVolume(0.5);
359 oas->Start(&source);
360 ::Sleep(500);
362 // Test that the volume is within the set limits.
363 double volume = 0.0;
364 oas->GetVolume(&volume);
365 EXPECT_LT(volume, 0.51);
366 EXPECT_GT(volume, 0.49);
367 oas->Stop();
368 oas->Close();
371 // Uses a restricted source to play ~2 seconds of audio for about 5 seconds. We
372 // try hard to generate situation where the two threads are accessing the
373 // object roughly at the same time.
374 TEST(WinAudioTest, PushSourceFile16KHz) {
375 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
376 if (!audio_man->HasAudioOutputDevices()) {
377 LOG(WARNING) << "No output device detected.";
378 return;
381 static const int kSampleRate = 16000;
382 SineWaveAudioSource source(1, 200.0, kSampleRate);
383 // Compute buffer size for 100ms of audio.
384 const uint32 kSamples100ms = (kSampleRate / 1000) * 100;
385 // Restrict SineWaveAudioSource to 100ms of samples.
386 source.CapSamples(kSamples100ms);
388 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
389 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
390 kSampleRate, 16, kSamples100ms));
391 ASSERT_TRUE(NULL != oas);
393 EXPECT_TRUE(oas->Open());
395 oas->SetVolume(1.0);
396 oas->Start(&source);
398 // We buffer and play at the same time, buffering happens every ~10ms and the
399 // consuming of the buffer happens every ~100ms. We do 100 buffers which
400 // effectively wrap around the file more than once.
401 for (uint32 ix = 0; ix != 100; ++ix) {
402 ::Sleep(10);
403 source.Reset();
406 // Play a little bit more of the file.
407 ::Sleep(500);
409 oas->Stop();
410 oas->Close();
413 // This test is to make sure an AudioOutputStream can be started after it was
414 // stopped. You will here two .5 seconds wave signal separated by 0.5 seconds
415 // of silence.
416 TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
417 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
418 if (!audio_man->HasAudioOutputDevices()) {
419 LOG(WARNING) << "No output device detected.";
420 return;
423 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
424 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
425 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
426 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms));
427 ASSERT_TRUE(NULL != oas);
429 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
430 EXPECT_TRUE(oas->Open());
431 oas->SetVolume(1.0);
433 // Play the wave for .5 seconds.
434 oas->Start(&source);
435 ::Sleep(500);
436 oas->Stop();
438 // Sleep to give silence after stopping the AudioOutputStream.
439 ::Sleep(250);
441 // Start again and play for .5 seconds.
442 oas->Start(&source);
443 ::Sleep(500);
444 oas->Stop();
446 oas->Close();
449 // With the low latency mode, WASAPI is utilized by default for Vista and
450 // higher and Wave is used for XP and lower. It is possible to utilize a
451 // smaller buffer size for WASAPI than for Wave.
452 TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
453 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
454 if (!audio_man->HasAudioOutputDevices()) {
455 LOG(WARNING) << "No output device detected.";
456 return;
459 // The WASAPI API requires a correct COM environment.
460 ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
462 // Use 10 ms buffer size for WASAPI and 50 ms buffer size for Wave.
463 // Take the existing native sample rate into account.
464 const AudioParameters params = audio_man->GetDefaultOutputStreamParameters();
465 int sample_rate = params.sample_rate();
466 uint32 samples_10_ms = sample_rate / 100;
467 int n = 1;
468 (base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1;
469 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
470 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
471 CHANNEL_LAYOUT_MONO, sample_rate,
472 16, n * samples_10_ms));
473 ASSERT_TRUE(NULL != oas);
475 SineWaveAudioSource source(1, 200, sample_rate);
477 bool opened = oas->Open();
478 if (!opened) {
479 // It was not possible to open this audio device in mono.
480 // No point in continuing the test so let's break here.
481 LOG(WARNING) << "Mono is not supported. Skipping test.";
482 oas->Close();
483 return;
485 oas->SetVolume(1.0);
487 // Play the wave for .8 seconds.
488 oas->Start(&source);
489 ::Sleep(800);
490 oas->Stop();
491 oas->Close();
494 // Check that the pending bytes value is correct what the stream starts.
495 TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
496 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
497 if (!audio_man->HasAudioOutputDevices()) {
498 LOG(WARNING) << "No output device detected.";
499 return;
502 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
503 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
504 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
505 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms));
506 ASSERT_TRUE(NULL != oas);
508 NiceMock<MockAudioSource> source;
509 EXPECT_TRUE(oas->Open());
511 uint32 bytes_100_ms = samples_100_ms * 2;
513 // Audio output stream has either a double or triple buffer scheme.
514 // We expect the amount of pending bytes will reaching up to 2 times of
515 // |bytes_100_ms| depending on number of buffers used.
516 // From that it would decrease as we are playing the data but not providing
517 // new one. And then we will try to provide zero data so the amount of
518 // pending bytes will go down and eventually read zero.
519 InSequence s;
521 EXPECT_CALL(source, OnMoreData(NotNull(),
522 Field(&AudioBuffersState::pending_bytes, 0)))
523 .WillOnce(Invoke(MockAudioSource::ClearData));
524 switch (NumberOfWaveOutBuffers()) {
525 case 2:
526 break; // Calls are the same as at end of 3-buffer scheme.
527 case 3:
528 EXPECT_CALL(source, OnMoreData(NotNull(),
529 Field(&AudioBuffersState::pending_bytes,
530 bytes_100_ms)))
531 .WillOnce(Invoke(MockAudioSource::ClearData));
532 EXPECT_CALL(source, OnMoreData(NotNull(),
533 Field(&AudioBuffersState::pending_bytes,
534 2 * bytes_100_ms)))
535 .WillOnce(Invoke(MockAudioSource::ClearData));
536 EXPECT_CALL(source, OnMoreData(NotNull(),
537 Field(&AudioBuffersState::pending_bytes,
538 2 * bytes_100_ms)))
539 .Times(AnyNumber())
540 .WillRepeatedly(Return(0));
541 break;
542 default:
543 ASSERT_TRUE(false)
544 << "Unexpected number of buffers: " << NumberOfWaveOutBuffers();
546 EXPECT_CALL(source, OnMoreData(NotNull(),
547 Field(&AudioBuffersState::pending_bytes,
548 bytes_100_ms)))
549 .Times(AnyNumber())
550 .WillRepeatedly(Return(0));
551 EXPECT_CALL(source, OnMoreData(NotNull(),
552 Field(&AudioBuffersState::pending_bytes, 0)))
553 .Times(AnyNumber())
554 .WillRepeatedly(Return(0));
556 oas->Start(&source);
557 ::Sleep(500);
558 oas->Stop();
559 oas->Close();
562 // Simple source that uses a SyncSocket to retrieve the audio data
563 // from a potentially remote thread.
564 class SyncSocketSource : public AudioOutputStream::AudioSourceCallback {
565 public:
566 SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params)
567 : socket_(socket) {
568 // Setup AudioBus wrapping data we'll receive over the sync socket.
569 data_size_ = AudioBus::CalculateMemorySize(params);
570 data_.reset(static_cast<float*>(
571 base::AlignedAlloc(data_size_, AudioBus::kChannelAlignment)));
572 audio_bus_ = AudioBus::WrapMemory(params, data_.get());
574 ~SyncSocketSource() {}
576 // AudioSourceCallback::OnMoreData implementation:
577 virtual int OnMoreData(AudioBus* audio_bus,
578 AudioBuffersState buffers_state) {
579 socket_->Send(&buffers_state, sizeof(buffers_state));
580 uint32 size = socket_->Receive(data_.get(), data_size_);
581 DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U);
582 audio_bus_->CopyTo(audio_bus);
583 return audio_bus_->frames();
585 virtual int OnMoreIOData(AudioBus* source,
586 AudioBus* dest,
587 AudioBuffersState buffers_state) {
588 NOTREACHED();
589 return 0;
591 // AudioSourceCallback::OnError implementation:
592 virtual void OnError(AudioOutputStream* stream) {
595 private:
596 base::SyncSocket* socket_;
597 int data_size_;
598 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data_;
599 scoped_ptr<AudioBus> audio_bus_;
602 struct SyncThreadContext {
603 base::SyncSocket* socket;
604 int sample_rate;
605 int channels;
606 int frames;
607 double sine_freq;
608 uint32 packet_size_bytes;
611 // This thread provides the data that the SyncSocketSource above needs
612 // using the other end of a SyncSocket. The protocol is as follows:
614 // SyncSocketSource ---send 4 bytes ------------> SyncSocketThread
615 // <--- audio packet ----------
617 DWORD __stdcall SyncSocketThread(void* context) {
618 SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context));
620 // Setup AudioBus wrapping data we'll pass over the sync socket.
621 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data(static_cast<float*>(
622 base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment)));
623 scoped_ptr<AudioBus> audio_bus = AudioBus::WrapMemory(
624 ctx.channels, ctx.frames, data.get());
626 SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate);
627 const int kTwoSecFrames = ctx.sample_rate * 2;
629 AudioBuffersState buffers_state;
630 int times = 0;
631 for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) {
632 if (ctx.socket->Receive(&buffers_state, sizeof(buffers_state)) == 0)
633 break;
634 if ((times > 0) && (buffers_state.pending_bytes < 1000)) __debugbreak();
635 sine.OnMoreData(audio_bus.get(), buffers_state);
636 ctx.socket->Send(data.get(), ctx.packet_size_bytes);
637 ++times;
640 return 0;
643 // Test the basic operation of AudioOutputStream used with a SyncSocket.
644 // The emphasis is to verify that it is possible to feed data to the audio
645 // layer using a source based on SyncSocket. In a real situation we would
646 // go for the low-latency version in combination with SyncSocket, but to keep
647 // the test more simple, AUDIO_PCM_LINEAR is utilized instead. The main
648 // principle of the test still remains and we avoid the additional complexity
649 // related to the two different audio-layers for AUDIO_PCM_LOW_LATENCY.
650 // In this test you should hear a continuous 200Hz tone for 2 seconds.
651 TEST(WinAudioTest, SyncSocketBasic) {
652 scoped_ptr<AudioManager> audio_man(AudioManager::Create());
653 if (!audio_man->HasAudioOutputDevices()) {
654 LOG(WARNING) << "No output device detected.";
655 return;
658 static const int sample_rate = AudioParameters::kAudioCDSampleRate;
659 static const uint32 kSamples20ms = sample_rate / 50;
660 AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
661 CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms);
664 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params);
665 ASSERT_TRUE(NULL != oas);
667 ASSERT_TRUE(oas->Open());
669 base::SyncSocket sockets[2];
670 ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1]));
672 SyncSocketSource source(&sockets[0], params);
674 SyncThreadContext thread_context;
675 thread_context.sample_rate = params.sample_rate();
676 thread_context.sine_freq = 200.0;
677 thread_context.packet_size_bytes = AudioBus::CalculateMemorySize(params);
678 thread_context.frames = params.frames_per_buffer();
679 thread_context.channels = params.channels();
680 thread_context.socket = &sockets[1];
682 HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread,
683 &thread_context, 0, NULL);
685 oas->Start(&source);
687 ::WaitForSingleObject(thread, INFINITE);
688 ::CloseHandle(thread);
690 oas->Stop();
691 oas->Close();
694 } // namespace media