[Android] Add ps_ext tool for tools-friendly cpu/mem/proc stats.
[chromium-blink-merge.git] / media / audio / win / audio_output_win_unittest.cc
blobdcb5ca35ecd252cecb414294a9174ea6373c915b
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/mock_audio_source_callback.h"
19 #include "media/audio/simple_sources.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using ::testing::_;
24 using ::testing::AnyNumber;
25 using ::testing::DoAll;
26 using ::testing::Field;
27 using ::testing::Invoke;
28 using ::testing::InSequence;
29 using ::testing::NiceMock;
30 using ::testing::NotNull;
31 using ::testing::Return;
33 using base::win::ScopedCOMInitializer;
35 namespace media {
37 static const wchar_t kAudioFile1_16b_m_16K[]
38 = L"media\\test\\data\\sweep02_16b_mono_16KHz.raw";
40 static int ClearData(AudioBus* audio_bus, AudioBuffersState buffers_state) {
41 audio_bus->Zero();
42 return audio_bus->frames();
45 // This class allows to find out if the callbacks are occurring as
46 // expected and if any error has been reported.
47 class TestSourceBasic : public AudioOutputStream::AudioSourceCallback {
48 public:
49 explicit TestSourceBasic()
50 : callback_count_(0),
51 had_error_(0) {
53 // AudioSourceCallback::OnMoreData implementation:
54 virtual int OnMoreData(AudioBus* audio_bus,
55 AudioBuffersState buffers_state) {
56 ++callback_count_;
57 // Touch the channel memory value to make sure memory is good.
58 audio_bus->Zero();
59 return audio_bus->frames();
61 virtual int OnMoreIOData(AudioBus* source,
62 AudioBus* dest,
63 AudioBuffersState buffers_state) {
64 NOTREACHED();
65 return 0;
67 // AudioSourceCallback::OnError implementation:
68 virtual void OnError(AudioOutputStream* stream) {
69 ++had_error_;
71 // Returns how many times OnMoreData() has been called.
72 int callback_count() const {
73 return callback_count_;
75 // Returns how many times the OnError callback was called.
76 int had_error() const {
77 return had_error_;
80 void set_error(bool error) {
81 had_error_ += error ? 1 : 0;
84 private:
85 int callback_count_;
86 int had_error_;
89 const int kMaxNumBuffers = 3;
90 // Specializes TestSourceBasic to simulate a source that blocks for some time
91 // in the OnMoreData callback.
92 class TestSourceLaggy : public TestSourceBasic {
93 public:
94 TestSourceLaggy(int laggy_after_buffer, int lag_in_ms)
95 : laggy_after_buffer_(laggy_after_buffer), lag_in_ms_(lag_in_ms) {
97 virtual int OnMoreData(AudioBus* audio_bus,
98 AudioBuffersState buffers_state) {
99 // Call the base, which increments the callback_count_.
100 TestSourceBasic::OnMoreData(audio_bus, buffers_state);
101 if (callback_count() > kMaxNumBuffers) {
102 ::Sleep(lag_in_ms_);
104 return audio_bus->frames();
106 private:
107 int laggy_after_buffer_;
108 int lag_in_ms_;
111 // Helper class to memory map an entire file. The mapping is read-only. Don't
112 // use for gigabyte-sized files. Attempts to write to this memory generate
113 // memory access violations.
114 class ReadOnlyMappedFile {
115 public:
116 explicit ReadOnlyMappedFile(const wchar_t* file_name)
117 : fmap_(NULL), start_(NULL), size_(0) {
118 HANDLE file = ::CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
119 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
120 if (INVALID_HANDLE_VALUE == file)
121 return;
122 fmap_ = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
123 ::CloseHandle(file);
124 if (!fmap_)
125 return;
126 start_ = reinterpret_cast<char*>(::MapViewOfFile(fmap_, FILE_MAP_READ,
127 0, 0, 0));
128 if (!start_)
129 return;
130 MEMORY_BASIC_INFORMATION mbi = {0};
131 ::VirtualQuery(start_, &mbi, sizeof(mbi));
132 size_ = mbi.RegionSize;
134 ~ReadOnlyMappedFile() {
135 if (start_) {
136 ::UnmapViewOfFile(start_);
137 ::CloseHandle(fmap_);
140 // Returns true if the file was successfully mapped.
141 bool is_valid() const {
142 return ((start_ > 0) && (size_ > 0));
144 // Returns the size in bytes of the mapped memory.
145 uint32 size() const {
146 return size_;
148 // Returns the memory backing the file.
149 const void* GetChunkAt(uint32 offset) {
150 return &start_[offset];
153 private:
154 HANDLE fmap_;
155 char* start_;
156 uint32 size_;
159 // ===========================================================================
160 // Validation of AudioManager::AUDIO_PCM_LINEAR
162 // NOTE:
163 // The tests can fail on the build bots when somebody connects to them via
164 // remote-desktop and the rdp client installs an audio device that fails to open
165 // at some point, possibly when the connection goes idle.
167 // Test that can it be created and closed.
168 TEST(WinAudioTest, PCMWaveStreamGetAndClose) {
169 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
170 if (!audio_man->HasAudioOutputDevices()) {
171 LOG(WARNING) << "No output device detected.";
172 return;
175 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
176 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
177 8000, 16, 256),
178 std::string(), std::string());
179 ASSERT_TRUE(NULL != oas);
180 oas->Close();
183 // Test that can it be cannot be created with invalid parameters.
184 TEST(WinAudioTest, SanityOnMakeParams) {
185 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
186 if (!audio_man->HasAudioOutputDevices()) {
187 LOG(WARNING) << "No output device detected.";
188 return;
191 AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR;
192 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
193 AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
194 std::string(), std::string()));
195 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
196 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256),
197 std::string(), std::string()));
198 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
199 AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256),
200 std::string(), std::string()));
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_STEREO, -8000, 16, 256),
206 std::string(), std::string()));
207 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
208 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100),
209 std::string(), std::string()));
210 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
211 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0),
212 std::string(), std::string()));
213 EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
214 AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16,
215 media::limits::kMaxSamplesPerPacket + 1),
216 std::string(), std::string()));
219 // Test that it can be opened and closed.
220 TEST(WinAudioTest, PCMWaveStreamOpenAndClose) {
221 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
222 if (!audio_man->HasAudioOutputDevices()) {
223 LOG(WARNING) << "No output device detected.";
224 return;
227 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
228 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
229 8000, 16, 256),
230 std::string(), std::string());
231 ASSERT_TRUE(NULL != oas);
232 EXPECT_TRUE(oas->Open());
233 oas->Close();
236 // Test that it has a maximum packet size.
237 TEST(WinAudioTest, PCMWaveStreamOpenLimit) {
238 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
239 if (!audio_man->HasAudioOutputDevices()) {
240 LOG(WARNING) << "No output device detected.";
241 return;
244 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
245 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
246 8000, 16, 1024 * 1024 * 1024),
247 std::string(), std::string());
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::CreateForTesting());
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 std::string(), std::string());
267 ASSERT_TRUE(NULL != oas);
268 TestSourceLaggy test_laggy(2, 90);
269 EXPECT_TRUE(oas->Open());
270 // The test parameters cause a callback every 32 ms and the source is
271 // sleeping for 90 ms, so it is guaranteed that we run out of ready buffers.
272 oas->Start(&test_laggy);
273 ::Sleep(500);
274 EXPECT_GT(test_laggy.callback_count(), 2);
275 EXPECT_FALSE(test_laggy.had_error());
276 oas->Stop();
277 ::Sleep(500);
278 oas->Close();
281 // Test another potential deadlock situation if the thread that calls Start()
282 // gets paused. This test is best when run over RDP with audio enabled. See
283 // bug 19276 for more details.
284 TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) {
285 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
286 if (!audio_man->HasAudioOutputDevices()) {
287 LOG(WARNING) << "No output device detected.";
288 return;
291 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
292 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
293 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
294 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
295 std::string(), std::string());
296 ASSERT_TRUE(NULL != oas);
298 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
300 EXPECT_TRUE(oas->Open());
301 oas->SetVolume(1.0);
303 for (int ix = 0; ix != 5; ++ix) {
304 oas->Start(&source);
305 ::Sleep(10);
306 oas->Stop();
308 oas->Close();
312 // This test produces actual audio for .5 seconds on the default wave
313 // device at 44.1K s/sec. Parameters have been chosen carefully so you should
314 // not hear pops or noises while the sound is playing.
315 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
316 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
317 if (!audio_man->HasAudioOutputDevices()) {
318 LOG(WARNING) << "No output device detected.";
319 return;
322 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
323 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
324 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
325 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
326 std::string(), std::string());
327 ASSERT_TRUE(NULL != oas);
329 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
331 EXPECT_TRUE(oas->Open());
332 oas->SetVolume(1.0);
333 oas->Start(&source);
334 ::Sleep(500);
335 oas->Stop();
336 oas->Close();
339 // This test produces actual audio for for .5 seconds on the default wave
340 // device at 22K s/sec. Parameters have been chosen carefully so you should
341 // not hear pops or noises while the sound is playing. The audio also should
342 // sound with a lower volume than PCMWaveStreamPlay200HzTone44Kss.
343 TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
344 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
345 if (!audio_man->HasAudioOutputDevices()) {
346 LOG(WARNING) << "No output device detected.";
347 return;
350 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 20;
351 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
352 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
353 AudioParameters::kAudioCDSampleRate / 2, 16,
354 samples_100_ms),
355 std::string(), std::string());
356 ASSERT_TRUE(NULL != oas);
358 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2);
360 EXPECT_TRUE(oas->Open());
362 oas->SetVolume(0.5);
363 oas->Start(&source);
364 ::Sleep(500);
366 // Test that the volume is within the set limits.
367 double volume = 0.0;
368 oas->GetVolume(&volume);
369 EXPECT_LT(volume, 0.51);
370 EXPECT_GT(volume, 0.49);
371 oas->Stop();
372 oas->Close();
375 // Uses a restricted source to play ~2 seconds of audio for about 5 seconds. We
376 // try hard to generate situation where the two threads are accessing the
377 // object roughly at the same time.
378 TEST(WinAudioTest, PushSourceFile16KHz) {
379 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
380 if (!audio_man->HasAudioOutputDevices()) {
381 LOG(WARNING) << "No output device detected.";
382 return;
385 static const int kSampleRate = 16000;
386 SineWaveAudioSource source(1, 200.0, kSampleRate);
387 // Compute buffer size for 100ms of audio.
388 const uint32 kSamples100ms = (kSampleRate / 1000) * 100;
389 // Restrict SineWaveAudioSource to 100ms of samples.
390 source.CapSamples(kSamples100ms);
392 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
393 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
394 kSampleRate, 16, kSamples100ms),
395 std::string(), std::string());
396 ASSERT_TRUE(NULL != oas);
398 EXPECT_TRUE(oas->Open());
400 oas->SetVolume(1.0);
401 oas->Start(&source);
403 // We buffer and play at the same time, buffering happens every ~10ms and the
404 // consuming of the buffer happens every ~100ms. We do 100 buffers which
405 // effectively wrap around the file more than once.
406 for (uint32 ix = 0; ix != 100; ++ix) {
407 ::Sleep(10);
408 source.Reset();
411 // Play a little bit more of the file.
412 ::Sleep(500);
414 oas->Stop();
415 oas->Close();
418 // This test is to make sure an AudioOutputStream can be started after it was
419 // stopped. You will here two .5 seconds wave signal separated by 0.5 seconds
420 // of silence.
421 TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
422 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
423 if (!audio_man->HasAudioOutputDevices()) {
424 LOG(WARNING) << "No output device detected.";
425 return;
428 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
429 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
430 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
431 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
432 std::string(), std::string());
433 ASSERT_TRUE(NULL != oas);
435 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
436 EXPECT_TRUE(oas->Open());
437 oas->SetVolume(1.0);
439 // Play the wave for .5 seconds.
440 oas->Start(&source);
441 ::Sleep(500);
442 oas->Stop();
444 // Sleep to give silence after stopping the AudioOutputStream.
445 ::Sleep(250);
447 // Start again and play for .5 seconds.
448 oas->Start(&source);
449 ::Sleep(500);
450 oas->Stop();
452 oas->Close();
455 // With the low latency mode, WASAPI is utilized by default for Vista and
456 // higher and Wave is used for XP and lower. It is possible to utilize a
457 // smaller buffer size for WASAPI than for Wave.
458 TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
459 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
460 if (!audio_man->HasAudioOutputDevices()) {
461 LOG(WARNING) << "No output device detected.";
462 return;
465 // The WASAPI API requires a correct COM environment.
466 ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
468 // Use 10 ms buffer size for WASAPI and 50 ms buffer size for Wave.
469 // Take the existing native sample rate into account.
470 const AudioParameters params = audio_man->GetDefaultOutputStreamParameters();
471 int sample_rate = params.sample_rate();
472 uint32 samples_10_ms = sample_rate / 100;
473 int n = 1;
474 (base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1;
475 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
476 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
477 CHANNEL_LAYOUT_MONO, sample_rate,
478 16, n * samples_10_ms),
479 std::string(), std::string());
480 ASSERT_TRUE(NULL != oas);
482 SineWaveAudioSource source(1, 200, sample_rate);
484 bool opened = oas->Open();
485 if (!opened) {
486 // It was not possible to open this audio device in mono.
487 // No point in continuing the test so let's break here.
488 LOG(WARNING) << "Mono is not supported. Skipping test.";
489 oas->Close();
490 return;
492 oas->SetVolume(1.0);
494 // Play the wave for .8 seconds.
495 oas->Start(&source);
496 ::Sleep(800);
497 oas->Stop();
498 oas->Close();
501 // Check that the pending bytes value is correct what the stream starts.
502 TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
503 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
504 if (!audio_man->HasAudioOutputDevices()) {
505 LOG(WARNING) << "No output device detected.";
506 return;
509 uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
510 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
511 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
512 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
513 std::string(), std::string());
514 ASSERT_TRUE(NULL != oas);
516 NiceMock<MockAudioSourceCallback> source;
517 EXPECT_TRUE(oas->Open());
519 uint32 bytes_100_ms = samples_100_ms * 2;
521 // Audio output stream has either a double or triple buffer scheme.
522 // We expect the amount of pending bytes will reaching up to 2 times of
523 // |bytes_100_ms| depending on number of buffers used.
524 // From that it would decrease as we are playing the data but not providing
525 // new one. And then we will try to provide zero data so the amount of
526 // pending bytes will go down and eventually read zero.
527 InSequence s;
529 EXPECT_CALL(source, OnMoreData(NotNull(),
530 Field(&AudioBuffersState::pending_bytes, 0)))
531 .WillOnce(Invoke(ClearData));
533 // Note: If AudioManagerWin::NumberOfWaveOutBuffers() ever changes, or if this
534 // test is run on Vista, these expectations will fail.
535 EXPECT_CALL(source, OnMoreData(NotNull(),
536 Field(&AudioBuffersState::pending_bytes,
537 bytes_100_ms)))
538 .WillOnce(Invoke(ClearData));
539 EXPECT_CALL(source, OnMoreData(NotNull(),
540 Field(&AudioBuffersState::pending_bytes,
541 2 * bytes_100_ms)))
542 .WillOnce(Invoke(ClearData));
543 EXPECT_CALL(source, OnMoreData(NotNull(),
544 Field(&AudioBuffersState::pending_bytes,
545 2 * bytes_100_ms)))
546 .Times(AnyNumber())
547 .WillRepeatedly(Return(0));
548 EXPECT_CALL(source, OnMoreData(NotNull(),
549 Field(&AudioBuffersState::pending_bytes,
550 bytes_100_ms)))
551 .Times(AnyNumber())
552 .WillRepeatedly(Return(0));
553 EXPECT_CALL(source, OnMoreData(NotNull(),
554 Field(&AudioBuffersState::pending_bytes, 0)))
555 .Times(AnyNumber())
556 .WillRepeatedly(Return(0));
558 oas->Start(&source);
559 ::Sleep(500);
560 oas->Stop();
561 oas->Close();
564 // Simple source that uses a SyncSocket to retrieve the audio data
565 // from a potentially remote thread.
566 class SyncSocketSource : public AudioOutputStream::AudioSourceCallback {
567 public:
568 SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params)
569 : socket_(socket) {
570 // Setup AudioBus wrapping data we'll receive over the sync socket.
571 data_size_ = AudioBus::CalculateMemorySize(params);
572 data_.reset(static_cast<float*>(
573 base::AlignedAlloc(data_size_, AudioBus::kChannelAlignment)));
574 audio_bus_ = AudioBus::WrapMemory(params, data_.get());
576 ~SyncSocketSource() {}
578 // AudioSourceCallback::OnMoreData implementation:
579 virtual int OnMoreData(AudioBus* audio_bus,
580 AudioBuffersState buffers_state) {
581 socket_->Send(&buffers_state, sizeof(buffers_state));
582 uint32 size = socket_->Receive(data_.get(), data_size_);
583 DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U);
584 audio_bus_->CopyTo(audio_bus);
585 return audio_bus_->frames();
587 virtual int OnMoreIOData(AudioBus* source,
588 AudioBus* dest,
589 AudioBuffersState buffers_state) {
590 NOTREACHED();
591 return 0;
593 // AudioSourceCallback::OnError implementation:
594 virtual void OnError(AudioOutputStream* stream) {
597 private:
598 base::SyncSocket* socket_;
599 int data_size_;
600 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data_;
601 scoped_ptr<AudioBus> audio_bus_;
604 struct SyncThreadContext {
605 base::SyncSocket* socket;
606 int sample_rate;
607 int channels;
608 int frames;
609 double sine_freq;
610 uint32 packet_size_bytes;
613 // This thread provides the data that the SyncSocketSource above needs
614 // using the other end of a SyncSocket. The protocol is as follows:
616 // SyncSocketSource ---send 4 bytes ------------> SyncSocketThread
617 // <--- audio packet ----------
619 DWORD __stdcall SyncSocketThread(void* context) {
620 SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context));
622 // Setup AudioBus wrapping data we'll pass over the sync socket.
623 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data(static_cast<float*>(
624 base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment)));
625 scoped_ptr<AudioBus> audio_bus = AudioBus::WrapMemory(
626 ctx.channels, ctx.frames, data.get());
628 SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate);
629 const int kTwoSecFrames = ctx.sample_rate * 2;
631 AudioBuffersState buffers_state;
632 int times = 0;
633 for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) {
634 if (ctx.socket->Receive(&buffers_state, sizeof(buffers_state)) == 0)
635 break;
636 if ((times > 0) && (buffers_state.pending_bytes < 1000)) __debugbreak();
637 sine.OnMoreData(audio_bus.get(), buffers_state);
638 ctx.socket->Send(data.get(), ctx.packet_size_bytes);
639 ++times;
642 return 0;
645 // Test the basic operation of AudioOutputStream used with a SyncSocket.
646 // The emphasis is to verify that it is possible to feed data to the audio
647 // layer using a source based on SyncSocket. In a real situation we would
648 // go for the low-latency version in combination with SyncSocket, but to keep
649 // the test more simple, AUDIO_PCM_LINEAR is utilized instead. The main
650 // principle of the test still remains and we avoid the additional complexity
651 // related to the two different audio-layers for AUDIO_PCM_LOW_LATENCY.
652 // In this test you should hear a continuous 200Hz tone for 2 seconds.
653 TEST(WinAudioTest, SyncSocketBasic) {
654 scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
655 if (!audio_man->HasAudioOutputDevices()) {
656 LOG(WARNING) << "No output device detected.";
657 return;
660 static const int sample_rate = AudioParameters::kAudioCDSampleRate;
661 static const uint32 kSamples20ms = sample_rate / 50;
662 AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
663 CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms);
666 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params,
667 std::string(), std::string());
668 ASSERT_TRUE(NULL != oas);
670 ASSERT_TRUE(oas->Open());
672 base::SyncSocket sockets[2];
673 ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1]));
675 SyncSocketSource source(&sockets[0], params);
677 SyncThreadContext thread_context;
678 thread_context.sample_rate = params.sample_rate();
679 thread_context.sine_freq = 200.0;
680 thread_context.packet_size_bytes = AudioBus::CalculateMemorySize(params);
681 thread_context.frames = params.frames_per_buffer();
682 thread_context.channels = params.channels();
683 thread_context.socket = &sockets[1];
685 HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread,
686 &thread_context, 0, NULL);
688 oas->Start(&source);
690 ::WaitForSingleObject(thread, INFINITE);
691 ::CloseHandle(thread);
693 oas->Stop();
694 oas->Close();
697 } // namespace media